From a82443c5e16ebca9b345ce54603d982199aff53d Mon Sep 17 00:00:00 2001 From: Kristina Nikolaeva <112946046+kristinaNikolaevaa@users.noreply.github.com> Date: Tue, 8 Aug 2023 17:30:44 +0300 Subject: [PATCH 001/318] Ndev 1981 neon api tests (#156) * NDEV 1982 neon api tests * Update docker-compose-ci.yml * fix host name * fixed compose file * Update test_neon_core_api.py --- evm_loader/docker-compose-ci.yml | 37 +++++++++++++ evm_loader/tests/conftest.py | 14 ++++- evm_loader/tests/solana_utils.py | 1 + evm_loader/tests/test_neon_core_api.py | 65 +++++++++++++++++++++++ evm_loader/tests/utils/neon_api_client.py | 35 ++++++++++++ 5 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 evm_loader/tests/test_neon_core_api.py create mode 100644 evm_loader/tests/utils/neon_api_client.py diff --git a/evm_loader/docker-compose-ci.yml b/evm_loader/docker-compose-ci.yml index de41061de..806d82a51 100644 --- a/evm_loader/docker-compose-ci.yml +++ b/evm_loader/docker-compose-ci.yml @@ -13,3 +13,40 @@ services: - "8899" entrypoint: /opt/solana/bin/solana-run-neon.sh + networks: + - net + + dk-neon-api: + restart: unless-stopped + container_name: dk-neon-api + hostname: neon_api + command: /opt/neon-api -H 0.0.0.0:8085 + environment: + RUST_BACKTRACE: 1 + RUST_LOG: debug + NEON_API_LISTENER_ADDR: 0.0.0.0:8085 + SOLANA_URL: http://solana:8899 + EVM_LOADER: 53DfF883gyixYNXnM7s5xhdeyV8mVk9T4i2hGV9vG9io + NEON_TOKEN_MINT: HPsV9Deocecw3GeZv1FkAPNCBRfuVyfw9MMwjwRe1xaU + NEON_CHAIN_ID: 111 + COMMITMENT: confirmed + NEON_DB_CLICKHOUSE_URLS: "http://45.250.253.36:8123;http://45.250.253.38:8123" + NEON_DB_INDEXER_HOST: 45.250.253.32 + NEON_DB_INDEXER_PORT: 5432 + NEON_DB_INDEXER_DATABASE: indexer + NEON_DB_INDEXER_USER: postgres + NEON_DB_INDEXER_PASSWORD: "" + KEYPAIR: /opt/id.json + FEEPAIR: /opt/id.json + image: neonlabsorg/evm_loader:latest + expose: + - "8085" + ports: + - 8085:8085 + volumes: + - ./files/id.json:/opt/id.json + networks: + - net + +networks: + net: diff --git a/evm_loader/tests/conftest.py b/evm_loader/tests/conftest.py index 1fcab2bd7..e4a55f7fb 100644 --- a/evm_loader/tests/conftest.py +++ b/evm_loader/tests/conftest.py @@ -15,6 +15,7 @@ from .utils.contract import deploy_contract from .utils.storage import create_holder from .utils.types import TreasuryPool, Caller, Contract +from .utils.neon_api_client import NeonApiClient def pytest_addoption(parser): @@ -22,6 +23,10 @@ def pytest_addoption(parser): "--operator-keys", action="store", default="~/.config/solana/id.json,~/.config/solana/id2.json", help="Path to 2 comma separated operator keypairs" ) + parser.addoption( + "--neon-api-uri", action="store", default="http://neon_api:8085/api", + help="" + ) def pytest_configure(config): @@ -51,8 +56,7 @@ def operator_keypair(request, evm_loader) -> Keypair: caller, caller_nonce = evm_loader.ether2program(caller_ether) if get_solana_balance(PublicKey(caller)) == 0: - evm_loader.check_account(account.public_key) - evm_loader.check_account(PublicKey(caller)) + evm_loader.create_ether_account(caller_ether) return account @@ -131,3 +135,9 @@ def rw_lock_caller(evm_loader: EvmLoader, operator_keypair: Keypair, def string_setter_contract(evm_loader: EvmLoader, operator_keypair: Keypair, session_user: Caller, treasury_pool) -> Contract: return deploy_contract(operator_keypair, session_user, "string_setter.binary", evm_loader, treasury_pool) + + +@pytest.fixture(scope="session") +def neon_api_client(request): + client = NeonApiClient(url=request.config.getoption("--neon-api-uri")) + return client diff --git a/evm_loader/tests/solana_utils.py b/evm_loader/tests/solana_utils.py index 449345edb..a20ae3ea9 100644 --- a/evm_loader/tests/solana_utils.py +++ b/evm_loader/tests/solana_utils.py @@ -335,6 +335,7 @@ def deploy(self, contract_path, config=None): def create_ether_account(self, ether): (trx, sol) = self.create_ether_account_trx(ether) signer = self.acc.get_acc() + self.check_account(signer.public_key) send_transaction(solana_client, trx, signer) return sol diff --git a/evm_loader/tests/test_neon_core_api.py b/evm_loader/tests/test_neon_core_api.py new file mode 100644 index 000000000..65106132a --- /dev/null +++ b/evm_loader/tests/test_neon_core_api.py @@ -0,0 +1,65 @@ +import pytest +from eth_utils import abi, to_text + +from .utils.contract import deploy_contract +from .solana_utils import solana_client + + +def test_get_storage_at(neon_api_client, operator_keypair, user_account, evm_loader, treasury_pool): + contract = deploy_contract(operator_keypair, user_account, "hello_world.binary", evm_loader, treasury_pool) + storage = neon_api_client.get_storage_at(contract.eth_address.hex())["value"] + zero_array = [0 for _ in range(31)] + assert storage == zero_array + [5] + + storage = neon_api_client.get_storage_at(contract.eth_address.hex(), index='0x2')["value"] + assert storage == zero_array + [0] + + +def test_get_ether_account_data(neon_api_client, user_account): + result = neon_api_client.get_ether_account_data(user_account.eth_address.hex())['value'] + assert f"0x{user_account.eth_address.hex()}" == result["address"] + assert str(user_account.solana_account_address) == result["solana_address"] + assert solana_client.get_account_info(user_account.solana_account.public_key).value is not None + + +def test_emulate_transfer(neon_api_client, user_account, session_user): + result = neon_api_client.emulate(user_account.eth_address.hex(), + session_user.eth_address.hex())["value"] + assert result['exit_status'] == 'succeed', f"The 'exit_status' field is not succeed. Result: {result}" + assert result['steps_executed'] == 1, f"Steps executed amount is not 1. Result: {result}" + assert result['used_gas'] > 0, f"Used gas is less than 0. Result: {result}" + + +def test_emulate_contract_deploy(neon_api_client, user_account): + contract_path = pytest.CONTRACTS_PATH / "hello_world.binary" + + with open(contract_path, 'rb') as f: + contract_code = f.read() + result = neon_api_client.emulate(user_account.eth_address.hex(), + contract=None, data=contract_code)["value"] + assert result['exit_status'] == 'succeed', f"The 'exit_status' field is not succeed. Result: {result}" + assert result['steps_executed'] > 100, f"Steps executed amount is wrong. Result: {result}" + assert result['used_gas'] > 0, f"Used gas is less than 0. Result: {result}" + + +def test_emulate_call_contract_function(neon_api_client, operator_keypair, treasury_pool, evm_loader, user_account): + contract = deploy_contract(operator_keypair, user_account, "hello_world.binary", evm_loader, treasury_pool) + assert contract.eth_address + data = abi.function_signature_to_4byte_selector('call_hello_world()') + + result = neon_api_client.emulate(user_account.eth_address.hex(), + contract=contract.eth_address.hex(), data=data)["value"] + + assert result['exit_status'] == 'succeed', f"The 'exit_status' field is not succeed. Result: {result}" + assert result['steps_executed'] > 0, f"Steps executed amount is 0. Result: {result}" + assert result['used_gas'] > 0, f"Used gas is less than 0. Result: {result}" + assert "Hello World" in to_text(result["result"]) + + +def test_emulate_with_small_amount_of_steps(neon_api_client, evm_loader, user_account): + contract_path = pytest.CONTRACTS_PATH / "hello_world.binary" + with open(contract_path, 'rb') as f: + contract_code = f.read() + result = neon_api_client.emulate(user_account.eth_address.hex(), + contract=None, data=contract_code, max_steps_to_execute=10) + assert result['error'] == 'Too many steps' diff --git a/evm_loader/tests/utils/neon_api_client.py b/evm_loader/tests/utils/neon_api_client.py new file mode 100644 index 000000000..2599f6ce3 --- /dev/null +++ b/evm_loader/tests/utils/neon_api_client.py @@ -0,0 +1,35 @@ +import os + +import requests + + +class NeonApiClient: + def __init__(self, url): + self.url = url + self.token_mint = os.environ.get('NEON_TOKEN_MINT') + self.chain_id = os.environ.get('NEON_CHAIN_ID') + self.headers = {"Content-Type": "application/json"} + + def emulate(self, sender, contract, gas_limit=None, data=None, token_mint=None, chain_id=None, + cached_accounts=None, solana_accounts=None, max_steps_to_execute=500000, + value='0x0'): + token_mint = self.token_mint if token_mint is None else token_mint + chain_id = int(self.chain_id) if chain_id is None else chain_id + + body = {"token_mint": token_mint, "chain_id": chain_id, + "max_steps_to_execute": max_steps_to_execute, "cached_accounts": cached_accounts, + "solana_accounts": solana_accounts, + "sender": sender, + "contract": contract, "value": value, "gas_limit": gas_limit} + if contract: + body["contract"] = contract + if data: + body['data'] = list(data) + resp = requests.post(url=f"{self.url}/emulate", json=body, headers=self.headers) + return resp.json() + + def get_storage_at(self, contract_id, index="0x0"): + return requests.get(f"{self.url}/get-storage-at?contract_id={contract_id}&index={index}").json() + + def get_ether_account_data(self, ether): + return requests.get(f"{self.url}/get-ether-account-data?ether={ether}").json() From 13a4e7915568cb26be0ec41ccc5e56f22d8d5e27 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Wed, 9 Aug 2023 13:00:16 +0300 Subject: [PATCH 002/318] NDEV-1925: Remove environmental crate (#149) * Move neon_lib::types::trace module into neon_lib::event_listener * Promote evm_loader::evm::tracing module to directory * Move neon_lib::event_listener module into evm_loader::evm::tracing * Inject Tracer as Machine field + remove environmental crate * cargo clippy --fix + cargo fmt * Add tracing feature back * CR * Move Bytes struct to bytes module * Rename bytes::Bytes to hexbytes::HexBytes --- evm_loader/Cargo.lock | 7 - evm_loader/api/Cargo.toml | 4 +- .../api/src/api_server/handlers/emulate.rs | 5 +- .../src/api_server/handlers/emulate_hash.rs | 5 +- evm_loader/api/src/main.rs | 1 - evm_loader/cli/Cargo.toml | 4 +- evm_loader/cli/src/main.rs | 6 +- evm_loader/lib/Cargo.toml | 4 +- evm_loader/lib/src/account_storage.rs | 7 +- evm_loader/lib/src/commands/emulate.rs | 19 +- evm_loader/lib/src/commands/trace.rs | 78 ++++---- evm_loader/lib/src/lib.rs | 1 - evm_loader/lib/src/types/mod.rs | 94 +--------- evm_loader/lib/src/types/request_models.rs | 2 +- evm_loader/program/Cargo.toml | 7 +- evm_loader/program/src/evm/memory.rs | 87 ++++++--- evm_loader/program/src/evm/mod.rs | 166 +++++++++++++----- evm_loader/program/src/evm/opcode.rs | 107 +++++++---- evm_loader/program/src/evm/stack.rs | 33 +++- .../event_listener/listener_tracer.rs | 2 +- .../event_listener/listener_vm_tracer.rs | 7 +- .../src/evm/tracing}/event_listener/mod.rs | 4 +- .../src/evm/tracing/event_listener}/trace.rs | 15 +- .../src/evm/tracing}/event_listener/tracer.rs | 11 +- .../evm/tracing}/event_listener/vm_tracer.rs | 2 +- .../src/evm/{tracing.rs => tracing/mod.rs} | 13 +- .../src/instruction/transaction_execute.rs | 8 +- .../src/instruction/transaction_step.rs | 8 +- evm_loader/program/src/types/hexbytes.rs | 90 ++++++++++ evm_loader/program/src/types/mod.rs | 1 + 30 files changed, 484 insertions(+), 314 deletions(-) rename evm_loader/{lib/src => program/src/evm/tracing}/event_listener/listener_tracer.rs (93%) rename evm_loader/{lib/src => program/src/evm/tracing}/event_listener/listener_vm_tracer.rs (94%) rename evm_loader/{lib/src => program/src/evm/tracing}/event_listener/mod.rs (94%) rename evm_loader/{lib/src/types => program/src/evm/tracing/event_listener}/trace.rs (97%) rename evm_loader/{lib/src => program/src/evm/tracing}/event_listener/tracer.rs (64%) rename evm_loader/{lib/src => program/src/evm/tracing}/event_listener/vm_tracer.rs (89%) rename evm_loader/program/src/evm/{tracing.rs => tracing/mod.rs} (72%) create mode 100644 evm_loader/program/src/types/hexbytes.rs diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 39bf4d77d..31aa93a99 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -1160,12 +1160,6 @@ dependencies = [ "termcolor", ] -[[package]] -name = "environmental" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48c92028aaa870e83d51c64e5d4e0b6981b360c522198c23959f219a4e1b15b" - [[package]] name = "errno" version = "0.3.1" @@ -1211,7 +1205,6 @@ dependencies = [ "borsh", "cfg-if", "const_format", - "environmental", "ethnum", "evm-loader-macro", "hex", diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index d849b642c..d8afc17f3 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -7,11 +7,11 @@ edition = "2021" [dependencies] clap = "2.33.3" -evm-loader = { path = "../program", default_features = false, features = ["log", "tracing"] } +evm-loader = { path = "../program", default_features = false, features = ["log"] } solana-sdk = "=1.14.20" serde = "1.0.147" serde_json = "1.0.85" -ethnum = { version = "1", default_features = false, features = [ "serde" ] } +ethnum = { version = "1", default_features = false, features = ["serde"] } tokio = { version = "1", features = ["full"] } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } diff --git a/evm_loader/api/src/api_server/handlers/emulate.rs b/evm_loader/api/src/api_server/handlers/emulate.rs index 9f0160fb9..cf24ced0a 100644 --- a/evm_loader/api/src/api_server/handlers/emulate.rs +++ b/evm_loader/api/src/api_server/handlers/emulate.rs @@ -1,10 +1,9 @@ use axum::{http::StatusCode, Json}; +use evm_loader::evm::tracing::event_listener::trace::TraceCallConfig; use std::convert::Into; use crate::{ - commands::emulate as EmulateCommand, - context, - types::{request_models::EmulateRequestModel, trace::TraceCallConfig}, + commands::emulate as EmulateCommand, context, types::request_models::EmulateRequestModel, NeonApiState, }; diff --git a/evm_loader/api/src/api_server/handlers/emulate_hash.rs b/evm_loader/api/src/api_server/handlers/emulate_hash.rs index 78c3a514a..39a21c6a6 100644 --- a/evm_loader/api/src/api_server/handlers/emulate_hash.rs +++ b/evm_loader/api/src/api_server/handlers/emulate_hash.rs @@ -1,10 +1,9 @@ use axum::{http::StatusCode, Json}; +use evm_loader::evm::tracing::event_listener::trace::TraceCallConfig; use std::convert::Into; use crate::{ - commands::emulate as EmulateCommand, - context, - types::{request_models::EmulateHashRequestModel, trace::TraceCallConfig}, + commands::emulate as EmulateCommand, context, types::request_models::EmulateHashRequestModel, NeonApiState, }; diff --git a/evm_loader/api/src/main.rs b/evm_loader/api/src/main.rs index 99ac6189c..103ad11da 100644 --- a/evm_loader/api/src/main.rs +++ b/evm_loader/api/src/main.rs @@ -11,7 +11,6 @@ pub use neon_lib::commands; pub use neon_lib::config; pub use neon_lib::context; pub use neon_lib::errors; -pub use neon_lib::event_listener; pub use neon_lib::rpc; pub use neon_lib::syscall_stubs; pub use neon_lib::types; diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index 7cf0b1643..acaac9ed1 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] clap = "2.33.3" -evm-loader = { path = "../program", default_features = false, features = ["log", "tracing"] } +evm-loader = { path = "../program", default_features = false, features = ["log"] } solana-sdk = "=1.14.20" solana-client = "=1.14.20" solana-clap-utils = "=1.14.20" @@ -17,6 +17,6 @@ serde = "1.0.147" serde_json = "1.0.85" log = "0.4.17" fern = "0.6" -ethnum = { version = "1", default_features = false, features = [ "serde" ] } +ethnum = { version = "1", default_features = false, features = ["serde"] } tokio = { version = "1", features = ["full"] } neon-lib = { path = "../lib" } diff --git a/evm_loader/cli/src/main.rs b/evm_loader/cli/src/main.rs index 1a8814f3c..dab7509af 100644 --- a/evm_loader/cli/src/main.rs +++ b/evm_loader/cli/src/main.rs @@ -21,6 +21,7 @@ pub use context::Context; use std::io::Read; use ethnum::U256; +use evm_loader::evm::tracing::event_listener::trace::{TraceCallConfig, TraceConfig}; use serde_json::json; use solana_clap_utils::input_parsers::{pubkey_of, value_of, values_of}; use solana_client::client_error::{ClientError, ClientErrorKind}; @@ -33,10 +34,7 @@ use tokio::time::Instant; use crate::{ errors::NeonError, rpc::Rpc, - types::{ - trace::{TraceCallConfig, TraceConfig}, - IndexerDb, TraceNextBlockParams, TransactionHashParams, TransactionParams, TxParams, - }, + types::{IndexerDb, TraceNextBlockParams, TransactionHashParams, TransactionParams, TxParams}, }; use evm_loader::types::Address; diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 43c8ca4d7..55c17d070 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -22,12 +22,12 @@ hex = "0.4.2" serde = "1.0.147" log = "0.4.17" rand = "0.8" -ethnum = { version = "1", default_features = false, features = [ "serde" ] } +ethnum = { version = "1", default_features = false, features = ["serde"] } goblin = { version = "0.6.0" } scroll = "0.11.0" tokio = { version = "1", features = ["full"] } postgres = { version = "0.19", features = ["with-chrono-0_4", "array-impls"] } -tokio-postgres = {version="0.7", features=["with-uuid-0_8"]} +tokio-postgres = { version = "0.7", features = ["with-uuid-0_8"] } lazy_static = "1.4" clickhouse = "0.11.5" tracing = "0.1" diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index e1a6ff10b..f8c1792dd 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -1,14 +1,11 @@ use std::{cell::RefCell, collections::HashMap, convert::TryInto, rc::Rc}; use tokio::sync::RwLock; -use crate::{ - rpc::Rpc, - types::trace::{AccountOverrides, BlockOverrides}, - NeonError, -}; +use crate::{rpc::Rpc, NeonError}; use ethnum::U256; use evm_loader::account::ether_contract; use evm_loader::account_storage::{find_slot_hash, AccountOperation, AccountsOperations}; +use evm_loader::evm::tracing::event_listener::trace::{AccountOverrides, BlockOverrides}; use evm_loader::{ account::{ ether_storage::EthereumStorageAddress, EthereumAccount, EthereumStorage, diff --git a/evm_loader/lib/src/commands/emulate.rs b/evm_loader/lib/src/commands/emulate.rs index a69174fc7..28929055d 100644 --- a/evm_loader/lib/src/commands/emulate.rs +++ b/evm_loader/lib/src/commands/emulate.rs @@ -1,7 +1,12 @@ -use log::{debug, info}; use std::fmt::{Display, Formatter}; use ethnum::U256; +use log::{debug, info}; +use serde::{Deserialize, Serialize}; +use solana_sdk::{commitment_config::CommitmentConfig, pubkey::Pubkey}; + +use evm_loader::evm::tracing::event_listener::trace::TraceCallConfig; +use evm_loader::evm::tracing::event_listener::tracer::TracerType; use evm_loader::{ account_storage::AccountStorage, config::{EVM_STEPS_MIN, PAYMENT_TO_TREASURE}, @@ -10,18 +15,15 @@ use evm_loader::{ gasometer::LAMPORTS_PER_SIGNATURE, types::{Address, Transaction}, }; -use serde::{Deserialize, Serialize}; -use crate::types::block; +use crate::types::{block, TxParams}; use crate::{ account_storage::{EmulatorAccountStorage, NeonAccount, SolanaAccount}, errors::NeonError, rpc::Rpc, syscall_stubs::Stubs, - types::{trace::TraceCallConfig, TxParams}, NeonResult, }; -use solana_sdk::{commitment_config::CommitmentConfig, pubkey::Pubkey}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct EmulationResult { @@ -119,6 +121,7 @@ pub async fn execute( accounts, solana_accounts, trace_call_config, + None, ) .await?; let accounts = block(storage.accounts.read()).values().cloned().collect(); @@ -147,6 +150,7 @@ pub(crate) async fn emulate_transaction<'a>( accounts: &[Address], solana_accounts: &[Pubkey], trace_call_config: TraceCallConfig, + tracer: TracerType, ) -> Result<(EmulationResult, EmulatorAccountStorage<'a>), NeonError> { setup_syscall_stubs(rpc_client).await?; @@ -163,7 +167,7 @@ pub(crate) async fn emulate_transaction<'a>( ) .await?; - emulate_trx(tx_params, &storage, chain_id, step_limit) + emulate_trx(tx_params, &storage, chain_id, step_limit, tracer) .await .map(move |result| (result, storage)) } @@ -173,6 +177,7 @@ pub(crate) async fn emulate_trx<'a>( storage: &'a EmulatorAccountStorage<'a>, chain_id: u64, step_limit: u64, + tracer: TracerType, ) -> Result { let (exit_status, actions, steps_executed) = { let mut backend = ExecutorState::new(storage); @@ -188,7 +193,7 @@ pub(crate) async fn emulate_trx<'a>( chain_id: Some(chain_id.into()), ..Transaction::default() }; - let mut evm = Machine::new(trx, tx_params.from, &mut backend)?; + let mut evm = Machine::new(trx, tx_params.from, &mut backend, tracer)?; let (result, steps_executed) = evm.execute(step_limit, &mut backend)?; if result == ExitStatus::StepLimit { diff --git a/evm_loader/lib/src/commands/trace.rs b/evm_loader/lib/src/commands/trace.rs index 1c7a03ff4..bc4a923b8 100644 --- a/evm_loader/lib/src/commands/trace.rs +++ b/evm_loader/lib/src/commands/trace.rs @@ -1,18 +1,20 @@ +use std::fmt::{Display, Formatter}; +use std::sync::{Arc, RwLock}; + +use serde::{Deserialize, Serialize}; +use solana_sdk::{commitment_config::CommitmentConfig, pubkey::Pubkey}; + +use evm_loader::evm::tracing::event_listener::trace::{TraceCallConfig, TraceConfig, TracedCall}; +use evm_loader::evm::tracing::event_listener::tracer::Tracer; +use evm_loader::types::Address; + use crate::{ account_storage::EmulatorAccountStorage, commands::emulate::{emulate_transaction, emulate_trx, setup_syscall_stubs}, errors::NeonError, - event_listener::tracer::Tracer, rpc::Rpc, - types::{ - trace::{TraceCallConfig, TraceConfig, TracedCall}, - TxParams, - }, + types::TxParams, }; -use evm_loader::types::Address; -use serde::{Deserialize, Serialize}; -use solana_sdk::{commitment_config::CommitmentConfig, pubkey::Pubkey}; -use std::fmt::{Display, Formatter}; #[allow(clippy::too_many_arguments)] pub async fn trace_transaction( @@ -27,26 +29,31 @@ pub async fn trace_transaction( solana_accounts: &[Pubkey], trace_call_config: TraceCallConfig, ) -> Result { - let mut tracer = Tracer::new(trace_call_config.trace_config.enable_return_data); - - let (emulation_result, _storage) = evm_loader::evm::tracing::using(&mut tracer, || async { - emulate_transaction( - rpc_client, - evm_loader, - tx, - token, - chain_id, - steps, - commitment, - accounts, - solana_accounts, - trace_call_config, - ) - .await - }) + let tracer = Arc::new(RwLock::new(Some(Tracer::new( + trace_call_config.trace_config.enable_return_data, + )))); + + let (emulation_result, _storage) = emulate_transaction( + rpc_client, + evm_loader, + tx, + token, + chain_id, + steps, + commitment, + accounts, + solana_accounts, + trace_call_config, + Some(tracer.clone()), + ) .await?; - let (vm_trace, full_trace_data) = tracer.into_traces(); + let (vm_trace, full_trace_data) = tracer + .write() + .expect("lock acquire should be successful") + .take() + .expect("Option should not be empty") + .into_traces(); Ok(TracedCall { vm_trace, @@ -110,14 +117,19 @@ async fn trace_trx<'a>( steps: u64, trace_config: &TraceConfig, ) -> Result { - let mut tracer = Tracer::new(trace_config.enable_return_data); + let tracer = Arc::new(RwLock::new(Some(Tracer::new( + trace_config.enable_return_data, + )))); - let emulation_result = evm_loader::evm::tracing::using(&mut tracer, || { - emulate_trx(tx_params, storage, chain_id, steps) - }) - .await?; + let emulation_result = + emulate_trx(tx_params, storage, chain_id, steps, Some(tracer.clone())).await?; - let (vm_trace, full_trace_data) = tracer.into_traces(); + let (vm_trace, full_trace_data) = tracer + .write() + .expect("lock acquire should be successful") + .take() + .expect("Option should not be empty") + .into_traces(); Ok(TracedCall { vm_trace, diff --git a/evm_loader/lib/src/lib.rs b/evm_loader/lib/src/lib.rs index a2a1eee4b..3d84ba382 100644 --- a/evm_loader/lib/src/lib.rs +++ b/evm_loader/lib/src/lib.rs @@ -3,7 +3,6 @@ pub mod commands; pub mod config; pub mod context; pub mod errors; -pub mod event_listener; pub mod rpc; pub mod syscall_stubs; pub mod types; diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index 4604adc92..659b5b870 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -1,7 +1,5 @@ mod indexer_db; pub mod request_models; -#[allow(clippy::all)] -pub mod trace; mod tracer_ch_db; pub use evm_loader::types::Address; @@ -13,100 +11,16 @@ use tokio::runtime::Runtime; use tokio::task::block_in_place; pub use tracer_ch_db::{ChError, ChResult, ClickHouseDb as TracerDb}; +use evm_loader::evm::tracing::event_listener::trace::{TraceCallConfig, TraceConfig}; +use evm_loader::types::hexbytes::HexBytes; use { - crate::types::trace::{TraceCallConfig, TraceConfig}, ethnum::U256, - hex::FromHex, postgres::NoTls, - serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer}, - std::{fmt, ops::Deref}, + serde::{Deserialize, Deserializer, Serialize, Serializer}, thiserror::Error, tokio_postgres::{connect, Client}, }; -/// Wrapper structure around vector of bytes. -#[derive(Debug, PartialEq, Eq, Default, Hash, Clone)] -pub struct Bytes(pub Vec); - -impl Bytes { - /// Simple constructor. - pub fn new(bytes: Vec) -> Bytes { - Bytes(bytes) - } -} - -impl Deref for Bytes { - type Target = Vec; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl From> for Bytes { - fn from(bytes: Vec) -> Bytes { - Bytes(bytes) - } -} - -impl From for Vec { - fn from(value: Bytes) -> Self { - value.0 - } -} - -impl Serialize for Bytes { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut value = "0x".to_owned(); - value.push_str(hex::encode(&self.0).as_str()); - serializer.serialize_str(value.as_ref()) - } -} - -impl<'a> Deserialize<'a> for Bytes { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'a>, - { - deserializer.deserialize_any(BytesVisitor) - } -} - -struct BytesVisitor; - -impl<'a> Visitor<'a> for BytesVisitor { - type Value = Bytes; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "a 0x-prefixed, hex-encoded vector of bytes") - } - - fn visit_str(self, value: &str) -> Result - where - E: serde::de::Error, - { - if value.len() >= 2 && value.starts_with("0x") && value.len() & 1 == 0 { - Ok(Bytes::new(FromHex::from_hex(&value[2..]).map_err(|e| { - serde::de::Error::custom(format!("Invalid hex: {e}")) - })?)) - } else { - Err(serde::de::Error::custom( - "Invalid bytes format. Expected a 0x-prefixed hex string with even length", - )) - } - } - - fn visit_string(self, value: String) -> Result - where - E: serde::de::Error, - { - self.visit_str(value.as_ref()) - } -} - #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone, Default)] pub struct ChDbConfig { pub clickhouse_url: Vec, @@ -131,7 +45,7 @@ pub struct TxParams { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TransactionParams { - pub data: Option, + pub data: Option, pub trace_config: Option, } diff --git a/evm_loader/lib/src/types/request_models.rs b/evm_loader/lib/src/types/request_models.rs index e64cda0e1..7c9a04368 100644 --- a/evm_loader/lib/src/types/request_models.rs +++ b/evm_loader/lib/src/types/request_models.rs @@ -1,6 +1,6 @@ -use crate::types::trace::{TraceCallConfig, TraceConfig}; use crate::types::{PubkeyBase58, TxParams}; use ethnum::U256; +use evm_loader::evm::tracing::event_listener::trace::{TraceCallConfig, TraceConfig}; use evm_loader::types::Address; use serde::{Deserialize, Serialize}; use solana_sdk::pubkey::Pubkey; diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index cfc046c5f..f104a0bbb 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -1,4 +1,3 @@ - # Note: This crate must be built using cargo build-bpf [package] @@ -34,7 +33,8 @@ no-entrypoint = [] test-bpf = [] custom-heap = [] default = ["custom-heap"] -tracing = ["environmental"] + +tracing = [] [dependencies] linked_list_allocator = { version = "0.10", default_features = false } @@ -53,11 +53,10 @@ borsh = "0.9" bincode = "1" serde_bytes = "0.11" serde = { version = "1", features = ["derive"] } -ethnum = { version = "1", default_features = false, features = [ "serde" ] } +ethnum = { version = "1", default_features = false, features = ["serde"] } const_format = { version = "0.2.21" } cfg-if = { version = "1.0" } log = { version = "0.4", default-features = false, optional = true } -environmental = { version = "1", default-features = false, optional = true} [dev-dependencies] serde_json = "1" diff --git a/evm_loader/program/src/evm/memory.rs b/evm_loader/program/src/evm/memory.rs index acbdd6270..cffb0a989 100644 --- a/evm_loader/program/src/evm/memory.rs +++ b/evm_loader/program/src/evm/memory.rs @@ -1,10 +1,16 @@ -use solana_program::program_memory::{sol_memcpy, sol_memset}; use std::alloc::{GlobalAlloc, Layout}; use std::ops::Range; +use solana_program::program_memory::{sol_memcpy, sol_memset}; + +use crate::error::Error; +#[cfg(feature = "tracing")] +use crate::evm::tracing::event_listener::tracer::TracerType; +#[cfg(feature = "tracing")] +use crate::evm::tracing::EventListener; + use super::utils::checked_next_multiple_of_32; use super::{tracing_event, Buffer}; -use crate::error::Error; const MAX_MEMORY_SIZE: usize = 64 * 1024; const MEMORY_CAPACITY: usize = 1024; @@ -16,14 +22,20 @@ pub struct Memory { data: *mut u8, capacity: usize, size: usize, + #[cfg(feature = "tracing")] + tracer: TracerType, } impl Memory { - pub fn new() -> Self { - Self::with_capacity(MEMORY_CAPACITY) + pub fn new(#[cfg(feature = "tracing")] tracer: TracerType) -> Self { + Self::with_capacity( + MEMORY_CAPACITY, + #[cfg(feature = "tracing")] + tracer, + ) } - pub fn with_capacity(capacity: usize) -> Self { + pub fn with_capacity(capacity: usize, #[cfg(feature = "tracing")] tracer: TracerType) -> Self { unsafe { let layout = Layout::from_size_align_unchecked(capacity, MEMORY_ALIGN); let data = crate::allocator::EVM.alloc_zeroed(layout); @@ -35,6 +47,8 @@ impl Memory { data, capacity, size: 0, + #[cfg(feature = "tracing")] + tracer, } } } @@ -55,6 +69,8 @@ impl Memory { data, capacity, size: v.len(), + #[cfg(feature = "tracing")] + tracer: None, } } } @@ -140,10 +156,13 @@ impl Memory { } pub fn write_32(&mut self, offset: usize, value: &[u8; 32]) -> Result<(), Error> { - tracing_event!(super::tracing::Event::MemorySet { - offset, - data: value.to_vec() - }); + tracing_event!( + self, + super::tracing::Event::MemorySet { + offset, + data: value.to_vec() + } + ); self.realloc(offset, 32)?; @@ -156,10 +175,13 @@ impl Memory { } pub fn write_byte(&mut self, offset: usize, value: u8) -> Result<(), Error> { - tracing_event!(super::tracing::Event::MemorySet { - offset, - data: vec![value] - }); + tracing_event!( + self, + super::tracing::Event::MemorySet { + offset, + data: vec![value] + } + ); self.realloc(offset, 1)?; @@ -191,24 +213,30 @@ impl Memory { match source_offset { source_offset if source_offset >= source.len() => { - tracing_event!(super::tracing::Event::MemorySet { - offset, - data: vec![0; length] - }); + tracing_event!( + self, + super::tracing::Event::MemorySet { + offset, + data: vec![0; length] + } + ); sol_memset(data, 0, length); } source_offset if (source_offset + length) > source.len() => { let source = &source[source_offset..]; - tracing_event!(super::tracing::Event::MemorySet { - offset, - data: { - let mut buffer = vec![0_u8; length]; - buffer[..source.len()].copy_from_slice(source); - buffer + tracing_event!( + self, + super::tracing::Event::MemorySet { + offset, + data: { + let mut buffer = vec![0_u8; length]; + buffer[..source.len()].copy_from_slice(source); + buffer + } } - }); + ); data[..source.len()].copy_from_slice(source); data[source.len()..].fill(0_u8); @@ -216,10 +244,13 @@ impl Memory { source_offset => { let source = &source[source_offset..source_offset + length]; - tracing_event!(super::tracing::Event::MemorySet { - offset, - data: source.to_vec() - }); + tracing_event!( + self, + super::tracing::Event::MemorySet { + offset, + data: source.to_vec() + } + ); sol_memcpy(data, source, length); } diff --git a/evm_loader/program/src/evm/mod.rs b/evm_loader/program/src/evm/mod.rs index 920c49462..437148b99 100644 --- a/evm_loader/program/src/evm/mod.rs +++ b/evm_loader/program/src/evm/mod.rs @@ -8,12 +8,22 @@ use ethnum::U256; use serde::{Deserialize, Serialize}; use solana_program::log::sol_log_data; +pub use buffer::Buffer; +pub use precompile::is_precompile_address; +pub use precompile::precompile; + +#[cfg(feature = "tracing")] +use crate::evm::tracing::event_listener::tracer::TracerType; +#[cfg(feature = "tracing")] +use crate::evm::tracing::EventListener; use crate::{ error::{build_revert_message, Error, Result}, evm::opcode::Action, types::{Address, Transaction}, }; +use self::{database::Database, memory::Memory, stack::Stack}; + mod buffer; pub mod database; mod memory; @@ -25,46 +35,46 @@ mod stack; pub mod tracing; mod utils; -use self::{database::Database, memory::Memory, stack::Stack}; -pub use buffer::Buffer; -pub use precompile::is_precompile_address; -pub use precompile::precompile; - macro_rules! tracing_event { - ($x:expr) => { + ($self:ident, $x:expr) => { #[cfg(feature = "tracing")] - crate::evm::tracing::with(|listener| listener.event($x)); + if let Some(tracer) = &$self.tracer { + tracer.write().unwrap().as_mut().unwrap().event($x); + } }; - ($condition:expr; $x:expr) => { + ($self:ident, $condition:expr, $x:expr) => { #[cfg(feature = "tracing")] - if $condition { - crate::evm::tracing::with(|listener| listener.event($x)); + if let Some(tracer) = &$self.tracer { + if $condition { + tracer.write().unwrap().as_mut().unwrap().event($x); + } } }; } macro_rules! trace_end_step { - ($return_data_vec:expr) => { + ($self:ident, $return_data_vec:expr) => { #[cfg(feature = "tracing")] - crate::evm::tracing::with(|listener| { - if listener.enable_return_data() { - listener.event(crate::evm::tracing::Event::EndStep { + if let Some(tracer) = &$self.tracer { + let mut tracer = tracer.write().unwrap(); + let tracer = tracer.as_mut().unwrap(); + if tracer.enable_return_data() { + tracer.event(crate::evm::tracing::Event::EndStep { gas_used: 0_u64, return_data: $return_data_vec, }) } else { - listener.event(crate::evm::tracing::Event::EndStep { + tracer.event(crate::evm::tracing::Event::EndStep { gas_used: 0_u64, return_data: None, }) } - }) + } }; - - ($condition:expr; $return_data_vec:expr) => { + ($self:ident, $condition:expr; $return_data_vec:expr) => { #[cfg(feature = "tracing")] if $condition { - trace_end_step!($return_data_vec) + trace_end_step!($self, $return_data_vec) } }; } @@ -113,8 +123,8 @@ pub struct Machine { return_data: Buffer, return_range: Range, - stack: stack::Stack, - memory: memory::Memory, + stack: Stack, + memory: Memory, pc: usize, is_static: bool, @@ -124,6 +134,10 @@ pub struct Machine { #[serde(skip)] phantom: PhantomData<*const B>, + + #[serde(skip)] + #[cfg(feature = "tracing")] + tracer: TracerType, } impl Machine { @@ -158,7 +172,12 @@ impl Machine { Ok(evm) } - pub fn new(trx: Transaction, origin: Address, backend: &mut B) -> Result { + pub fn new( + trx: Transaction, + origin: Address, + backend: &mut B, + #[cfg(feature = "tracing")] tracer: TracerType, + ) -> Result { let origin_nonce = backend.nonce(&origin)?; if origin_nonce == u64::MAX { @@ -188,13 +207,30 @@ impl Machine { } if trx.target.is_some() { - Self::new_call(trx, origin, backend) + Self::new_call( + trx, + origin, + backend, + #[cfg(feature = "tracing")] + tracer, + ) } else { - Self::new_create(trx, origin, backend) + Self::new_create( + trx, + origin, + backend, + #[cfg(feature = "tracing")] + tracer, + ) } } - fn new_call(trx: Transaction, origin: Address, backend: &mut B) -> Result { + fn new_call( + trx: Transaction, + origin: Address, + backend: &mut B, + #[cfg(feature = "tracing")] tracer: TracerType, + ) -> Result { assert!(trx.target.is_some()); let target = trx.target.unwrap(); @@ -221,17 +257,30 @@ impl Machine { call_data: trx.call_data, return_data: Buffer::empty(), return_range: 0..0, - stack: Stack::new(), - memory: Memory::new(), + stack: Stack::new( + #[cfg(feature = "tracing")] + tracer.clone(), + ), + memory: Memory::new( + #[cfg(feature = "tracing")] + tracer.clone(), + ), pc: 0_usize, is_static: false, reason: Reason::Call, parent: None, phantom: PhantomData, + #[cfg(feature = "tracing")] + tracer, }) } - fn new_create(trx: Transaction, origin: Address, backend: &mut B) -> Result { + fn new_create( + trx: Transaction, + origin: Address, + backend: &mut B, + #[cfg(feature = "tracing")] tracer: TracerType, + ) -> Result { assert!(trx.target.is_none()); let target = Address::from_create(&origin, trx.nonce); @@ -259,8 +308,14 @@ impl Machine { gas_limit: trx.gas_limit, return_data: Buffer::empty(), return_range: 0..0, - stack: Stack::new(), - memory: Memory::new(), + stack: Stack::new( + #[cfg(feature = "tracing")] + tracer.clone(), + ), + memory: Memory::new( + #[cfg(feature = "tracing")] + tracer.clone(), + ), pc: 0_usize, is_static: false, reason: Reason::Create, @@ -268,6 +323,8 @@ impl Machine { call_data: Buffer::empty(), parent: None, phantom: PhantomData, + #[cfg(feature = "tracing")] + tracer, }) } @@ -278,10 +335,13 @@ impl Machine { let mut step = 0_u64; - tracing_event!(tracing::Event::BeginVM { - context: self.context, - code: self.execution_code.to_vec() - }); + tracing_event!( + self, + tracing::Event::BeginVM { + context: self.context, + code: self.execution_code.to_vec() + } + ); let status = loop { if is_precompile_address(&self.context.contract) { @@ -299,12 +359,15 @@ impl Machine { let opcode = self.execution_code.get_or_default(self.pc); - tracing_event!(tracing::Event::BeginStep { - opcode, - pc: self.pc, - stack: self.stack.to_vec(), - memory: self.memory.to_vec() - }); + tracing_event!( + self, + tracing::Event::BeginStep { + opcode, + pc: self.pc, + stack: self.stack.to_vec(), + memory: self.memory.to_vec() + } + ); // SAFETY: OPCODES.len() == 256, opcode <= 255 let opcode_fn = unsafe { Self::OPCODES.get_unchecked(opcode as usize) }; @@ -317,7 +380,7 @@ impl Machine { } }; - trace_end_step!(opcode_result != Action::Noop; match &opcode_result { + trace_end_step!(self, opcode_result != Action::Noop; match &opcode_result { Action::Return(value) | Action::Revert(value) => Some(value.clone()), _ => None, }); @@ -333,9 +396,12 @@ impl Machine { }; }; - tracing_event!(tracing::Event::EndVM { - status: status.clone() - }); + tracing_event!( + self, + tracing::Event::EndVM { + status: status.clone() + } + ); Ok((status, step)) } @@ -357,13 +423,21 @@ impl Machine { call_data, return_data: Buffer::empty(), return_range: 0..0, - stack: Stack::new(), - memory: Memory::new(), + stack: Stack::new( + #[cfg(feature = "tracing")] + self.tracer.clone(), + ), + memory: Memory::new( + #[cfg(feature = "tracing")] + self.tracer.clone(), + ), pc: 0_usize, is_static: self.is_static, reason, parent: None, phantom: PhantomData, + #[cfg(feature = "tracing")] + tracer: self.tracer.clone(), }; core::mem::swap(self, &mut other); diff --git a/evm_loader/program/src/evm/opcode.rs b/evm_loader/program/src/evm/opcode.rs index d90926d8e..8dee94c8e 100644 --- a/evm_loader/program/src/evm/opcode.rs +++ b/evm_loader/program/src/evm/opcode.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "tracing")] +use crate::evm::tracing::EventListener; /// use ethnum::{I256, U256}; use solana_program::log::sol_log_data; @@ -735,7 +737,7 @@ impl Machine { let index = self.stack.pop_u256()?; let value = backend.storage(&self.context.contract, &index)?; - tracing_event!(super::tracing::Event::StorageAccess { index, value }); + tracing_event!(self, super::tracing::Event::StorageAccess { index, value }); self.stack.push_array(&value)?; @@ -751,8 +753,8 @@ impl Machine { let index = self.stack.pop_u256()?; let value = *self.stack.pop_array()?; - tracing_event!(super::tracing::Event::StorageSet { index, value }); - tracing_event!(super::tracing::Event::StorageAccess { index, value }); + tracing_event!(self, super::tracing::Event::StorageSet { index, value }); + tracing_event!(self, super::tracing::Event::StorageAccess { index, value }); backend.set_storage(self.context.contract, index, value)?; @@ -981,10 +983,13 @@ impl Machine { code_address: None, }; - tracing_event!(super::tracing::Event::BeginVM { - context, - code: init_code.to_vec() - }); + tracing_event!( + self, + super::tracing::Event::BeginVM { + context, + code: init_code.to_vec() + } + ); self.fork(Reason::Create, context, init_code, Buffer::empty(), None); backend.snapshot(); @@ -1028,10 +1033,13 @@ impl Machine { code_address: Some(address), }; - tracing_event!(super::tracing::Event::BeginVM { - context, - code: code.to_vec() - }); + tracing_event!( + self, + super::tracing::Event::BeginVM { + context, + code: code.to_vec() + } + ); self.fork(Reason::Call, context, code, call_data, Some(gas_limit)); backend.snapshot(); @@ -1074,10 +1082,13 @@ impl Machine { code_address: Some(address), }; - tracing_event!(super::tracing::Event::BeginVM { - context, - code: code.to_vec() - }); + tracing_event!( + self, + super::tracing::Event::BeginVM { + context, + code: code.to_vec() + } + ); self.fork(Reason::Call, context, code, call_data, Some(gas_limit)); backend.snapshot(); @@ -1112,10 +1123,13 @@ impl Machine { ..self.context }; - tracing_event!(super::tracing::Event::BeginVM { - context, - code: code.to_vec() - }); + tracing_event!( + self, + super::tracing::Event::BeginVM { + context, + code: code.to_vec() + } + ); self.fork(Reason::Call, context, code, call_data, Some(gas_limit)); backend.snapshot(); @@ -1148,10 +1162,13 @@ impl Machine { code_address: Some(address), }; - tracing_event!(super::tracing::Event::BeginVM { - context, - code: code.to_vec() - }); + tracing_event!( + self, + super::tracing::Event::BeginVM { + context, + code: code.to_vec() + } + ); self.fork(Reason::Call, context, code, call_data, Some(gas_limit)); self.is_static = true; @@ -1213,10 +1230,13 @@ impl Machine { return Ok(Action::Return(return_data.to_vec())); } - trace_end_step!(Some(return_data.to_vec())); - tracing_event!(super::tracing::Event::EndVM { - status: super::ExitStatus::Return(return_data.to_vec()) - }); + trace_end_step!(self, Some(return_data.to_vec())); + tracing_event!( + self, + super::tracing::Event::EndVM { + status: super::ExitStatus::Return(return_data.to_vec()) + } + ); let returned = self.join(); match returned.reason { @@ -1253,10 +1273,13 @@ impl Machine { return Ok(Action::Revert(return_data.to_vec())); } - trace_end_step!(Some(return_data.to_vec())); - tracing_event!(super::tracing::Event::EndVM { - status: super::ExitStatus::Revert(return_data.to_vec()) - }); + trace_end_step!(self, Some(return_data.to_vec())); + tracing_event!( + self, + super::tracing::Event::EndVM { + status: super::ExitStatus::Revert(return_data.to_vec()) + } + ); let returned = self.join(); match returned.reason { @@ -1301,10 +1324,13 @@ impl Machine { return Ok(Action::Suicide); } - trace_end_step!(None); - tracing_event!(super::tracing::Event::EndVM { - status: super::ExitStatus::Suicide - }); + trace_end_step!(self, None); + tracing_event!( + self, + super::tracing::Event::EndVM { + status: super::ExitStatus::Suicide + } + ); let returned = self.join(); match returned.reason { @@ -1329,10 +1355,13 @@ impl Machine { return Ok(Action::Stop); } - trace_end_step!(None); - tracing_event!(super::tracing::Event::EndVM { - status: super::ExitStatus::Stop - }); + trace_end_step!(self, None); + tracing_event!( + self, + super::tracing::Event::EndVM { + status: super::ExitStatus::Stop + } + ); let returned = self.join(); match returned.reason { diff --git a/evm_loader/program/src/evm/stack.rs b/evm_loader/program/src/evm/stack.rs index dee7dd9fc..1181fe5fa 100644 --- a/evm_loader/program/src/evm/stack.rs +++ b/evm_loader/program/src/evm/stack.rs @@ -1,13 +1,20 @@ #![allow(clippy::inline_always)] -use super::tracing_event; -use crate::{error::Error, types::Address}; -use ethnum::{I256, U256}; use std::{ alloc::{GlobalAlloc, Layout}, convert::TryInto, }; +use ethnum::{I256, U256}; + +#[cfg(feature = "tracing")] +use crate::evm::tracing::event_listener::tracer::TracerType; +#[cfg(feature = "tracing")] +use crate::evm::tracing::EventListener; +use crate::{error::Error, types::Address}; + +use super::tracing_event; + const ELEMENT_SIZE: usize = 32; const STACK_SIZE: usize = ELEMENT_SIZE * 128; @@ -15,10 +22,12 @@ pub struct Stack { begin: *mut u8, end: *mut u8, top: *mut u8, + #[cfg(feature = "tracing")] + tracer: TracerType, } impl Stack { - pub fn new() -> Self { + pub fn new(#[cfg(feature = "tracing")] tracer: TracerType) -> Self { let (begin, end) = unsafe { let layout = Layout::from_size_align_unchecked(STACK_SIZE, ELEMENT_SIZE); let begin = crate::allocator::EVM.alloc(layout); @@ -35,6 +44,8 @@ impl Stack { begin, end, top: begin, + #[cfg(feature = "tracing")] + tracer, } } @@ -61,9 +72,12 @@ impl Stack { return Err(Error::StackOverflow); } - tracing_event!(super::tracing::Event::StackPush { - value: unsafe { *self.read() } - }); + tracing_event!( + self, + super::tracing::Event::StackPush { + value: unsafe { *self.read() } + } + ); unsafe { self.top = self.top.add(32); @@ -303,7 +317,10 @@ impl<'de> serde::Deserialize<'de> for Stack { return Err(E::invalid_length(v.len(), &self)); } - let mut stack = Stack::new(); + let mut stack = Stack::new( + #[cfg(feature = "tracing")] + None, + ); unsafe { stack.top = stack.begin.add(v.len()); diff --git a/evm_loader/lib/src/event_listener/listener_tracer.rs b/evm_loader/program/src/evm/tracing/event_listener/listener_tracer.rs similarity index 93% rename from evm_loader/lib/src/event_listener/listener_tracer.rs rename to evm_loader/program/src/evm/tracing/event_listener/listener_tracer.rs index cdc59c44a..9788927e9 100644 --- a/evm_loader/lib/src/event_listener/listener_tracer.rs +++ b/evm_loader/program/src/evm/tracing/event_listener/listener_tracer.rs @@ -1,5 +1,5 @@ use super::tracer::Tracer; -use crate::types::trace::FullTraceData; +use crate::evm::tracing::event_listener::trace::FullTraceData; pub trait ListenerTracer { fn begin_step(&mut self, stack: Vec<[u8; 32]>, memory: Vec); diff --git a/evm_loader/lib/src/event_listener/listener_vm_tracer.rs b/evm_loader/program/src/evm/tracing/event_listener/listener_vm_tracer.rs similarity index 94% rename from evm_loader/lib/src/event_listener/listener_vm_tracer.rs rename to evm_loader/program/src/evm/tracing/event_listener/listener_vm_tracer.rs index d9fa14be6..e5e72ec03 100644 --- a/evm_loader/lib/src/event_listener/listener_vm_tracer.rs +++ b/evm_loader/program/src/evm/tracing/event_listener/listener_vm_tracer.rs @@ -1,7 +1,8 @@ -use super::vm_tracer::VmTracer; -use crate::types::trace::{MemoryDiff, StorageDiff, VMTracer}; +use crate::evm::tracing::event_listener::trace::{MemoryDiff, StorageDiff, VMTracer}; +use crate::evm::{Context, ExitStatus}; use ethnum::U256; -use evm_loader::evm::{Context, ExitStatus}; + +use super::vm_tracer::VmTracer; pub trait ListenerVmTracer { fn begin_vm(&mut self, context: Context, code: Vec); diff --git a/evm_loader/lib/src/event_listener/mod.rs b/evm_loader/program/src/evm/tracing/event_listener/mod.rs similarity index 94% rename from evm_loader/lib/src/event_listener/mod.rs rename to evm_loader/program/src/evm/tracing/event_listener/mod.rs index 91e53e222..e61e5dc2d 100644 --- a/evm_loader/lib/src/event_listener/mod.rs +++ b/evm_loader/program/src/evm/tracing/event_listener/mod.rs @@ -1,9 +1,11 @@ mod listener_tracer; mod listener_vm_tracer; +#[allow(clippy::all)] +pub mod trace; pub mod tracer; mod vm_tracer; -use evm_loader::evm::tracing::{Event, EventListener}; +use crate::evm::tracing::{Event, EventListener}; use {listener_tracer::ListenerTracer, listener_vm_tracer::ListenerVmTracer, tracer::Tracer}; impl EventListener for Tracer { diff --git a/evm_loader/lib/src/types/trace.rs b/evm_loader/program/src/evm/tracing/event_listener/trace.rs similarity index 97% rename from evm_loader/lib/src/types/trace.rs rename to evm_loader/program/src/evm/tracing/event_listener/trace.rs index 854d69e8a..f2abdad96 100644 --- a/evm_loader/lib/src/types/trace.rs +++ b/evm_loader/program/src/evm/tracing/event_listener/trace.rs @@ -1,7 +1,9 @@ -use evm_loader::{account::EthereumAccount, types::Address}; +use crate::account::EthereumAccount; +use crate::types::hexbytes::HexBytes; +use crate::types::Address; use serde::{Deserialize, Serialize}; use std::fmt::{Display, Formatter}; -use {crate::types::Bytes, ethnum::U256, std::collections::HashMap}; +use {ethnum::U256, std::collections::HashMap}; #[derive(Serialize, Deserialize, Debug, Clone, PartialEq /*, RlpEncodable, RlpDecodable */)] /// A diff of some chunk of memory. @@ -9,7 +11,7 @@ pub struct MemoryDiff { /// Offset into memory the change begins. pub offset: usize, /// The changed data. - pub data: Bytes, + pub data: HexBytes, } #[derive(Serialize, Deserialize, Debug, Clone, PartialEq /*, RlpEncodable, RlpDecodable */)] @@ -58,7 +60,7 @@ pub struct VMTrace { /// The step (i.e. index into operations) at which this trace corresponds. pub parent_step: usize, /// The code to be executed. - pub code: Bytes, + pub code: HexBytes, /// The operations executed. pub operations: Vec, /// The sub traces for each interior action performed as part of this call/create. @@ -90,11 +92,12 @@ pub struct ExecutiveVMTracer { impl ExecutiveVMTracer { /// Create a new top-level instance. + #[must_use] pub fn toplevel() -> Self { ExecutiveVMTracer { data: VMTrace { parent_step: 0, - code: Bytes::default(), + code: HexBytes::default(), operations: vec![VMOperation::default()], // prefill with a single entry so that prepare_subtrace can get the parent_step subs: vec![], }, @@ -243,7 +246,7 @@ pub struct BlockOverrides { #[serde(rename_all = "camelCase")] pub struct AccountOverride { pub nonce: Option, - pub code: Option, + pub code: Option, pub balance: Option, pub state: Option>, pub state_diff: Option>, diff --git a/evm_loader/lib/src/event_listener/tracer.rs b/evm_loader/program/src/evm/tracing/event_listener/tracer.rs similarity index 64% rename from evm_loader/lib/src/event_listener/tracer.rs rename to evm_loader/program/src/evm/tracing/event_listener/tracer.rs index b3397f265..70da11af1 100644 --- a/evm_loader/lib/src/event_listener/tracer.rs +++ b/evm_loader/program/src/evm/tracing/event_listener/tracer.rs @@ -1,13 +1,19 @@ +use std::sync::{Arc, RwLock}; + +use crate::evm::tracing::event_listener::trace::{FullTraceData, VMTrace, VMTracer}; + use super::vm_tracer::VmTracer; -use crate::types::trace::{FullTraceData, VMTrace, VMTracer}; + +pub type TracerType = Option>>>; pub struct Tracer { pub vm: VmTracer, pub data: Vec, - pub(crate) enable_return_data: bool, + pub enable_return_data: bool, } impl Tracer { + #[must_use] pub fn new(enable_return_data: bool) -> Self { Tracer { vm: VmTracer::init(), @@ -16,6 +22,7 @@ impl Tracer { } } + #[must_use] pub fn into_traces(self) -> (Option, Vec) { let vm = self.vm.tracer.drain(); (vm, self.data) diff --git a/evm_loader/lib/src/event_listener/vm_tracer.rs b/evm_loader/program/src/evm/tracing/event_listener/vm_tracer.rs similarity index 89% rename from evm_loader/lib/src/event_listener/vm_tracer.rs rename to evm_loader/program/src/evm/tracing/event_listener/vm_tracer.rs index 67a038e51..8374e7426 100644 --- a/evm_loader/lib/src/event_listener/vm_tracer.rs +++ b/evm_loader/program/src/evm/tracing/event_listener/vm_tracer.rs @@ -1,4 +1,4 @@ -use crate::types::trace::{ExecutiveVMTracer, MemoryDiff, StorageDiff}; +use crate::evm::tracing::event_listener::trace::{ExecutiveVMTracer, MemoryDiff, StorageDiff}; use ethnum::U256; #[derive(Debug, Default, Clone)] diff --git a/evm_loader/program/src/evm/tracing.rs b/evm_loader/program/src/evm/tracing/mod.rs similarity index 72% rename from evm_loader/program/src/evm/tracing.rs rename to evm_loader/program/src/evm/tracing/mod.rs index 789008e54..cfd02f75a 100644 --- a/evm_loader/program/src/evm/tracing.rs +++ b/evm_loader/program/src/evm/tracing/mod.rs @@ -1,7 +1,7 @@ use super::{Context, ExitStatus}; use ethnum::U256; -environmental::environmental!(listener: dyn EventListener + 'static); +pub mod event_listener; pub trait EventListener { fn enable_return_data(&self) -> bool; @@ -44,14 +44,3 @@ pub enum Event { value: [u8; 32], }, } - -pub fn with(f: F) { - listener::with(f); -} - -pub fn using R>( - new: &mut (dyn EventListener + 'static + Send + Sync), - f: F, -) -> R { - listener::using(new, f) -} diff --git a/evm_loader/program/src/instruction/transaction_execute.rs b/evm_loader/program/src/instruction/transaction_execute.rs index 46a7d0ca5..5f3b9b305 100644 --- a/evm_loader/program/src/instruction/transaction_execute.rs +++ b/evm_loader/program/src/instruction/transaction_execute.rs @@ -54,7 +54,13 @@ pub fn execute<'a>( let (exit_reason, apply_state) = { let mut backend = ExecutorState::new(account_storage); - let mut evm = Machine::new(trx, caller_address, &mut backend)?; + let mut evm = Machine::new( + trx, + caller_address, + &mut backend, + #[cfg(feature = "tracing")] + None, + )?; let (result, _) = evm.execute(u64::MAX, &mut backend)?; let actions = backend.into_actions(); diff --git a/evm_loader/program/src/instruction/transaction_step.rs b/evm_loader/program/src/instruction/transaction_step.rs index 628183824..286d98dd7 100644 --- a/evm_loader/program/src/instruction/transaction_step.rs +++ b/evm_loader/program/src/instruction/transaction_step.rs @@ -38,7 +38,13 @@ pub fn do_begin<'a>( account_storage.block_accounts(true); let mut backend = ExecutorState::new(account_storage); - let evm = Machine::new(trx, caller, &mut backend)?; + let evm = Machine::new( + trx, + caller, + &mut backend, + #[cfg(feature = "tracing")] + None, + )?; serialize_evm_state(&mut storage, &backend, &evm)?; diff --git a/evm_loader/program/src/types/hexbytes.rs b/evm_loader/program/src/types/hexbytes.rs new file mode 100644 index 000000000..60601beb2 --- /dev/null +++ b/evm_loader/program/src/types/hexbytes.rs @@ -0,0 +1,90 @@ +use hex::FromHex; +use serde::de::Visitor; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use std::fmt; +use std::ops::Deref; + +/// TODO Maybe replace with #[serde(with = "hex")], but pay attention to "0x" prefix missing from "hex" serialization +/// Wrapper structure around vector of bytes. +#[derive(Debug, PartialEq, Eq, Default, Hash, Clone)] +pub struct HexBytes(pub Vec); + +impl HexBytes { + /// Simple constructor. + #[must_use] + pub fn new(bytes: Vec) -> HexBytes { + HexBytes(bytes) + } +} + +impl Deref for HexBytes { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl From> for HexBytes { + fn from(bytes: Vec) -> HexBytes { + HexBytes(bytes) + } +} + +impl From for Vec { + fn from(value: HexBytes) -> Self { + value.0 + } +} + +impl Serialize for HexBytes { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut value = "0x".to_owned(); + value.push_str(hex::encode(&self.0).as_str()); + serializer.serialize_str(value.as_ref()) + } +} + +impl<'a> Deserialize<'a> for HexBytes { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'a>, + { + deserializer.deserialize_any(BytesVisitor) + } +} + +struct BytesVisitor; + +impl<'a> Visitor<'a> for BytesVisitor { + type Value = HexBytes; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "a 0x-prefixed, hex-encoded vector of bytes") + } + + fn visit_str(self, value: &str) -> Result + where + E: serde::de::Error, + { + if value.len() >= 2 && value.starts_with("0x") && value.len() & 1 == 0 { + Ok(HexBytes::new(FromHex::from_hex(&value[2..]).map_err( + |e| serde::de::Error::custom(format!("Invalid hex: {e}")), + )?)) + } else { + Err(serde::de::Error::custom( + "Invalid bytes format. Expected a 0x-prefixed hex string with even length", + )) + } + } + + fn visit_string(self, value: String) -> Result + where + E: serde::de::Error, + { + self.visit_str(value.as_ref()) + } +} diff --git a/evm_loader/program/src/types/mod.rs b/evm_loader/program/src/types/mod.rs index 0cdaebdd9..2a7e7579e 100644 --- a/evm_loader/program/src/types/mod.rs +++ b/evm_loader/program/src/types/mod.rs @@ -2,4 +2,5 @@ pub use address::Address; pub use transaction::Transaction; mod address; +pub mod hexbytes; mod transaction; From cd01c2144da6141b3b2727aee93e056ac00a31bd Mon Sep 17 00:00:00 2001 From: Kristina Nikolaeva <112946046+kristinaNikolaevaa@users.noreply.github.com> Date: Mon, 14 Aug 2023 14:03:33 +0300 Subject: [PATCH 003/318] Fix neon evm CI (#161) * Update docker-compose-ci.yml * fixed pattern * Update docker-compose-ci.yml --- .github/workflows/deploy.py | 2 +- evm_loader/docker-compose-ci.yml | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index 6e610467d..08fdbd02d 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -137,7 +137,7 @@ def get_solana_container_name(project_name): f"docker-compose -p {project_name} -f ./evm_loader/docker-compose-ci.yml ps", shell=True, capture_output=True, text=True).stdout click.echo(data) - pattern = rf'{project_name}_[a-zA-Z0-9_]+' + pattern = rf'{project_name}_solana_[1-9]+' match = re.search(pattern, data) return match.group(0) diff --git a/evm_loader/docker-compose-ci.yml b/evm_loader/docker-compose-ci.yml index 806d82a51..2638ed777 100644 --- a/evm_loader/docker-compose-ci.yml +++ b/evm_loader/docker-compose-ci.yml @@ -18,7 +18,6 @@ services: dk-neon-api: restart: unless-stopped - container_name: dk-neon-api hostname: neon_api command: /opt/neon-api -H 0.0.0.0:8085 environment: @@ -38,11 +37,9 @@ services: NEON_DB_INDEXER_PASSWORD: "" KEYPAIR: /opt/id.json FEEPAIR: /opt/id.json - image: neonlabsorg/evm_loader:latest - expose: - - "8085" + image: ${EVM_LOADER_IMAGE} ports: - - 8085:8085 + - 8085 volumes: - ./files/id.json:/opt/id.json networks: From 163f6de2a31a739d8261cda1eda09a4483b53274 Mon Sep 17 00:00:00 2001 From: Denis K <100715772+dk-neon@users.noreply.github.com> Date: Wed, 16 Aug 2023 13:20:34 +0500 Subject: [PATCH 004/318] Simplified `TracerType` (removed unnecessary `Option`) (#164) --- evm_loader/lib/src/commands/trace.rs | 26 ++++++++----------- evm_loader/program/src/evm/mod.rs | 13 +++++----- .../tracing/event_listener/listener_tracer.rs | 5 +++- .../src/evm/tracing/event_listener/trace.rs | 2 ++ .../src/evm/tracing/event_listener/tracer.rs | 3 ++- .../evm/tracing/event_listener/vm_tracer.rs | 1 + 6 files changed, 26 insertions(+), 24 deletions(-) diff --git a/evm_loader/lib/src/commands/trace.rs b/evm_loader/lib/src/commands/trace.rs index bc4a923b8..576544edd 100644 --- a/evm_loader/lib/src/commands/trace.rs +++ b/evm_loader/lib/src/commands/trace.rs @@ -29,9 +29,9 @@ pub async fn trace_transaction( solana_accounts: &[Pubkey], trace_call_config: TraceCallConfig, ) -> Result { - let tracer = Arc::new(RwLock::new(Some(Tracer::new( + let tracer = Arc::new(RwLock::new(Tracer::new( trace_call_config.trace_config.enable_return_data, - )))); + ))); let (emulation_result, _storage) = emulate_transaction( rpc_client, @@ -48,11 +48,10 @@ pub async fn trace_transaction( ) .await?; - let (vm_trace, full_trace_data) = tracer - .write() - .expect("lock acquire should be successful") - .take() - .expect("Option should not be empty") + let (vm_trace, full_trace_data) = Arc::try_unwrap(tracer) + .expect("There is must be only one reference") + .into_inner() + .expect("Poisoned RwLock") .into_traces(); Ok(TracedCall { @@ -117,18 +116,15 @@ async fn trace_trx<'a>( steps: u64, trace_config: &TraceConfig, ) -> Result { - let tracer = Arc::new(RwLock::new(Some(Tracer::new( - trace_config.enable_return_data, - )))); + let tracer = Arc::new(RwLock::new(Tracer::new(trace_config.enable_return_data))); let emulation_result = emulate_trx(tx_params, storage, chain_id, steps, Some(tracer.clone())).await?; - let (vm_trace, full_trace_data) = tracer - .write() - .expect("lock acquire should be successful") - .take() - .expect("Option should not be empty") + let (vm_trace, full_trace_data) = Arc::try_unwrap(tracer) + .expect("There is must be only one reference") + .into_inner() + .expect("Poisoned RwLock") .into_traces(); Ok(TracedCall { diff --git a/evm_loader/program/src/evm/mod.rs b/evm_loader/program/src/evm/mod.rs index 437148b99..5be048821 100644 --- a/evm_loader/program/src/evm/mod.rs +++ b/evm_loader/program/src/evm/mod.rs @@ -39,14 +39,14 @@ macro_rules! tracing_event { ($self:ident, $x:expr) => { #[cfg(feature = "tracing")] if let Some(tracer) = &$self.tracer { - tracer.write().unwrap().as_mut().unwrap().event($x); + tracer.write().expect("Poisoned RwLock").event($x); } }; ($self:ident, $condition:expr, $x:expr) => { #[cfg(feature = "tracing")] if let Some(tracer) = &$self.tracer { if $condition { - tracer.write().unwrap().as_mut().unwrap().event($x); + tracer.write().expect("Poisoned RwLock").event($x); } } }; @@ -56,15 +56,14 @@ macro_rules! trace_end_step { ($self:ident, $return_data_vec:expr) => { #[cfg(feature = "tracing")] if let Some(tracer) = &$self.tracer { - let mut tracer = tracer.write().unwrap(); - let tracer = tracer.as_mut().unwrap(); - if tracer.enable_return_data() { - tracer.event(crate::evm::tracing::Event::EndStep { + let mut tracer_write_guard = tracer.write().expect("Poisoned RwLock"); + if tracer_write_guard.enable_return_data() { + tracer_write_guard.event(crate::evm::tracing::Event::EndStep { gas_used: 0_u64, return_data: $return_data_vec, }) } else { - tracer.event(crate::evm::tracing::Event::EndStep { + tracer_write_guard.event(crate::evm::tracing::Event::EndStep { gas_used: 0_u64, return_data: None, }) diff --git a/evm_loader/program/src/evm/tracing/event_listener/listener_tracer.rs b/evm_loader/program/src/evm/tracing/event_listener/listener_tracer.rs index 9788927e9..23b067396 100644 --- a/evm_loader/program/src/evm/tracing/event_listener/listener_tracer.rs +++ b/evm_loader/program/src/evm/tracing/event_listener/listener_tracer.rs @@ -23,7 +23,10 @@ impl ListenerTracer for Tracer { } fn end_step(&mut self, return_data: Option>) { - let data = self.data.last_mut().expect("data was pushed in begin_step"); + let data = self + .data + .last_mut() + .expect("No data were pushed in `begin_step`"); data.return_data = return_data; if let Some((index, value)) = self.vm.step_diff().storage_access { data.storage.insert(index, value); diff --git a/evm_loader/program/src/evm/tracing/event_listener/trace.rs b/evm_loader/program/src/evm/tracing/event_listener/trace.rs index f2abdad96..9b68c6372 100644 --- a/evm_loader/program/src/evm/tracing/event_listener/trace.rs +++ b/evm_loader/program/src/evm/tracing/event_listener/trace.rs @@ -69,6 +69,7 @@ pub struct VMTrace { } // OpenEthereum tracer ethcore/trace/src/executive_tracer.rs +#[derive(Debug)] #[allow(clippy::module_name_repetitions)] pub struct TraceData { pub mem_written: Option<(usize, usize)>, @@ -84,6 +85,7 @@ pub struct FullTraceData { } /// Simple VM tracer. Traces all operations. +#[derive(Debug)] pub struct ExecutiveVMTracer { data: VMTrace, pub depth: usize, diff --git a/evm_loader/program/src/evm/tracing/event_listener/tracer.rs b/evm_loader/program/src/evm/tracing/event_listener/tracer.rs index 70da11af1..153e33fc9 100644 --- a/evm_loader/program/src/evm/tracing/event_listener/tracer.rs +++ b/evm_loader/program/src/evm/tracing/event_listener/tracer.rs @@ -4,8 +4,9 @@ use crate::evm::tracing::event_listener::trace::{FullTraceData, VMTrace, VMTrace use super::vm_tracer::VmTracer; -pub type TracerType = Option>>>; +pub type TracerType = Option>>; +#[derive(Debug)] pub struct Tracer { pub vm: VmTracer, pub data: Vec, diff --git a/evm_loader/program/src/evm/tracing/event_listener/vm_tracer.rs b/evm_loader/program/src/evm/tracing/event_listener/vm_tracer.rs index 8374e7426..bb2861411 100644 --- a/evm_loader/program/src/evm/tracing/event_listener/vm_tracer.rs +++ b/evm_loader/program/src/evm/tracing/event_listener/vm_tracer.rs @@ -9,6 +9,7 @@ pub struct StepDiff { pub stack_push: Vec<[u8; 32]>, } +#[derive(Debug)] pub struct VmTracer { pub tracer: ExecutiveVMTracer, step_diff: Vec, From 98b7a5b5559f7bf86f5900bd4f7a6675d197ca7a Mon Sep 17 00:00:00 2001 From: Denis Date: Wed, 16 Aug 2023 17:45:18 +0300 Subject: [PATCH 005/318] NDEV-1881: Use non blocking writer for logs (#165) --- evm_loader/Cargo.lock | 12 ++++++++++++ evm_loader/api/Cargo.toml | 1 + evm_loader/api/src/main.rs | 9 +++++++-- evm_loader/lib/src/config.rs | 2 +- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 31aa93a99..aff050235 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -2197,6 +2197,7 @@ dependencies = [ "tokio", "tower", "tracing", + "tracing-appender", "tracing-subscriber", ] @@ -4802,6 +4803,17 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-appender" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d48f71a791638519505cefafe162606f706c25592e4bde4d97600c0195312e" +dependencies = [ + "crossbeam-channel", + "time 0.3.20", + "tracing-subscriber", +] + [[package]] name = "tracing-attributes" version = "0.1.23" diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index d8afc17f3..2c77c82e3 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -15,6 +15,7 @@ ethnum = { version = "1", default_features = false, features = ["serde"] } tokio = { version = "1", features = ["full"] } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } +tracing-appender = "0.2.2" axum = "0.6" tower = { version = "0.4", features = ["make"] } neon-lib = { path = "../lib" } diff --git a/evm_loader/api/src/main.rs b/evm_loader/api/src/main.rs index 103ad11da..0e5aea434 100644 --- a/evm_loader/api/src/main.rs +++ b/evm_loader/api/src/main.rs @@ -14,6 +14,7 @@ pub use neon_lib::errors; pub use neon_lib::rpc; pub use neon_lib::syscall_stubs; pub use neon_lib::types; +use tracing_appender::non_blocking::NonBlockingBuilder; use std::sync::Arc; use std::{env, net::SocketAddr, str::FromStr}; @@ -30,11 +31,15 @@ async fn main() -> NeonApiResult<()> { let options = api_options::parse(); // initialize tracing - tracing_subscriber::fmt::init(); + let (non_blocking, _guard) = NonBlockingBuilder::default() + .lossy(false) + .finish(std::io::stdout()); + + tracing_subscriber::fmt().with_writer(non_blocking).init(); let api_config = config::load_api_config_from_enviroment(); - let config = config::create_from_api_comnfig(&api_config)?; + let config = config::create_from_api_config(&api_config)?; let state: NeonApiState = Arc::new(api_server::state::State::new(config)); diff --git a/evm_loader/lib/src/config.rs b/evm_loader/lib/src/config.rs index 0518dca68..be4f0dd33 100644 --- a/evm_loader/lib/src/config.rs +++ b/evm_loader/lib/src/config.rs @@ -26,7 +26,7 @@ pub struct Config { // } /// # Errors -pub fn create_from_api_comnfig(api_config: &APIOptions) -> Result { +pub fn create_from_api_config(api_config: &APIOptions) -> Result { let solana_cli_config: SolanaConfig = if let Some(path) = api_config.solana_cli_config_path.clone() { solana_cli_config::Config::load(path.as_str()).unwrap_or_default() From 9864c35a05df1824c2589fd4ff205dafe879febe Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Thu, 24 Aug 2023 15:55:03 +0300 Subject: [PATCH 006/318] Fix performance with precompile contract (#172) --- evm_loader/program/src/evm/mod.rs | 99 ++++++++++---------- evm_loader/program/src/evm/precompile/mod.rs | 30 +++--- 2 files changed, 60 insertions(+), 69 deletions(-) diff --git a/evm_loader/program/src/evm/mod.rs b/evm_loader/program/src/evm/mod.rs index 5be048821..e03058a00 100644 --- a/evm_loader/program/src/evm/mod.rs +++ b/evm_loader/program/src/evm/mod.rs @@ -9,8 +9,6 @@ use serde::{Deserialize, Serialize}; use solana_program::log::sol_log_data; pub use buffer::Buffer; -pub use precompile::is_precompile_address; -pub use precompile::precompile; #[cfg(feature = "tracing")] use crate::evm::tracing::event_listener::tracer::TracerType; @@ -18,7 +16,7 @@ use crate::evm::tracing::event_listener::tracer::TracerType; use crate::evm::tracing::EventListener; use crate::{ error::{build_revert_message, Error, Result}, - evm::opcode::Action, + evm::{opcode::Action, precompile::is_precompile_address}, types::{Address, Transaction}, }; @@ -342,57 +340,56 @@ impl Machine { } ); - let status = loop { - if is_precompile_address(&self.context.contract) { - let value = precompile(&self.context.contract, &self.call_data).unwrap_or_default(); + let status = if is_precompile_address(&self.context.contract) { + let value = Self::precompile(&self.context.contract, &self.call_data).unwrap(); + backend.commit_snapshot(); - backend.commit_snapshot(); - - break ExitStatus::Return(value); - } - - step += 1; - if step > step_limit { - break ExitStatus::StepLimit; - } - - let opcode = self.execution_code.get_or_default(self.pc); - - tracing_event!( - self, - tracing::Event::BeginStep { - opcode, - pc: self.pc, - stack: self.stack.to_vec(), - memory: self.memory.to_vec() + ExitStatus::Return(value) + } else { + loop { + step += 1; + if step > step_limit { + break ExitStatus::StepLimit; } - ); - - // SAFETY: OPCODES.len() == 256, opcode <= 255 - let opcode_fn = unsafe { Self::OPCODES.get_unchecked(opcode as usize) }; - let opcode_result = match opcode_fn(self, backend) { - Ok(result) => result, - Err(e) => { - let message = build_revert_message(&e.to_string()); - self.opcode_revert_impl(Buffer::from_slice(&message), backend)? - } - }; - - trace_end_step!(self, opcode_result != Action::Noop; match &opcode_result { - Action::Return(value) | Action::Revert(value) => Some(value.clone()), - _ => None, - }); - - match opcode_result { - Action::Continue => self.pc += 1, - Action::Jump(target) => self.pc = target, - Action::Stop => break ExitStatus::Stop, - Action::Return(value) => break ExitStatus::Return(value), - Action::Revert(value) => break ExitStatus::Revert(value), - Action::Suicide => break ExitStatus::Suicide, - Action::Noop => {} - }; + let opcode = self.execution_code.get_or_default(self.pc); + + tracing_event!( + self, + tracing::Event::BeginStep { + opcode, + pc: self.pc, + stack: self.stack.to_vec(), + memory: self.memory.to_vec() + } + ); + + // SAFETY: OPCODES.len() == 256, opcode <= 255 + let opcode_fn = unsafe { Self::OPCODES.get_unchecked(opcode as usize) }; + + let opcode_result = match opcode_fn(self, backend) { + Ok(result) => result, + Err(e) => { + let message = build_revert_message(&e.to_string()); + self.opcode_revert_impl(Buffer::from_slice(&message), backend)? + } + }; + + trace_end_step!(self, opcode_result != Action::Noop; match &opcode_result { + Action::Return(value) | Action::Revert(value) => Some(value.clone()), + _ => None, + }); + + match opcode_result { + Action::Continue => self.pc += 1, + Action::Jump(target) => self.pc = target, + Action::Stop => break ExitStatus::Stop, + Action::Return(value) => break ExitStatus::Return(value), + Action::Revert(value) => break ExitStatus::Revert(value), + Action::Suicide => break ExitStatus::Suicide, + Action::Noop => {} + }; + } }; tracing_event!( diff --git a/evm_loader/program/src/evm/precompile/mod.rs b/evm_loader/program/src/evm/precompile/mod.rs index 511bb903f..16bb5666c 100644 --- a/evm_loader/program/src/evm/precompile/mod.rs +++ b/evm_loader/program/src/evm/precompile/mod.rs @@ -56,26 +56,20 @@ pub fn is_precompile_address(address: &Address) -> bool { || *address == SYSTEM_ACCOUNT_BLAKE2F } -/// Run precompile code -#[must_use] -pub fn precompile(address: &Address, data: &[u8]) -> Option> { - match *address { - SYSTEM_ACCOUNT_ECRECOVER => Some(ecrecover::ecrecover(data)), - SYSTEM_ACCOUNT_SHA_256 => Some(sha256::sha256(data)), - SYSTEM_ACCOUNT_RIPEMD160 => Some(ripemd160::ripemd160(data)), - SYSTEM_ACCOUNT_DATACOPY => Some(datacopy::datacopy(data)), - SYSTEM_ACCOUNT_BIGMODEXP => Some(big_mod_exp::big_mod_exp(data)), - SYSTEM_ACCOUNT_BN256_ADD => Some(bn256::bn256_add(data)), - SYSTEM_ACCOUNT_BN256_SCALAR_MUL => Some(bn256::bn256_scalar_mul(data)), - SYSTEM_ACCOUNT_BN256_PAIRING => Some(bn256::bn256_pairing(data)), - SYSTEM_ACCOUNT_BLAKE2F => Some(blake2_f::blake2_f(data)), - _ => None, - } -} - impl Machine { #[must_use] pub fn precompile(address: &Address, data: &[u8]) -> Option> { - precompile(address, data) + match *address { + SYSTEM_ACCOUNT_ECRECOVER => Some(ecrecover::ecrecover(data)), + SYSTEM_ACCOUNT_SHA_256 => Some(sha256::sha256(data)), + SYSTEM_ACCOUNT_RIPEMD160 => Some(ripemd160::ripemd160(data)), + SYSTEM_ACCOUNT_DATACOPY => Some(datacopy::datacopy(data)), + SYSTEM_ACCOUNT_BIGMODEXP => Some(big_mod_exp::big_mod_exp(data)), + SYSTEM_ACCOUNT_BN256_ADD => Some(bn256::bn256_add(data)), + SYSTEM_ACCOUNT_BN256_SCALAR_MUL => Some(bn256::bn256_scalar_mul(data)), + SYSTEM_ACCOUNT_BN256_PAIRING => Some(bn256::bn256_pairing(data)), + SYSTEM_ACCOUNT_BLAKE2F => Some(blake2_f::blake2_f(data)), + _ => None, + } } } From ce1e7320bd5332344521f274d92f1c225f75f6b4 Mon Sep 17 00:00:00 2001 From: Kristina Nikolaeva <112946046+kristinaNikolaevaa@users.noreply.github.com> Date: Fri, 25 Aug 2023 10:23:08 +0300 Subject: [PATCH 007/318] Added own operator for each thread in tests (#171) * moved operators account creating to tests * Update conftest.py * added more operators * fix path * deleted unused files * Update Dockerfile * back create-test-account.sh * Update Dockerfile * Create neon_token_keypair.json * fix * Update Dockerfile --- Dockerfile | 10 +-- evm_loader/create-test-accounts.sh | 0 evm_loader/deploy-test.sh | 2 - evm_loader/docker-compose-ci.yml | 6 +- .../id.json} | 0 evm_loader/operator-keypairs/id10.json | 1 + evm_loader/operator-keypairs/id11.json | 1 + evm_loader/operator-keypairs/id12.json | 1 + evm_loader/operator-keypairs/id13.json | 1 + evm_loader/operator-keypairs/id14.json | 1 + evm_loader/operator-keypairs/id15.json | 1 + evm_loader/operator-keypairs/id16.json | 1 + evm_loader/operator-keypairs/id17.json | 1 + evm_loader/operator-keypairs/id18.json | 1 + evm_loader/operator-keypairs/id19.json | 1 + .../id2.json} | 0 evm_loader/operator-keypairs/id20.json | 1 + evm_loader/operator-keypairs/id21.json | 1 + evm_loader/operator-keypairs/id22.json | 1 + evm_loader/operator-keypairs/id23.json | 1 + evm_loader/operator-keypairs/id24.json | 1 + evm_loader/operator-keypairs/id25.json | 1 + evm_loader/operator-keypairs/id26.json | 1 + evm_loader/operator-keypairs/id27.json | 1 + evm_loader/operator-keypairs/id28.json | 1 + evm_loader/operator-keypairs/id29.json | 1 + evm_loader/operator-keypairs/id3.json | 1 + evm_loader/operator-keypairs/id30.json | 1 + evm_loader/operator-keypairs/id4.json | 1 + evm_loader/operator-keypairs/id5.json | 1 + evm_loader/operator-keypairs/id6.json | 1 + evm_loader/operator-keypairs/id7.json | 1 + evm_loader/operator-keypairs/id8.json | 1 + evm_loader/operator-keypairs/id9.json | 1 + evm_loader/tests/README.md | 2 +- evm_loader/tests/conftest.py | 69 +++++++++++-------- evm_loader/tests/solana_utils.py | 42 +++-------- 37 files changed, 85 insertions(+), 74 deletions(-) mode change 100755 => 100644 evm_loader/create-test-accounts.sh rename evm_loader/{operator1-keypair.json => operator-keypairs/id.json} (100%) create mode 100644 evm_loader/operator-keypairs/id10.json create mode 100644 evm_loader/operator-keypairs/id11.json create mode 100644 evm_loader/operator-keypairs/id12.json create mode 100644 evm_loader/operator-keypairs/id13.json create mode 100644 evm_loader/operator-keypairs/id14.json create mode 100644 evm_loader/operator-keypairs/id15.json create mode 100644 evm_loader/operator-keypairs/id16.json create mode 100644 evm_loader/operator-keypairs/id17.json create mode 100644 evm_loader/operator-keypairs/id18.json create mode 100644 evm_loader/operator-keypairs/id19.json rename evm_loader/{operator2-keypair.json => operator-keypairs/id2.json} (100%) create mode 100644 evm_loader/operator-keypairs/id20.json create mode 100644 evm_loader/operator-keypairs/id21.json create mode 100644 evm_loader/operator-keypairs/id22.json create mode 100644 evm_loader/operator-keypairs/id23.json create mode 100644 evm_loader/operator-keypairs/id24.json create mode 100644 evm_loader/operator-keypairs/id25.json create mode 100644 evm_loader/operator-keypairs/id26.json create mode 100644 evm_loader/operator-keypairs/id27.json create mode 100644 evm_loader/operator-keypairs/id28.json create mode 100644 evm_loader/operator-keypairs/id29.json create mode 100644 evm_loader/operator-keypairs/id3.json create mode 100644 evm_loader/operator-keypairs/id30.json create mode 100644 evm_loader/operator-keypairs/id4.json create mode 100644 evm_loader/operator-keypairs/id5.json create mode 100644 evm_loader/operator-keypairs/id6.json create mode 100644 evm_loader/operator-keypairs/id7.json create mode 100644 evm_loader/operator-keypairs/id8.json create mode 100644 evm_loader/operator-keypairs/id9.json diff --git a/Dockerfile b/Dockerfile index 27d90adfe..84c753576 100644 --- a/Dockerfile +++ b/Dockerfile @@ -82,17 +82,17 @@ COPY --from=contracts /opt/ /opt/solidity/ COPY --from=contracts /usr/bin/solc /usr/bin/solc COPY evm_loader/wait-for-solana.sh \ evm_loader/wait-for-neon.sh \ - evm_loader/create-test-accounts.sh \ evm_loader/deploy-evm.sh \ evm_loader/deploy-test.sh \ + evm_loader/create-test-accounts.sh \ evm_loader/evm_loader-keypair.json \ /opt/ -COPY evm_loader/keys/ /opt/keys +COPY evm_loader/operator-keypairs/ /opt/operator-keypairs COPY evm_loader/tests /opt/tests -COPY evm_loader/operator1-keypair.json /root/.config/solana/id.json -COPY evm_loader/operator2-keypair.json /root/.config/solana/id2.json - +COPY evm_loader/operator-keypairs/id.json /root/.config/solana/id.json +COPY evm_loader/operator-keypairs/id2.json /root/.config/solana/id2.json +COPY evm_loader/keys/ /opt/keys ENV CONTRACTS_DIR=/opt/solidity/ ENV PATH=/opt/solana/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt diff --git a/evm_loader/create-test-accounts.sh b/evm_loader/create-test-accounts.sh old mode 100755 new mode 100644 diff --git a/evm_loader/deploy-test.sh b/evm_loader/deploy-test.sh index 07fa8f275..75594e9af 100755 --- a/evm_loader/deploy-test.sh +++ b/evm_loader/deploy-test.sh @@ -18,8 +18,6 @@ for key, value in json.loads(sys.argv[1])['value'].items(): print(f'{key}={value}') " "$ELF_PARAMS") -echo "Create test operator accounts" -create-test-accounts.sh 2 py.test -n 6 tests/ diff --git a/evm_loader/docker-compose-ci.yml b/evm_loader/docker-compose-ci.yml index 2638ed777..68c06de89 100644 --- a/evm_loader/docker-compose-ci.yml +++ b/evm_loader/docker-compose-ci.yml @@ -35,13 +35,11 @@ services: NEON_DB_INDEXER_DATABASE: indexer NEON_DB_INDEXER_USER: postgres NEON_DB_INDEXER_PASSWORD: "" - KEYPAIR: /opt/id.json - FEEPAIR: /opt/id.json + KEYPAIR: /opt/operator-keypairs/id.json + FEEPAIR: /opt/operator-keypairs/id.json image: ${EVM_LOADER_IMAGE} ports: - 8085 - volumes: - - ./files/id.json:/opt/id.json networks: - net diff --git a/evm_loader/operator1-keypair.json b/evm_loader/operator-keypairs/id.json similarity index 100% rename from evm_loader/operator1-keypair.json rename to evm_loader/operator-keypairs/id.json diff --git a/evm_loader/operator-keypairs/id10.json b/evm_loader/operator-keypairs/id10.json new file mode 100644 index 000000000..0775610ce --- /dev/null +++ b/evm_loader/operator-keypairs/id10.json @@ -0,0 +1 @@ +[95,1,219,168,183,165,35,48,232,59,7,206,250,251,243,138,175,212,58,154,252,147,193,16,240,56,129,24,104,220,21,244,70,237,248,21,84,35,91,157,114,197,241,253,93,33,93,230,14,255,229,131,73,153,27,16,86,172,34,220,16,128,14,26] \ No newline at end of file diff --git a/evm_loader/operator-keypairs/id11.json b/evm_loader/operator-keypairs/id11.json new file mode 100644 index 000000000..db7143029 --- /dev/null +++ b/evm_loader/operator-keypairs/id11.json @@ -0,0 +1 @@ +[112,233,194,170,175,217,98,186,160,118,143,249,88,40,179,77,222,62,121,149,205,155,152,1,34,243,188,44,66,231,63,202,143,44,91,212,211,86,255,54,80,56,164,192,211,49,40,167,211,153,130,207,41,220,90,64,169,45,26,169,42,202,231,252] \ No newline at end of file diff --git a/evm_loader/operator-keypairs/id12.json b/evm_loader/operator-keypairs/id12.json new file mode 100644 index 000000000..3cfb114dc --- /dev/null +++ b/evm_loader/operator-keypairs/id12.json @@ -0,0 +1 @@ +[107,242,59,236,113,145,60,13,84,146,102,174,36,95,255,207,104,129,118,70,114,139,210,54,17,195,176,206,202,153,82,111,25,231,254,200,204,102,17,163,119,42,14,188,149,225,220,221,195,14,163,251,62,228,171,180,124,174,161,152,231,162,221,54] \ No newline at end of file diff --git a/evm_loader/operator-keypairs/id13.json b/evm_loader/operator-keypairs/id13.json new file mode 100644 index 000000000..e5e633ee3 --- /dev/null +++ b/evm_loader/operator-keypairs/id13.json @@ -0,0 +1 @@ +[132,30,178,226,98,41,184,97,30,124,214,218,107,138,88,82,206,12,27,217,25,6,146,118,146,174,17,129,255,96,33,56,204,58,207,78,57,180,19,42,180,42,245,237,110,83,156,150,192,15,157,91,246,49,103,146,168,79,122,156,136,146,247,152] \ No newline at end of file diff --git a/evm_loader/operator-keypairs/id14.json b/evm_loader/operator-keypairs/id14.json new file mode 100644 index 000000000..3258026f3 --- /dev/null +++ b/evm_loader/operator-keypairs/id14.json @@ -0,0 +1 @@ +[77,155,208,78,141,49,104,72,43,252,108,43,240,125,166,156,235,146,195,221,21,235,48,39,224,133,233,174,110,10,211,154,123,240,134,8,166,118,208,116,229,35,39,53,203,206,97,95,22,107,236,62,70,200,191,63,221,34,154,91,159,153,180,171] \ No newline at end of file diff --git a/evm_loader/operator-keypairs/id15.json b/evm_loader/operator-keypairs/id15.json new file mode 100644 index 000000000..317b10c65 --- /dev/null +++ b/evm_loader/operator-keypairs/id15.json @@ -0,0 +1 @@ +[176,43,81,75,52,27,223,223,223,150,148,199,16,151,195,121,143,174,242,189,90,208,164,198,92,28,77,104,72,230,11,154,212,64,129,103,42,57,174,119,63,101,167,173,184,97,146,208,207,208,81,239,29,214,66,101,101,151,247,130,197,17,172,170] \ No newline at end of file diff --git a/evm_loader/operator-keypairs/id16.json b/evm_loader/operator-keypairs/id16.json new file mode 100644 index 000000000..a2ea6fa61 --- /dev/null +++ b/evm_loader/operator-keypairs/id16.json @@ -0,0 +1 @@ +[56,132,45,132,252,89,229,88,99,111,37,90,53,175,128,227,57,228,18,166,56,5,168,23,33,127,37,69,154,150,67,213,227,9,242,48,173,228,249,65,55,107,84,219,87,138,241,192,218,29,149,67,43,239,9,132,93,209,218,167,27,138,112,46] \ No newline at end of file diff --git a/evm_loader/operator-keypairs/id17.json b/evm_loader/operator-keypairs/id17.json new file mode 100644 index 000000000..5cbbbd54d --- /dev/null +++ b/evm_loader/operator-keypairs/id17.json @@ -0,0 +1 @@ +[169,132,11,32,251,137,85,119,180,62,4,36,213,240,247,29,61,194,252,19,134,98,188,82,22,213,206,195,39,133,36,162,202,14,212,69,151,114,40,66,173,213,100,145,235,70,34,247,101,166,227,86,18,81,56,17,58,103,152,200,117,163,88,236] \ No newline at end of file diff --git a/evm_loader/operator-keypairs/id18.json b/evm_loader/operator-keypairs/id18.json new file mode 100644 index 000000000..5a2ad7abc --- /dev/null +++ b/evm_loader/operator-keypairs/id18.json @@ -0,0 +1 @@ +[34,136,232,16,199,6,212,178,9,245,202,238,151,70,70,205,173,92,116,43,176,222,250,193,7,242,79,227,3,252,57,47,171,52,75,200,195,215,71,197,31,185,128,5,62,168,237,61,5,25,229,26,19,201,190,9,149,80,104,95,157,123,207,40] \ No newline at end of file diff --git a/evm_loader/operator-keypairs/id19.json b/evm_loader/operator-keypairs/id19.json new file mode 100644 index 000000000..716b611d6 --- /dev/null +++ b/evm_loader/operator-keypairs/id19.json @@ -0,0 +1 @@ +[107,48,148,246,46,55,52,252,132,177,71,135,119,118,187,16,236,80,237,198,239,54,112,107,225,26,36,200,242,63,40,71,143,117,14,174,182,27,199,155,93,167,196,216,69,150,100,195,216,48,222,143,240,185,186,37,202,137,179,232,239,26,85,242] \ No newline at end of file diff --git a/evm_loader/operator2-keypair.json b/evm_loader/operator-keypairs/id2.json similarity index 100% rename from evm_loader/operator2-keypair.json rename to evm_loader/operator-keypairs/id2.json diff --git a/evm_loader/operator-keypairs/id20.json b/evm_loader/operator-keypairs/id20.json new file mode 100644 index 000000000..03a27c45e --- /dev/null +++ b/evm_loader/operator-keypairs/id20.json @@ -0,0 +1 @@ +[203,226,8,46,184,170,110,207,167,123,46,136,82,48,44,123,212,127,198,109,113,6,103,190,9,144,89,120,215,45,75,17,134,73,9,238,232,115,234,164,179,96,197,67,31,175,86,222,149,202,209,164,83,170,133,179,189,178,99,158,15,3,152,135] \ No newline at end of file diff --git a/evm_loader/operator-keypairs/id21.json b/evm_loader/operator-keypairs/id21.json new file mode 100644 index 000000000..caa4fb733 --- /dev/null +++ b/evm_loader/operator-keypairs/id21.json @@ -0,0 +1 @@ +[218,78,39,37,233,34,133,207,6,61,140,213,98,27,8,7,255,50,100,179,83,154,114,120,52,199,178,29,32,131,193,9,46,69,220,188,192,48,86,70,174,193,58,32,171,172,54,169,134,56,245,54,239,253,235,32,155,211,137,90,163,61,54,57] \ No newline at end of file diff --git a/evm_loader/operator-keypairs/id22.json b/evm_loader/operator-keypairs/id22.json new file mode 100644 index 000000000..7966c4ba4 --- /dev/null +++ b/evm_loader/operator-keypairs/id22.json @@ -0,0 +1 @@ +[213,38,17,156,63,219,208,33,176,13,185,208,204,212,179,20,63,74,116,6,104,176,68,242,100,10,76,138,124,95,99,168,91,253,251,27,103,97,112,214,38,187,136,19,100,149,58,106,184,17,85,214,7,150,172,139,155,133,93,93,168,107,139,174] \ No newline at end of file diff --git a/evm_loader/operator-keypairs/id23.json b/evm_loader/operator-keypairs/id23.json new file mode 100644 index 000000000..e2c659a57 --- /dev/null +++ b/evm_loader/operator-keypairs/id23.json @@ -0,0 +1 @@ +[161,138,142,31,77,141,153,110,193,211,60,52,240,89,17,162,42,125,158,78,243,214,203,144,85,66,34,231,222,87,106,54,184,10,234,92,109,70,63,141,23,221,150,4,181,90,234,216,132,7,213,115,220,202,207,31,31,191,66,27,76,106,139,28] \ No newline at end of file diff --git a/evm_loader/operator-keypairs/id24.json b/evm_loader/operator-keypairs/id24.json new file mode 100644 index 000000000..ab53a2b48 --- /dev/null +++ b/evm_loader/operator-keypairs/id24.json @@ -0,0 +1 @@ +[111,225,67,67,201,129,87,214,46,150,197,209,142,102,243,6,197,103,130,19,12,11,205,90,228,216,232,212,42,87,217,246,20,32,169,144,96,175,129,11,93,237,7,215,62,60,254,34,29,15,133,117,199,162,8,140,144,35,233,179,139,198,54,30] \ No newline at end of file diff --git a/evm_loader/operator-keypairs/id25.json b/evm_loader/operator-keypairs/id25.json new file mode 100644 index 000000000..c3cd09b2a --- /dev/null +++ b/evm_loader/operator-keypairs/id25.json @@ -0,0 +1 @@ +[124,147,121,70,22,245,195,2,113,226,67,159,168,33,247,202,149,42,5,18,192,26,192,41,21,255,15,1,115,38,184,182,28,114,114,195,60,79,241,252,192,204,205,176,152,170,117,102,255,74,145,69,85,136,64,214,177,134,255,221,184,119,141,125] \ No newline at end of file diff --git a/evm_loader/operator-keypairs/id26.json b/evm_loader/operator-keypairs/id26.json new file mode 100644 index 000000000..11980bcaa --- /dev/null +++ b/evm_loader/operator-keypairs/id26.json @@ -0,0 +1 @@ +[194,43,141,149,241,214,135,212,243,123,229,238,68,168,5,2,148,253,171,107,40,251,133,240,237,248,82,44,45,252,177,157,9,157,56,52,149,119,152,127,172,5,132,184,12,65,237,196,211,249,93,75,246,23,49,187,1,196,138,243,254,148,127,200] \ No newline at end of file diff --git a/evm_loader/operator-keypairs/id27.json b/evm_loader/operator-keypairs/id27.json new file mode 100644 index 000000000..00c30dea2 --- /dev/null +++ b/evm_loader/operator-keypairs/id27.json @@ -0,0 +1 @@ +[208,83,61,173,206,206,193,114,39,85,114,190,81,55,97,76,94,156,47,248,193,163,230,202,176,121,89,43,16,210,146,36,208,251,160,86,224,180,79,140,119,14,118,76,60,79,81,96,160,123,179,88,201,27,173,141,126,239,109,213,242,106,36,246] \ No newline at end of file diff --git a/evm_loader/operator-keypairs/id28.json b/evm_loader/operator-keypairs/id28.json new file mode 100644 index 000000000..4b858ba33 --- /dev/null +++ b/evm_loader/operator-keypairs/id28.json @@ -0,0 +1 @@ +[209,78,176,59,205,21,225,147,100,16,206,202,223,36,96,43,85,159,238,98,244,52,0,49,98,111,122,225,225,165,9,112,104,103,35,237,229,14,253,80,210,177,222,83,166,131,106,170,212,72,208,227,125,135,92,255,38,250,183,162,139,32,85,50] \ No newline at end of file diff --git a/evm_loader/operator-keypairs/id29.json b/evm_loader/operator-keypairs/id29.json new file mode 100644 index 000000000..454b40b63 --- /dev/null +++ b/evm_loader/operator-keypairs/id29.json @@ -0,0 +1 @@ +[139,25,69,250,8,210,132,135,49,210,33,168,172,48,73,239,226,151,2,49,128,127,136,222,160,209,112,172,83,153,57,59,231,21,48,207,152,236,233,187,223,100,82,93,7,113,26,194,124,70,245,140,6,215,63,170,178,46,130,201,93,40,215,178] \ No newline at end of file diff --git a/evm_loader/operator-keypairs/id3.json b/evm_loader/operator-keypairs/id3.json new file mode 100644 index 000000000..7bc96cdf7 --- /dev/null +++ b/evm_loader/operator-keypairs/id3.json @@ -0,0 +1 @@ +[109,212,150,39,229,176,85,103,100,217,115,40,197,125,185,154,137,194,7,69,141,239,74,113,237,187,26,120,169,5,255,32,35,79,159,50,228,49,216,5,51,156,105,212,248,146,245,190,201,70,233,200,237,253,215,78,68,113,248,0,238,15,136,200] \ No newline at end of file diff --git a/evm_loader/operator-keypairs/id30.json b/evm_loader/operator-keypairs/id30.json new file mode 100644 index 000000000..b6b4a9b64 --- /dev/null +++ b/evm_loader/operator-keypairs/id30.json @@ -0,0 +1 @@ +[164,184,180,94,178,30,255,212,198,57,93,119,61,202,55,97,47,134,31,115,120,201,199,32,163,108,202,131,121,135,128,6,68,231,110,177,230,42,56,26,247,172,232,205,110,76,106,16,153,106,234,56,11,247,17,237,241,11,56,21,145,232,254,153] \ No newline at end of file diff --git a/evm_loader/operator-keypairs/id4.json b/evm_loader/operator-keypairs/id4.json new file mode 100644 index 000000000..f0ca8465a --- /dev/null +++ b/evm_loader/operator-keypairs/id4.json @@ -0,0 +1 @@ +[214,210,14,130,12,222,73,66,181,175,176,156,48,43,71,4,216,168,159,87,124,129,219,255,7,252,25,161,46,177,45,113,108,56,97,99,254,82,6,60,29,65,233,96,140,158,29,212,193,138,51,31,126,138,226,116,105,127,95,121,156,23,55,54] \ No newline at end of file diff --git a/evm_loader/operator-keypairs/id5.json b/evm_loader/operator-keypairs/id5.json new file mode 100644 index 000000000..1a5e67907 --- /dev/null +++ b/evm_loader/operator-keypairs/id5.json @@ -0,0 +1 @@ +[135,36,157,212,37,148,54,141,6,153,179,125,174,108,39,176,152,84,179,2,79,124,113,176,10,83,101,69,165,219,43,89,7,50,172,103,235,215,62,192,98,108,223,67,30,114,241,40,45,61,189,107,162,9,86,31,11,124,184,245,39,12,101,13] \ No newline at end of file diff --git a/evm_loader/operator-keypairs/id6.json b/evm_loader/operator-keypairs/id6.json new file mode 100644 index 000000000..e367a5373 --- /dev/null +++ b/evm_loader/operator-keypairs/id6.json @@ -0,0 +1 @@ +[245,253,29,158,248,242,248,20,31,201,243,72,241,50,136,180,229,63,143,99,92,29,230,5,181,107,230,147,253,103,22,247,1,192,248,239,196,211,107,121,216,2,30,108,163,95,239,105,245,93,161,171,252,153,27,40,132,14,136,73,52,195,251,158] \ No newline at end of file diff --git a/evm_loader/operator-keypairs/id7.json b/evm_loader/operator-keypairs/id7.json new file mode 100644 index 000000000..088191ba9 --- /dev/null +++ b/evm_loader/operator-keypairs/id7.json @@ -0,0 +1 @@ +[103,137,235,222,211,158,252,227,63,199,231,174,155,23,246,93,31,194,94,222,156,0,159,205,93,110,243,4,179,21,145,13,236,212,22,139,247,96,23,122,167,37,106,151,101,126,240,202,104,15,176,243,57,143,103,132,64,211,83,237,3,68,189,154] \ No newline at end of file diff --git a/evm_loader/operator-keypairs/id8.json b/evm_loader/operator-keypairs/id8.json new file mode 100644 index 000000000..515cd77c5 --- /dev/null +++ b/evm_loader/operator-keypairs/id8.json @@ -0,0 +1 @@ +[43,222,228,254,6,34,211,192,249,60,124,254,19,117,183,192,163,79,160,118,73,194,91,40,166,32,139,101,161,204,226,199,202,125,95,169,241,101,72,248,194,7,102,135,184,165,73,207,166,48,108,180,62,205,193,52,91,86,120,152,102,112,62,105] \ No newline at end of file diff --git a/evm_loader/operator-keypairs/id9.json b/evm_loader/operator-keypairs/id9.json new file mode 100644 index 000000000..02f112529 --- /dev/null +++ b/evm_loader/operator-keypairs/id9.json @@ -0,0 +1 @@ +[76,252,69,52,51,62,9,220,165,183,52,47,149,238,49,198,68,226,22,251,245,70,58,59,205,49,212,77,31,191,81,94,131,180,89,79,237,117,30,106,190,97,233,53,235,163,61,130,254,35,88,148,254,230,240,235,118,222,84,106,92,2,89,155] \ No newline at end of file diff --git a/evm_loader/tests/README.md b/evm_loader/tests/README.md index 95e372390..7ce13b3d2 100644 --- a/evm_loader/tests/README.md +++ b/evm_loader/tests/README.md @@ -15,7 +15,7 @@ py.test ./ -s -v Moreover, we can use additional command line keys: -1. --operator-keys - path to 2 comma separated operator keys (by default ~/.config/solana/id.json,~/.config/solana/id2.json) +1. --neon-api-uri - neon_core_api url (by default 'http://neon_api:8085/api') Also we can configure some variables from environment variables: diff --git a/evm_loader/tests/conftest.py b/evm_loader/tests/conftest.py index e4a55f7fb..254653dcb 100644 --- a/evm_loader/tests/conftest.py +++ b/evm_loader/tests/conftest.py @@ -10,8 +10,9 @@ from solana.publickey import PublicKey from solana.rpc.commitment import Confirmed -from .solana_utils import EvmLoader, OperatorAccount, create_treasury_pool_address, make_new_user, get_solana_balance, \ - deposit_neon, solana_client +from .solana_utils import EvmLoader, create_treasury_pool_address, make_new_user, \ + deposit_neon, solana_client, spl_cli, wait_confirm_transaction, get_solana_balance +from .utils.constants import NEON_TOKEN_MINT_ID from .utils.contract import deploy_contract from .utils.storage import create_holder from .utils.types import TreasuryPool, Caller, Contract @@ -19,17 +20,13 @@ def pytest_addoption(parser): - parser.addoption( - "--operator-keys", action="store", default="~/.config/solana/id.json,~/.config/solana/id2.json", - help="Path to 2 comma separated operator keypairs" - ) parser.addoption( "--neon-api-uri", action="store", default="http://neon_api:8085/api", help="" ) -def pytest_configure(config): +def pytest_configure(): if "RUST_LOG" in os.environ: pytest.CONTRACTS_PATH = pathlib.Path("/opt/solidity") else: @@ -37,44 +34,56 @@ def pytest_configure(config): @pytest.fixture(scope="session") -def evm_loader(request) -> EvmLoader: - wallet = OperatorAccount( - pathlib.Path(request.config.getoption("--operator-keys").split(',')[0]).expanduser().as_posix()) - loader = EvmLoader(wallet) +def evm_loader(operator_keypair) -> EvmLoader: + loader = EvmLoader(operator_keypair) return loader -@pytest.fixture(scope="session") -def operator_keypair(request, evm_loader) -> Keypair: - """ - Initialized solana keypair with balance. Get private key from cli or ~/.config/solana/id.json - """ - with open(pathlib.Path(request.config.getoption("--operator-keys").split(',')[0]).expanduser(), "r") as key: +def prepare_operator(key_file): + with open(key_file, "r") as key: secret_key = json.load(key)[:32] account = Keypair.from_secret_key(secret_key) + tx = solana_client.request_airdrop(account.public_key, 1000000 * 10 ** 9, commitment=Confirmed) + wait_confirm_transaction(solana_client, tx.value) caller_ether = eth_keys.PrivateKey(account.secret_key[:32]).public_key.to_canonical_address() + evm_loader = EvmLoader(account) + evm_loader.ether2program(caller_ether) caller, caller_nonce = evm_loader.ether2program(caller_ether) - - if get_solana_balance(PublicKey(caller)) == 0: - + acc_info = solana_client.get_account_info(PublicKey(caller), commitment=Confirmed) + if acc_info.value is None: + token = spl_cli.create_token_account(NEON_TOKEN_MINT_ID, account.public_key, fee_payer=key_file) + spl_cli.mint(NEON_TOKEN_MINT_ID, token, 5000000, fee_payer=key_file) evm_loader.create_ether_account(caller_ether) return account @pytest.fixture(scope="session") -def second_operator_keypair(request, evm_loader) -> Keypair: +def operator_keypair(worker_id) -> Keypair: """ - Initialized solana keypair with balance. Get private key from cli or ~/.config/solana/id.json + Initialized solana keypair with balance. Get private keys from ci/operator-keypairs """ - with open(pathlib.Path(request.config.getoption("--operator-keys").split(",")[1]).expanduser(), "r") as key: - secret_key = json.load(key)[:32] - account = Keypair.from_secret_key(secret_key) - caller_ether = eth_keys.PrivateKey(account.secret_key[:32]).public_key.to_canonical_address() - caller, caller_nonce = evm_loader.ether2program(caller_ether) + key_path = pathlib.Path(__file__).parent.parent / "operator-keypairs" + if worker_id in ("master", "gw1"): + key_file = key_path / "id.json" + else: + file_id = int(worker_id[-1]) + 2 + key_file = key_path / f"id{file_id}.json" + return prepare_operator(key_file) - if get_solana_balance(PublicKey(caller)) == 0: - evm_loader.create_ether_account(caller_ether) - return account + +@pytest.fixture(scope="session") +def second_operator_keypair(worker_id) -> Keypair: + """ + Initialized solana keypair with balance. Get private key from cli or ./ci/operator-keypairs + """ + key_path = pathlib.Path(__file__).parent.parent / "operator-keypairs" + if worker_id in ("master", "gw1"): + key_file = key_path / "id20.json" + else: + file_id = 20 + int(worker_id[-1]) + 2 + key_file = key_path / f"id{file_id}.json" + + return prepare_operator(key_file) @pytest.fixture(scope="session") diff --git a/evm_loader/tests/solana_utils.py b/evm_loader/tests/solana_utils.py index a20ae3ea9..eeed1efea 100644 --- a/evm_loader/tests/solana_utils.py +++ b/evm_loader/tests/solana_utils.py @@ -1,7 +1,6 @@ import json import math import os -import pathlib import subprocess import time import typing @@ -81,11 +80,10 @@ def balance(self, acc): res = self.call("balance --address {}".format(acc)) return Decimal(res.rstrip()) - def mint(self, mint_id, recipient, amount, owner=None): - if owner is None: - self.call("mint {} {} {}".format(mint_id, amount, recipient)) - else: - self.call("mint {} {} {} --owner {}".format(mint_id, amount, recipient, owner)) + def mint(self, mint_id, recipient, amount, fee_payer=None): + self.call( + "mint {} {} --owner evm_loader-keypair.json --fee-payer {} -- {}".format(mint_id, amount, fee_payer, + recipient)) print("minting {} tokens for {}".format(amount, recipient)) def create_token(self, owner=None): @@ -98,11 +96,11 @@ def create_token(self, owner=None): else: return res.split()[2] - def create_token_account(self, token, owner=None): + def create_token_account(self, token, owner=None, fee_payer=None): if owner is None: res = self.call("create-account {}".format(token)) else: - res = self.call("create-account {} --owner {}".format(token, owner)) + res = self.call("create-account {} --owner {} --fee-payer {}".format(token, owner, fee_payer)) if not res.startswith("Creating account "): raise Exception("create account error %s" % res) else: @@ -288,28 +286,8 @@ def __init__(self, path): print('Wallet public key:', self.acc.public_key()) -class OperatorAccount: - def __init__(self, path=None): - if path is None: - self.path = pathlib.Path.home() / ".config" / "solana" / "id.json" - else: - self.path = path - self.retrieve_keys() - - def retrieve_keys(self): - with open(self.path) as f: - d = json.load(f) - self.acc = Keypair.from_secret_key(d[0:32]) - - def get_path(self): - return self.path - - def get_acc(self) -> Keypair: - return self.acc - - class EvmLoader: - def __init__(self, acc: OperatorAccount, program_id=EVM_LOADER): + def __init__(self, acc, program_id=EVM_LOADER): if program_id is None: print(f"EVM Loader program address is empty, deploy it") result = json.loads(solana_cli(acc).call('deploy {}'.format(EVM_LOADER_SO))) @@ -334,7 +312,7 @@ def deploy(self, contract_path, config=None): def create_ether_account(self, ether): (trx, sol) = self.create_ether_account_trx(ether) - signer = self.acc.get_acc() + signer = self.acc self.check_account(signer.public_key) send_transaction(solana_client, trx, signer) return sol @@ -357,7 +335,7 @@ def ether2bytes(ether: Union[str, bytes]): def ether2seed(self, ether: Union[str, bytes]): seed = b58encode(ACCOUNT_SEED_VERSION + self.ether2bytes(ether)).decode('utf8') - acc = account_with_seed(self.acc.get_acc().public_key, seed, self.loader_id) + acc = account_with_seed(self.acc.public_key, seed, self.loader_id) print('ether2program: {} {} => {}'.format(self.ether2hex(ether), 255, acc)) return acc, 255 @@ -386,7 +364,7 @@ def deploy_checked(self, location, caller, caller_ether): def create_ether_account_trx(self, ether: Union[str, bytes]) -> Tuple[Transaction, str]: (sol, nonce) = self.ether2program(ether) print('createEtherAccount: {} {} => {}'.format(ether, nonce, sol)) - base = self.acc.get_acc().public_key + base = self.acc.public_key data = bytes.fromhex('28') + CREATE_ACCOUNT_LAYOUT.build(dict(ether=self.ether2bytes(ether))) trx = Transaction() trx.add(TransactionInstruction( From bfa302d052bda45ce94187bf098b7d32b412b0d1 Mon Sep 17 00:00:00 2001 From: Denis K <100715772+dk-neon@users.noreply.github.com> Date: Fri, 25 Aug 2023 18:20:20 +0500 Subject: [PATCH 008/318] Added support for different tracer types (#168) * Made `TracerType` dynamic * Refactored. Added support for different tracer types. Moved debug tracing functionality from Tracer API. * Fixed warnings * Added support of byte-vector buffer in order to reduce cloning * Reduced cloning of `return_data` * Removed unused `trace_stack` * Marked `Buffer::from_account` as `unsafe` * Small optimization * Restructured modules, simplified code * Rewritten `StructLogger` tracer in order to simplify the code * Rewritten `opcode_call_precompile_impl` to more idiomatic * Rolled back changes rejected during review * Updated serde version * Updated serde version * Fixed arguments for `emulate-hash` in Neon CLI --- evm_loader/Cargo.lock | 201 +++++------ evm_loader/api/Cargo.toml | 2 +- .../api/src/api_server/handlers/emulate.rs | 4 +- .../src/api_server/handlers/emulate_hash.rs | 4 +- evm_loader/cli/Cargo.toml | 2 +- evm_loader/cli/src/main.rs | 10 +- evm_loader/lib/Cargo.toml | 3 +- evm_loader/lib/src/account_storage.rs | 2 +- evm_loader/lib/src/commands/emulate.rs | 57 ++-- evm_loader/lib/src/commands/trace.rs | 58 ++-- evm_loader/lib/src/types/mod.rs | 2 +- evm_loader/lib/src/types/request_models.rs | 2 +- evm_loader/program-macro/Cargo.toml | 2 +- evm_loader/program/Cargo.toml | 10 +- .../program/src/account_storage/backend.rs | 2 +- evm_loader/program/src/evm/buffer.rs | 21 +- evm_loader/program/src/evm/memory.rs | 13 +- evm_loader/program/src/evm/mod.rs | 72 ++-- evm_loader/program/src/evm/opcode.rs | 11 +- evm_loader/program/src/evm/opcode_table.rs | 322 +++++++++--------- evm_loader/program/src/evm/stack.rs | 8 +- .../tracing/event_listener/listener_tracer.rs | 35 -- .../event_listener/listener_vm_tracer.rs | 70 ---- .../src/evm/tracing/event_listener/mod.rs | 54 --- .../src/evm/tracing/event_listener/trace.rs | 307 ----------------- .../src/evm/tracing/event_listener/tracer.rs | 31 -- .../evm/tracing/event_listener/vm_tracer.rs | 39 --- evm_loader/program/src/evm/tracing/mod.rs | 110 +++++- .../program/src/evm/tracing/tracers/mod.rs | 20 ++ .../src/evm/tracing/tracers/struct_logger.rs | 221 ++++++++++++ 30 files changed, 766 insertions(+), 929 deletions(-) delete mode 100644 evm_loader/program/src/evm/tracing/event_listener/listener_tracer.rs delete mode 100644 evm_loader/program/src/evm/tracing/event_listener/listener_vm_tracer.rs delete mode 100644 evm_loader/program/src/evm/tracing/event_listener/mod.rs delete mode 100644 evm_loader/program/src/evm/tracing/event_listener/trace.rs delete mode 100644 evm_loader/program/src/evm/tracing/event_listener/tracer.rs delete mode 100644 evm_loader/program/src/evm/tracing/event_listener/vm_tracer.rs create mode 100644 evm_loader/program/src/evm/tracing/tracers/mod.rs create mode 100644 evm_loader/program/src/evm/tracing/tracers/struct_logger.rs diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index aff050235..e12996223 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -159,8 +159,8 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", + "proc-macro2 1.0.66", + "quote 1.0.32", "syn 1.0.109", "synstructure", ] @@ -171,8 +171,8 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", + "proc-macro2 1.0.66", + "quote 1.0.32", "syn 1.0.109", ] @@ -211,9 +211,9 @@ version = "0.1.68" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", - "syn 2.0.15", + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 2.0.28", ] [[package]] @@ -388,7 +388,7 @@ dependencies = [ "borsh-derive-internal", "borsh-schema-derive-internal", "proc-macro-crate 0.1.5", - "proc-macro2 1.0.56", + "proc-macro2 1.0.66", "syn 1.0.109", ] @@ -398,8 +398,8 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", + "proc-macro2 1.0.66", + "quote 1.0.32", "syn 1.0.109", ] @@ -409,8 +409,8 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", + "proc-macro2 1.0.66", + "quote 1.0.32", "syn 1.0.109", ] @@ -481,9 +481,9 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", - "syn 2.0.15", + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 2.0.28", ] [[package]] @@ -635,8 +635,8 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18af5425854858c507eec70f7deb4d5d8cec4216fcb086283a78872387281ea5" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", + "proc-macro2 1.0.66", + "quote 1.0.32", "serde_derive_internals", "syn 1.0.109", ] @@ -727,8 +727,8 @@ version = "0.2.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d897f47bf7270cf70d370f8f98c1abb6d2d4cf60a6845d30e05bfb90c6568650" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", + "proc-macro2 1.0.66", + "quote 1.0.32", "unicode-xid 0.2.4", ] @@ -908,10 +908,10 @@ dependencies = [ "cc", "codespan-reporting", "once_cell", - "proc-macro2 1.0.56", - "quote 1.0.26", + "proc-macro2 1.0.66", + "quote 1.0.32", "scratch", - "syn 2.0.15", + "syn 2.0.28", ] [[package]] @@ -926,9 +926,9 @@ version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", - "syn 2.0.15", + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 2.0.28", ] [[package]] @@ -1025,8 +1025,8 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", + "proc-macro2 1.0.66", + "quote 1.0.32", "syn 1.0.109", ] @@ -1130,8 +1130,8 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8958699f9359f0b04e691a13850d48b7de329138023876d07cbd024c2c820598" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", + "proc-macro2 1.0.66", + "quote 1.0.32", "syn 1.0.109", ] @@ -1142,8 +1142,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11f36e95862220b211a6e2aa5eca09b4fa391b13cd52ceb8035a24bf65a79de2" dependencies = [ "once_cell", - "proc-macro2 1.0.56", - "quote 1.0.26", + "proc-macro2 1.0.66", + "quote 1.0.32", "syn 1.0.109", ] @@ -1229,7 +1229,7 @@ version = "1.0.0" dependencies = [ "bs58", "itertools", - "quote 1.0.26", + "quote 1.0.32", "serde", "syn 1.0.109", "toml", @@ -1365,9 +1365,9 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", - "syn 2.0.15", + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 2.0.28", ] [[package]] @@ -2148,7 +2148,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12989bc45715b0ee91944855130131479f9c772e198a910c3eb0ea327d5bffc3" dependencies = [ - "quote 1.0.26", + "quote 1.0.32", "syn 1.0.109", ] @@ -2240,6 +2240,7 @@ dependencies = [ "rand 0.8.5", "scroll", "serde", + "serde_json", "solana-clap-utils", "solana-cli", "solana-cli-config", @@ -2350,8 +2351,8 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", + "proc-macro2 1.0.66", + "quote 1.0.32", "syn 1.0.109", ] @@ -2423,8 +2424,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" dependencies = [ "proc-macro-crate 1.3.1", - "proc-macro2 1.0.56", - "quote 1.0.26", + "proc-macro2 1.0.66", + "quote 1.0.32", "syn 1.0.109", ] @@ -2476,9 +2477,9 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", - "syn 2.0.15", + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 2.0.28", ] [[package]] @@ -2615,9 +2616,9 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", - "syn 2.0.15", + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 2.0.28", ] [[package]] @@ -2755,9 +2756,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.56" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] @@ -2835,11 +2836,11 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.26" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" dependencies = [ - "proc-macro2 1.0.56", + "proc-macro2 1.0.66", ] [[package]] @@ -3297,8 +3298,8 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bdbda6ac5cd1321e724fa9cee216f3a61885889b896f073b8f82322789c5250e" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", + "proc-macro2 1.0.66", + "quote 1.0.32", "syn 1.0.109", ] @@ -3319,8 +3320,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b5e421024b5e5edfbaa8e60ecf90bda9dbffc602dbb230e6028763f85f0c68c" dependencies = [ "heck", - "proc-macro2 1.0.56", - "quote 1.0.26", + "proc-macro2 1.0.66", + "quote 1.0.32", "syn 1.0.109", ] @@ -3355,31 +3356,31 @@ checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" [[package]] name = "serde" -version = "1.0.160" +version = "1.0.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" +checksum = "9f5db24220c009de9bd45e69fb2938f4b6d2df856aa9304ce377b3180f83b7c1" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.9" +version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416bda436f9aab92e02c8e10d49a15ddd339cea90b6e340fe51ed97abb548294" +checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.160" +version = "1.0.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" +checksum = "5ad697f7e0b65af4983a4ce8f56ed5b357e8d3c36651bf6a7e13639c17b8e670" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", - "syn 2.0.15", + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 2.0.28", ] [[package]] @@ -3388,16 +3389,16 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", + "proc-macro2 1.0.66", + "quote 1.0.32", "syn 1.0.109", ] [[package]] name = "serde_json" -version = "1.0.96" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" dependencies = [ "itoa", "ryu", @@ -3509,8 +3510,8 @@ version = "0.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63927d22a1e8b74bda98cc6e151fcdf178b7abb0dc6c4f81e0bbf5ffe2fc4ec8" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", + "proc-macro2 1.0.66", + "quote 1.0.32", "shank_macro_impl", "syn 1.0.109", ] @@ -3522,8 +3523,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40ce03403df682f80f4dc1efafa87a4d0cb89b03726d0565e6364bdca5b9a441" dependencies = [ "anyhow", - "proc-macro2 1.0.56", - "quote 1.0.26", + "proc-macro2 1.0.66", + "quote 1.0.32", "serde", "syn 1.0.109", ] @@ -3912,8 +3913,8 @@ version = "1.14.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f527f44601b35dd67d11bc72f2f7512976a466f9304ef574b87dac83ced8a42" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", + "proc-macro2 1.0.66", + "quote 1.0.32", "rustc_version", "syn 1.0.109", ] @@ -4166,8 +4167,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bbc3ab3070c090e1a18fd5a0a07d729d0db2bc8524414dc3e16504286d38049" dependencies = [ "bs58", - "proc-macro2 1.0.56", - "quote 1.0.26", + "proc-macro2 1.0.66", + "quote 1.0.32", "rustversion", "syn 1.0.109", ] @@ -4441,19 +4442,19 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", + "proc-macro2 1.0.66", + "quote 1.0.32", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.15" +version = "2.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", + "proc-macro2 1.0.66", + "quote 1.0.32", "unicode-ident", ] @@ -4469,8 +4470,8 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", + "proc-macro2 1.0.66", + "quote 1.0.32", "syn 1.0.109", "unicode-xid 0.2.4", ] @@ -4527,9 +4528,9 @@ version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", - "syn 2.0.15", + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 2.0.28", ] [[package]] @@ -4645,9 +4646,9 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", - "syn 2.0.15", + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 2.0.28", ] [[package]] @@ -4820,8 +4821,8 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", + "proc-macro2 1.0.66", + "quote 1.0.32", "syn 1.0.109", ] @@ -5078,8 +5079,8 @@ dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2 1.0.56", - "quote 1.0.26", + "proc-macro2 1.0.66", + "quote 1.0.32", "syn 1.0.109", "wasm-bindgen-shared", ] @@ -5102,7 +5103,7 @@ version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" dependencies = [ - "quote 1.0.26", + "quote 1.0.32", "wasm-bindgen-macro-support", ] @@ -5112,8 +5113,8 @@ version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", + "proc-macro2 1.0.66", + "quote 1.0.32", "syn 1.0.109", "wasm-bindgen-backend", "wasm-bindgen-shared", @@ -5410,9 +5411,9 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ - "proc-macro2 1.0.56", - "quote 1.0.26", - "syn 2.0.15", + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 2.0.28", ] [[package]] diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 2c77c82e3..464d8a992 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" clap = "2.33.3" evm-loader = { path = "../program", default_features = false, features = ["log"] } solana-sdk = "=1.14.20" -serde = "1.0.147" +serde = "1.0.186" serde_json = "1.0.85" ethnum = { version = "1", default_features = false, features = ["serde"] } tokio = { version = "1", features = ["full"] } diff --git a/evm_loader/api/src/api_server/handlers/emulate.rs b/evm_loader/api/src/api_server/handlers/emulate.rs index cf24ced0a..083e40075 100644 --- a/evm_loader/api/src/api_server/handlers/emulate.rs +++ b/evm_loader/api/src/api_server/handlers/emulate.rs @@ -1,5 +1,4 @@ use axum::{http::StatusCode, Json}; -use evm_loader::evm::tracing::event_listener::trace::TraceCallConfig; use std::convert::Into; use crate::{ @@ -36,7 +35,8 @@ pub async fn emulate( state.config.commitment, &accounts, &solana_accounts, - TraceCallConfig::default(), + &None, + None, ) .await .map_err(Into::into), diff --git a/evm_loader/api/src/api_server/handlers/emulate_hash.rs b/evm_loader/api/src/api_server/handlers/emulate_hash.rs index 39a21c6a6..4d425d877 100644 --- a/evm_loader/api/src/api_server/handlers/emulate_hash.rs +++ b/evm_loader/api/src/api_server/handlers/emulate_hash.rs @@ -1,5 +1,4 @@ use axum::{http::StatusCode, Json}; -use evm_loader::evm::tracing::event_listener::trace::TraceCallConfig; use std::convert::Into; use crate::{ @@ -49,7 +48,8 @@ pub async fn emulate_hash( state.config.commitment, &accounts, &solana_accounts, - TraceCallConfig::default(), + &None, + None, ) .await .map_err(Into::into), diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index acaac9ed1..15c800fd2 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -13,7 +13,7 @@ solana-client = "=1.14.20" solana-clap-utils = "=1.14.20" solana-cli-config = "=1.14.20" hex = "0.4.2" -serde = "1.0.147" +serde = "1.0.186" serde_json = "1.0.85" log = "0.4.17" fern = "0.6" diff --git a/evm_loader/cli/src/main.rs b/evm_loader/cli/src/main.rs index dab7509af..ae6efc045 100644 --- a/evm_loader/cli/src/main.rs +++ b/evm_loader/cli/src/main.rs @@ -21,7 +21,7 @@ pub use context::Context; use std::io::Read; use ethnum::U256; -use evm_loader::evm::tracing::event_listener::trace::{TraceCallConfig, TraceConfig}; +use evm_loader::evm::tracing::{TraceCallConfig, TraceConfig}; use serde_json::json; use solana_clap_utils::input_parsers::{pubkey_of, value_of, values_of}; use solana_client::client_error::{ClientError, ClientErrorKind}; @@ -119,13 +119,14 @@ async fn execute<'a>( config.commitment, &accounts, &solana_accounts, - trace_call_config, + &trace_call_config.block_overrides, + trace_call_config.state_overrides, ) .await .map(|result| json!(result)) } ("emulate-hash", Some(params)) => { - let (tx, trace_config) = parse_tx_hash(context.rpc_client.as_ref()).await; + let tx = context.rpc_client.get_transaction_data().await?; let (token, chain, steps, accounts, solana_accounts) = parse_tx_params(config, context, params).await; emulate::execute( @@ -138,7 +139,8 @@ async fn execute<'a>( config.commitment, &accounts, &solana_accounts, - trace_config.into(), + &None, + None, ) .await .map(|result| json!(result)) diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 55c17d070..87ae35a45 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -19,7 +19,8 @@ spl-token = { version = "~3.5", default_features = false, features = ["no-entryp spl-associated-token-account = { version = "~1.1", default_features = false, features = ["no-entrypoint"] } bs58 = "0.4.0" hex = "0.4.2" -serde = "1.0.147" +serde = "1.0.186" +serde_json = "1.0.105" log = "0.4.17" rand = "0.8" ethnum = { version = "1", default_features = false, features = ["serde"] } diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index f8c1792dd..8dcb3980a 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -5,7 +5,7 @@ use crate::{rpc::Rpc, NeonError}; use ethnum::U256; use evm_loader::account::ether_contract; use evm_loader::account_storage::{find_slot_hash, AccountOperation, AccountsOperations}; -use evm_loader::evm::tracing::event_listener::trace::{AccountOverrides, BlockOverrides}; +use evm_loader::evm::tracing::{AccountOverrides, BlockOverrides}; use evm_loader::{ account::{ ether_storage::EthereumStorageAddress, EthereumAccount, EthereumStorage, diff --git a/evm_loader/lib/src/commands/emulate.rs b/evm_loader/lib/src/commands/emulate.rs index 28929055d..fdcbc41d2 100644 --- a/evm_loader/lib/src/commands/emulate.rs +++ b/evm_loader/lib/src/commands/emulate.rs @@ -5,8 +5,8 @@ use log::{debug, info}; use serde::{Deserialize, Serialize}; use solana_sdk::{commitment_config::CommitmentConfig, pubkey::Pubkey}; -use evm_loader::evm::tracing::event_listener::trace::TraceCallConfig; -use evm_loader::evm::tracing::event_listener::tracer::TracerType; +use evm_loader::evm::tracing::TracerTypeOpt; +use evm_loader::evm::tracing::{AccountOverrides, BlockOverrides}; use evm_loader::{ account_storage::AccountStorage, config::{EVM_STEPS_MIN, PAYMENT_TO_TREASURE}, @@ -50,6 +50,18 @@ impl Display for EmulationResult { } } +impl From for EmulationResult { + fn from(value: evm_loader::evm::tracing::EmulationResult) -> Self { + Self { + exit_status: value.exit_status.status().to_string(), + result: value.exit_status.into_result().unwrap_or_default(), + steps_executed: value.steps_executed, + used_gas: value.used_gas, + actions: value.actions, + } + } +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct EmulationResultWithAccounts { pub accounts: Vec, @@ -108,7 +120,8 @@ pub async fn execute( commitment: CommitmentConfig, accounts: &[Address], solana_accounts: &[Pubkey], - trace_call_config: TraceCallConfig, + block_overrides: &Option, + state_overrides: Option, ) -> NeonResult { let (emulation_result, storage) = emulate_transaction( rpc_client, @@ -120,7 +133,8 @@ pub async fn execute( commitment, accounts, solana_accounts, - trace_call_config, + block_overrides, + state_overrides, None, ) .await?; @@ -134,7 +148,7 @@ pub async fn execute( accounts, solana_accounts, token_accounts: vec![], - emulation_result, + emulation_result: emulation_result.into(), }) } @@ -149,9 +163,16 @@ pub(crate) async fn emulate_transaction<'a>( commitment: CommitmentConfig, accounts: &[Address], solana_accounts: &[Pubkey], - trace_call_config: TraceCallConfig, - tracer: TracerType, -) -> Result<(EmulationResult, EmulatorAccountStorage<'a>), NeonError> { + block_overrides: &Option, + state_overrides: Option, + tracer: TracerTypeOpt, +) -> Result< + ( + evm_loader::evm::tracing::EmulationResult, + EmulatorAccountStorage<'a>, + ), + NeonError, +> { setup_syscall_stubs(rpc_client).await?; let storage = EmulatorAccountStorage::with_accounts( @@ -162,8 +183,8 @@ pub(crate) async fn emulate_transaction<'a>( commitment, accounts, solana_accounts, - &trace_call_config.block_overrides, - trace_call_config.state_overrides, + block_overrides, + state_overrides, ) .await?; @@ -177,8 +198,8 @@ pub(crate) async fn emulate_trx<'a>( storage: &'a EmulatorAccountStorage<'a>, chain_id: u64, step_limit: u64, - tracer: TracerType, -) -> Result { + tracer: TracerTypeOpt, +) -> Result { let (exit_status, actions, steps_executed) = { let mut backend = ExecutorState::new(storage); let trx = Transaction { @@ -216,16 +237,8 @@ pub(crate) async fn emulate_trx<'a>( let accounts_gas = block(storage.apply_accounts_operations(accounts_operations)); info!("Gas - steps: {steps_gas}, actions: {actions_gas}, accounts: {accounts_gas}"); - let (result, status) = match exit_status { - ExitStatus::Return(v) => (v, "succeed"), - ExitStatus::Revert(v) => (v, "revert"), - ExitStatus::Stop | ExitStatus::Suicide => (vec![], "succeed"), - ExitStatus::StepLimit => unreachable!(), - }; - - Ok(EmulationResult { - result, - exit_status: status.to_string(), + Ok(evm_loader::evm::tracing::EmulationResult { + exit_status, steps_executed, used_gas: steps_gas + begin_end_gas + actions_gas + accounts_gas, actions, diff --git a/evm_loader/lib/src/commands/trace.rs b/evm_loader/lib/src/commands/trace.rs index 576544edd..7a7061fc6 100644 --- a/evm_loader/lib/src/commands/trace.rs +++ b/evm_loader/lib/src/commands/trace.rs @@ -1,11 +1,12 @@ use std::fmt::{Display, Formatter}; -use std::sync::{Arc, RwLock}; +use std::sync::Arc; use serde::{Deserialize, Serialize}; +use serde_json::Value; use solana_sdk::{commitment_config::CommitmentConfig, pubkey::Pubkey}; -use evm_loader::evm::tracing::event_listener::trace::{TraceCallConfig, TraceConfig, TracedCall}; -use evm_loader::evm::tracing::event_listener::tracer::Tracer; +use evm_loader::evm::tracing::tracers::new_tracer; +use evm_loader::evm::tracing::{TraceCallConfig, TraceConfig}; use evm_loader::types::Address; use crate::{ @@ -28,10 +29,8 @@ pub async fn trace_transaction( accounts: &[Address], solana_accounts: &[Pubkey], trace_call_config: TraceCallConfig, -) -> Result { - let tracer = Arc::new(RwLock::new(Tracer::new( - trace_call_config.trace_config.enable_return_data, - ))); +) -> Result { + let tracer = new_tracer(&trace_call_config.trace_config)?; let (emulation_result, _storage) = emulate_transaction( rpc_client, @@ -43,28 +42,21 @@ pub async fn trace_transaction( commitment, accounts, solana_accounts, - trace_call_config, - Some(tracer.clone()), + &trace_call_config.block_overrides, + trace_call_config.state_overrides, + Some(Arc::clone(&tracer)), ) .await?; - let (vm_trace, full_trace_data) = Arc::try_unwrap(tracer) + Ok(Arc::try_unwrap(tracer) .expect("There is must be only one reference") .into_inner() .expect("Poisoned RwLock") - .into_traces(); - - Ok(TracedCall { - vm_trace, - full_trace_data, - used_gas: emulation_result.used_gas, - result: emulation_result.result, - exit_status: emulation_result.exit_status, - }) + .into_traces(emulation_result)) } #[derive(Serialize, Deserialize)] -pub struct TraceBlockReturn(pub Vec); +pub struct TraceBlockReturn(pub Vec); impl Display for TraceBlockReturn { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { @@ -115,23 +107,21 @@ async fn trace_trx<'a>( chain_id: u64, steps: u64, trace_config: &TraceConfig, -) -> Result { - let tracer = Arc::new(RwLock::new(Tracer::new(trace_config.enable_return_data))); +) -> Result { + let tracer = new_tracer(trace_config)?; - let emulation_result = - emulate_trx(tx_params, storage, chain_id, steps, Some(tracer.clone())).await?; + let emulation_result = emulate_trx( + tx_params, + storage, + chain_id, + steps, + Some(Arc::clone(&tracer)), + ) + .await?; - let (vm_trace, full_trace_data) = Arc::try_unwrap(tracer) + Ok(Arc::try_unwrap(tracer) .expect("There is must be only one reference") .into_inner() .expect("Poisoned RwLock") - .into_traces(); - - Ok(TracedCall { - vm_trace, - full_trace_data, - used_gas: emulation_result.used_gas, - result: emulation_result.result, - exit_status: emulation_result.exit_status, - }) + .into_traces(emulation_result)) } diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index 659b5b870..4384207c9 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -11,7 +11,7 @@ use tokio::runtime::Runtime; use tokio::task::block_in_place; pub use tracer_ch_db::{ChError, ChResult, ClickHouseDb as TracerDb}; -use evm_loader::evm::tracing::event_listener::trace::{TraceCallConfig, TraceConfig}; +use evm_loader::evm::tracing::{TraceCallConfig, TraceConfig}; use evm_loader::types::hexbytes::HexBytes; use { ethnum::U256, diff --git a/evm_loader/lib/src/types/request_models.rs b/evm_loader/lib/src/types/request_models.rs index 7c9a04368..2769dc3e3 100644 --- a/evm_loader/lib/src/types/request_models.rs +++ b/evm_loader/lib/src/types/request_models.rs @@ -1,6 +1,6 @@ use crate::types::{PubkeyBase58, TxParams}; use ethnum::U256; -use evm_loader::evm::tracing::event_listener::trace::{TraceCallConfig, TraceConfig}; +use evm_loader::evm::tracing::{TraceCallConfig, TraceConfig}; use evm_loader::types::Address; use serde::{Deserialize, Serialize}; use solana_sdk::pubkey::Pubkey; diff --git a/evm_loader/program-macro/Cargo.toml b/evm_loader/program-macro/Cargo.toml index 02d109b73..422086822 100644 --- a/evm_loader/program-macro/Cargo.toml +++ b/evm_loader/program-macro/Cargo.toml @@ -13,5 +13,5 @@ syn = "1" quote = "1" itertools = "0.10.5" bs58 = "0.4" -serde = { version = "1", features = [ "derive" ] } +serde = { version = "1.0.186", features = [ "derive" ] } toml = "0.5" diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index f104a0bbb..9cc0c70dc 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -34,7 +34,7 @@ test-bpf = [] custom-heap = [] default = ["custom-heap"] -tracing = [] +tracing = ["serde_json"] [dependencies] linked_list_allocator = { version = "0.10", default_features = false } @@ -51,16 +51,14 @@ rlp = "0.5" static_assertions = "1" borsh = "0.9" bincode = "1" -serde_bytes = "0.11" -serde = { version = "1", features = ["derive"] } +serde_bytes = "0.11.12" +serde = { version = "1.0.186", default-features = false, features = ["derive", "rc"] } +serde_json = { version = "1.0.105", optional = true } ethnum = { version = "1", default_features = false, features = ["serde"] } const_format = { version = "0.2.21" } cfg-if = { version = "1.0" } log = { version = "0.4", default-features = false, optional = true } -[dev-dependencies] -serde_json = "1" - [lib] crate-type = ["cdylib", "lib"] diff --git a/evm_loader/program/src/account_storage/backend.rs b/evm_loader/program/src/account_storage/backend.rs index b38645242..2b93c0976 100644 --- a/evm_loader/program/src/account_storage/backend.rs +++ b/evm_loader/program/src/account_storage/backend.rs @@ -98,7 +98,7 @@ impl<'a> AccountStorage for ProgramAccountStorage<'a> { return Buffer::empty(); } - Buffer::from_account(account.info, account.code_location()) + unsafe { Buffer::from_account(account.info, account.code_location()) } } else { Buffer::empty() } diff --git a/evm_loader/program/src/evm/buffer.rs b/evm_loader/program/src/evm/buffer.rs index 580f715e5..7b95e248e 100644 --- a/evm_loader/program/src/evm/buffer.rs +++ b/evm_loader/program/src/evm/buffer.rs @@ -48,13 +48,17 @@ impl Buffer { Buffer { ptr, len, inner } } + /// # Safety + /// + /// This function was marked as unsafe until correct lifetimes will be set. + /// At the moment, `Buffer` may outlive `account`, since no lifetimes has been set, + /// so they are not checked by the compiler and it's the user's responsibility to take + /// care of them. #[must_use] - pub fn from_account(account: &AccountInfo, range: Range) -> Self { - let data = unsafe { - // todo cell_leak #69099 - let ptr = account.data.as_ptr(); - (*ptr).as_mut_ptr() - }; + pub unsafe fn from_account(account: &AccountInfo, range: Range) -> Self { + // todo cell_leak #69099 + let ptr = account.data.as_ptr(); + let data = (*ptr).as_mut_ptr(); Buffer::new(Inner::Account { key: *account.key, @@ -98,6 +102,11 @@ impl Buffer { Buffer::new(Inner::Empty) } + #[must_use] + pub fn is_initialized(&self) -> bool { + !matches!(self.inner, Inner::AccountUninit { .. }) + } + #[must_use] pub fn uninit_data(&self) -> Option<(Pubkey, Range)> { if let Inner::AccountUninit { key, range } = &self.inner { diff --git a/evm_loader/program/src/evm/memory.rs b/evm_loader/program/src/evm/memory.rs index cffb0a989..ce9c40c6d 100644 --- a/evm_loader/program/src/evm/memory.rs +++ b/evm_loader/program/src/evm/memory.rs @@ -5,9 +5,7 @@ use solana_program::program_memory::{sol_memcpy, sol_memset}; use crate::error::Error; #[cfg(feature = "tracing")] -use crate::evm::tracing::event_listener::tracer::TracerType; -#[cfg(feature = "tracing")] -use crate::evm::tracing::EventListener; +use crate::evm::tracing::TracerTypeOpt; use super::utils::checked_next_multiple_of_32; use super::{tracing_event, Buffer}; @@ -23,11 +21,11 @@ pub struct Memory { capacity: usize, size: usize, #[cfg(feature = "tracing")] - tracer: TracerType, + tracer: TracerTypeOpt, } impl Memory { - pub fn new(#[cfg(feature = "tracing")] tracer: TracerType) -> Self { + pub fn new(#[cfg(feature = "tracing")] tracer: TracerTypeOpt) -> Self { Self::with_capacity( MEMORY_CAPACITY, #[cfg(feature = "tracing")] @@ -35,7 +33,10 @@ impl Memory { ) } - pub fn with_capacity(capacity: usize, #[cfg(feature = "tracing")] tracer: TracerType) -> Self { + pub fn with_capacity( + capacity: usize, + #[cfg(feature = "tracing")] tracer: TracerTypeOpt, + ) -> Self { unsafe { let layout = Layout::from_size_align_unchecked(capacity, MEMORY_ALIGN); let data = crate::allocator::EVM.alloc_zeroed(layout); diff --git a/evm_loader/program/src/evm/mod.rs b/evm_loader/program/src/evm/mod.rs index e03058a00..f6f653d04 100644 --- a/evm_loader/program/src/evm/mod.rs +++ b/evm_loader/program/src/evm/mod.rs @@ -11,9 +11,7 @@ use solana_program::log::sol_log_data; pub use buffer::Buffer; #[cfg(feature = "tracing")] -use crate::evm::tracing::event_listener::tracer::TracerType; -#[cfg(feature = "tracing")] -use crate::evm::tracing::EventListener; +use crate::evm::tracing::TracerTypeOpt; use crate::{ error::{build_revert_message, Error, Result}, evm::{opcode::Action, precompile::is_precompile_address}, @@ -51,27 +49,22 @@ macro_rules! tracing_event { } macro_rules! trace_end_step { - ($self:ident, $return_data_vec:expr) => { + ($self:ident, $return_data:expr) => { #[cfg(feature = "tracing")] if let Some(tracer) = &$self.tracer { - let mut tracer_write_guard = tracer.write().expect("Poisoned RwLock"); - if tracer_write_guard.enable_return_data() { - tracer_write_guard.event(crate::evm::tracing::Event::EndStep { - gas_used: 0_u64, - return_data: $return_data_vec, - }) - } else { - tracer_write_guard.event(crate::evm::tracing::Event::EndStep { + tracer + .write() + .expect("Poisoned RwLock") + .event(crate::evm::tracing::Event::EndStep { gas_used: 0_u64, - return_data: None, + return_data: $return_data, }) - } } }; - ($self:ident, $condition:expr; $return_data_vec:expr) => { + ($self:ident, $condition:expr; $return_data_getter:expr) => { #[cfg(feature = "tracing")] if $condition { - trace_end_step!($self, $return_data_vec) + trace_end_step!($self, $return_data_getter) } }; } @@ -88,6 +81,34 @@ pub enum ExitStatus { StepLimit, } +impl ExitStatus { + #[must_use] + pub fn status(&self) -> &'static str { + match self { + ExitStatus::Return(_) | ExitStatus::Stop | ExitStatus::Suicide => "succeed", + ExitStatus::Revert(_) => "revert", + ExitStatus::StepLimit => "step limit exceeded", + } + } + + #[must_use] + pub fn is_succeed(&self) -> Option { + match self { + ExitStatus::Stop | ExitStatus::Return(_) | ExitStatus::Suicide => Some(true), + ExitStatus::Revert(_) => Some(false), + ExitStatus::StepLimit => None, + } + } + + #[must_use] + pub fn into_result(self) -> Option> { + match self { + ExitStatus::Return(v) | ExitStatus::Revert(v) => Some(v), + ExitStatus::Stop | ExitStatus::Suicide | ExitStatus::StepLimit => None, + } + } +} + #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)] pub enum Reason { Call, @@ -134,7 +155,7 @@ pub struct Machine { #[serde(skip)] #[cfg(feature = "tracing")] - tracer: TracerType, + tracer: TracerTypeOpt, } impl Machine { @@ -149,7 +170,8 @@ impl Machine { pub fn deserialize_from(buffer: &[u8], backend: &B) -> Result { fn reinit_buffer(buffer: &mut Buffer, backend: &B) { if let Some((key, range)) = buffer.uninit_data() { - *buffer = backend.map_solana_account(&key, |i| Buffer::from_account(i, range)); + *buffer = + backend.map_solana_account(&key, |i| unsafe { Buffer::from_account(i, range) }); } } @@ -173,7 +195,7 @@ impl Machine { trx: Transaction, origin: Address, backend: &mut B, - #[cfg(feature = "tracing")] tracer: TracerType, + #[cfg(feature = "tracing")] tracer: TracerTypeOpt, ) -> Result { let origin_nonce = backend.nonce(&origin)?; @@ -226,7 +248,7 @@ impl Machine { trx: Transaction, origin: Address, backend: &mut B, - #[cfg(feature = "tracing")] tracer: TracerType, + #[cfg(feature = "tracing")] tracer: TracerTypeOpt, ) -> Result { assert!(trx.target.is_some()); @@ -276,7 +298,7 @@ impl Machine { trx: Transaction, origin: Address, backend: &mut B, - #[cfg(feature = "tracing")] tracer: TracerType, + #[cfg(feature = "tracing")] tracer: TracerTypeOpt, ) -> Result { assert!(trx.target.is_none()); @@ -326,9 +348,9 @@ impl Machine { } pub fn execute(&mut self, step_limit: u64, backend: &mut B) -> Result<(ExitStatus, u64)> { - assert!(self.execution_code.uninit_data().is_none()); - assert!(self.call_data.uninit_data().is_none()); - assert!(self.return_data.uninit_data().is_none()); + assert!(self.execution_code.is_initialized()); + assert!(self.call_data.is_initialized()); + assert!(self.return_data.is_initialized()); let mut step = 0_u64; @@ -365,7 +387,7 @@ impl Machine { ); // SAFETY: OPCODES.len() == 256, opcode <= 255 - let opcode_fn = unsafe { Self::OPCODES.get_unchecked(opcode as usize) }; + let (_, opcode_fn) = unsafe { Self::OPCODES.get_unchecked(opcode as usize) }; let opcode_result = match opcode_fn(self, backend) { Ok(result) => result, diff --git a/evm_loader/program/src/evm/opcode.rs b/evm_loader/program/src/evm/opcode.rs index 8dee94c8e..928ad0349 100644 --- a/evm_loader/program/src/evm/opcode.rs +++ b/evm_loader/program/src/evm/opcode.rs @@ -1,5 +1,3 @@ -#[cfg(feature = "tracing")] -use crate::evm::tracing::EventListener; /// use ethnum::{I256, U256}; use solana_program::log::sol_log_data; @@ -1192,14 +1190,11 @@ impl Machine { backend.precompile_extension(&self.context, address, &self.call_data, self.is_static) }); - if result.is_none() { - return Ok(Action::Noop); + if let Some(return_data) = result.transpose()? { + return self.opcode_return_impl(Buffer::from_slice(&return_data), backend); } - let result = result.unwrap()?; - let return_data = Buffer::from_slice(&result); - - self.opcode_return_impl(return_data, backend) + Ok(Action::Noop) } /// Halt execution returning output data diff --git a/evm_loader/program/src/evm/opcode_table.rs b/evm_loader/program/src/evm/opcode_table.rs index ab68d71fd..086a8e3a1 100644 --- a/evm_loader/program/src/evm/opcode_table.rs +++ b/evm_loader/program/src/evm/opcode_table.rs @@ -4,167 +4,169 @@ use crate::error::Result; use super::{database::Database, opcode::Action, Machine}; +type OpCode = (&'static str, fn(&mut Machine, &mut B) -> Result); + impl Machine { - pub const OPCODES: [fn(&mut Self, &mut B) -> Result; 256] = { - let mut opcodes: [fn(&mut Self, &mut B) -> Result; 256] = - [Self::opcode_unknown; 256]; - - opcodes[0x00] = Self::opcode_stop; - opcodes[0x01] = Self::opcode_add; - opcodes[0x02] = Self::opcode_mul; - opcodes[0x03] = Self::opcode_sub; - opcodes[0x04] = Self::opcode_div; - opcodes[0x05] = Self::opcode_sdiv; - opcodes[0x06] = Self::opcode_mod; - opcodes[0x07] = Self::opcode_smod; - opcodes[0x08] = Self::opcode_addmod; - opcodes[0x09] = Self::opcode_mulmod; - opcodes[0x0A] = Self::opcode_exp; - opcodes[0x0B] = Self::opcode_signextend; - - opcodes[0x10] = Self::opcode_lt; - opcodes[0x11] = Self::opcode_gt; - opcodes[0x12] = Self::opcode_slt; - opcodes[0x13] = Self::opcode_sgt; - opcodes[0x14] = Self::opcode_eq; - opcodes[0x15] = Self::opcode_iszero; - opcodes[0x16] = Self::opcode_and; - opcodes[0x17] = Self::opcode_or; - opcodes[0x18] = Self::opcode_xor; - opcodes[0x19] = Self::opcode_not; - opcodes[0x1A] = Self::opcode_byte; - opcodes[0x1B] = Self::opcode_shl; - opcodes[0x1C] = Self::opcode_shr; - opcodes[0x1D] = Self::opcode_sar; - - opcodes[0x20] = Self::opcode_sha3; - - opcodes[0x30] = Self::opcode_address; - opcodes[0x31] = Self::opcode_balance; - opcodes[0x32] = Self::opcode_origin; - opcodes[0x33] = Self::opcode_caller; - opcodes[0x34] = Self::opcode_callvalue; - opcodes[0x35] = Self::opcode_calldataload; - opcodes[0x36] = Self::opcode_calldatasize; - opcodes[0x37] = Self::opcode_calldatacopy; - opcodes[0x38] = Self::opcode_codesize; - opcodes[0x39] = Self::opcode_codecopy; - opcodes[0x3A] = Self::opcode_gasprice; - opcodes[0x3B] = Self::opcode_extcodesize; - opcodes[0x3C] = Self::opcode_extcodecopy; - opcodes[0x3D] = Self::opcode_returndatasize; - opcodes[0x3E] = Self::opcode_returndatacopy; - opcodes[0x3F] = Self::opcode_extcodehash; - opcodes[0x40] = Self::opcode_blockhash; - opcodes[0x41] = Self::opcode_coinbase; - opcodes[0x42] = Self::opcode_timestamp; - opcodes[0x43] = Self::opcode_number; - opcodes[0x44] = Self::opcode_difficulty; - opcodes[0x45] = Self::opcode_gaslimit; - opcodes[0x46] = Self::opcode_chainid; - opcodes[0x47] = Self::opcode_selfbalance; - opcodes[0x48] = Self::opcode_basefee; - - opcodes[0x50] = Self::opcode_pop; - opcodes[0x51] = Self::opcode_mload; - opcodes[0x52] = Self::opcode_mstore; - opcodes[0x53] = Self::opcode_mstore8; - opcodes[0x54] = Self::opcode_sload; - opcodes[0x55] = Self::opcode_sstore; - opcodes[0x56] = Self::opcode_jump; - opcodes[0x57] = Self::opcode_jumpi; - opcodes[0x58] = Self::opcode_pc; - opcodes[0x59] = Self::opcode_msize; - opcodes[0x5A] = Self::opcode_gas; - opcodes[0x5B] = Self::opcode_jumpdest; - - opcodes[0x5F] = Self::opcode_push_0; - opcodes[0x60] = Self::opcode_push_1; - opcodes[0x61] = Self::opcode_push_2_31::<2>; - opcodes[0x62] = Self::opcode_push_2_31::<3>; - opcodes[0x63] = Self::opcode_push_2_31::<4>; - opcodes[0x64] = Self::opcode_push_2_31::<5>; - opcodes[0x65] = Self::opcode_push_2_31::<6>; - opcodes[0x66] = Self::opcode_push_2_31::<7>; - opcodes[0x67] = Self::opcode_push_2_31::<8>; - opcodes[0x68] = Self::opcode_push_2_31::<9>; - opcodes[0x69] = Self::opcode_push_2_31::<10>; - opcodes[0x6A] = Self::opcode_push_2_31::<11>; - opcodes[0x6B] = Self::opcode_push_2_31::<12>; - opcodes[0x6C] = Self::opcode_push_2_31::<13>; - opcodes[0x6D] = Self::opcode_push_2_31::<14>; - opcodes[0x6E] = Self::opcode_push_2_31::<15>; - opcodes[0x6F] = Self::opcode_push_2_31::<16>; - opcodes[0x70] = Self::opcode_push_2_31::<17>; - opcodes[0x71] = Self::opcode_push_2_31::<18>; - opcodes[0x72] = Self::opcode_push_2_31::<19>; - opcodes[0x73] = Self::opcode_push_2_31::<20>; - opcodes[0x74] = Self::opcode_push_2_31::<21>; - opcodes[0x75] = Self::opcode_push_2_31::<22>; - opcodes[0x76] = Self::opcode_push_2_31::<23>; - opcodes[0x77] = Self::opcode_push_2_31::<24>; - opcodes[0x78] = Self::opcode_push_2_31::<25>; - opcodes[0x79] = Self::opcode_push_2_31::<26>; - opcodes[0x7A] = Self::opcode_push_2_31::<27>; - opcodes[0x7B] = Self::opcode_push_2_31::<28>; - opcodes[0x7C] = Self::opcode_push_2_31::<29>; - opcodes[0x7D] = Self::opcode_push_2_31::<30>; - opcodes[0x7E] = Self::opcode_push_2_31::<31>; - opcodes[0x7F] = Self::opcode_push_32; - - opcodes[0x80] = Self::opcode_dup_1_16::<1>; - opcodes[0x81] = Self::opcode_dup_1_16::<2>; - opcodes[0x82] = Self::opcode_dup_1_16::<3>; - opcodes[0x83] = Self::opcode_dup_1_16::<4>; - opcodes[0x84] = Self::opcode_dup_1_16::<5>; - opcodes[0x85] = Self::opcode_dup_1_16::<6>; - opcodes[0x86] = Self::opcode_dup_1_16::<7>; - opcodes[0x87] = Self::opcode_dup_1_16::<8>; - opcodes[0x88] = Self::opcode_dup_1_16::<9>; - opcodes[0x89] = Self::opcode_dup_1_16::<10>; - opcodes[0x8A] = Self::opcode_dup_1_16::<11>; - opcodes[0x8B] = Self::opcode_dup_1_16::<12>; - opcodes[0x8C] = Self::opcode_dup_1_16::<13>; - opcodes[0x8D] = Self::opcode_dup_1_16::<14>; - opcodes[0x8E] = Self::opcode_dup_1_16::<15>; - opcodes[0x8F] = Self::opcode_dup_1_16::<16>; - - opcodes[0x90] = Self::opcode_swap_1_16::<1>; - opcodes[0x91] = Self::opcode_swap_1_16::<2>; - opcodes[0x92] = Self::opcode_swap_1_16::<3>; - opcodes[0x93] = Self::opcode_swap_1_16::<4>; - opcodes[0x94] = Self::opcode_swap_1_16::<5>; - opcodes[0x95] = Self::opcode_swap_1_16::<6>; - opcodes[0x96] = Self::opcode_swap_1_16::<7>; - opcodes[0x97] = Self::opcode_swap_1_16::<8>; - opcodes[0x98] = Self::opcode_swap_1_16::<9>; - opcodes[0x99] = Self::opcode_swap_1_16::<10>; - opcodes[0x9A] = Self::opcode_swap_1_16::<11>; - opcodes[0x9B] = Self::opcode_swap_1_16::<12>; - opcodes[0x9C] = Self::opcode_swap_1_16::<13>; - opcodes[0x9D] = Self::opcode_swap_1_16::<14>; - opcodes[0x9E] = Self::opcode_swap_1_16::<15>; - opcodes[0x9F] = Self::opcode_swap_1_16::<16>; - - opcodes[0xA0] = Self::opcode_log_0_4::<0>; - opcodes[0xA1] = Self::opcode_log_0_4::<1>; - opcodes[0xA2] = Self::opcode_log_0_4::<2>; - opcodes[0xA3] = Self::opcode_log_0_4::<3>; - opcodes[0xA4] = Self::opcode_log_0_4::<4>; - - opcodes[0xF0] = Self::opcode_create; - opcodes[0xF1] = Self::opcode_call; - opcodes[0xF2] = Self::opcode_callcode; - opcodes[0xF3] = Self::opcode_return; - opcodes[0xF4] = Self::opcode_delegatecall; - opcodes[0xF5] = Self::opcode_create2; - - opcodes[0xFA] = Self::opcode_staticcall; - - opcodes[0xFD] = Self::opcode_revert; - opcodes[0xFE] = Self::opcode_invalid; - - opcodes[0xFF] = Self::opcode_selfdestruct; + const OPCODE_UNKNOWN: OpCode = ("", Self::opcode_unknown); + pub const OPCODES: [OpCode; 256] = { + let mut opcodes: [OpCode; 256] = [Self::OPCODE_UNKNOWN; 256]; + + opcodes[0x00] = ("STOP", Self::opcode_stop); + opcodes[0x01] = ("ADD", Self::opcode_add); + opcodes[0x02] = ("MUL", Self::opcode_mul); + opcodes[0x03] = ("SUB", Self::opcode_sub); + opcodes[0x04] = ("DIV", Self::opcode_div); + opcodes[0x05] = ("SDIV", Self::opcode_sdiv); + opcodes[0x06] = ("MOD", Self::opcode_mod); + opcodes[0x07] = ("SMOD", Self::opcode_smod); + opcodes[0x08] = ("ADDMOD", Self::opcode_addmod); + opcodes[0x09] = ("MULMOD", Self::opcode_mulmod); + opcodes[0x0A] = ("EXP", Self::opcode_exp); + opcodes[0x0B] = ("SIGNEXTEND", Self::opcode_signextend); + + opcodes[0x10] = ("LT", Self::opcode_lt); + opcodes[0x11] = ("GT", Self::opcode_gt); + opcodes[0x12] = ("SLT", Self::opcode_slt); + opcodes[0x13] = ("SGT", Self::opcode_sgt); + opcodes[0x14] = ("EQ", Self::opcode_eq); + opcodes[0x15] = ("ISZERO", Self::opcode_iszero); + opcodes[0x16] = ("AND", Self::opcode_and); + opcodes[0x17] = ("OR", Self::opcode_or); + opcodes[0x18] = ("XOR", Self::opcode_xor); + opcodes[0x19] = ("NOT", Self::opcode_not); + opcodes[0x1A] = ("BYTE", Self::opcode_byte); + opcodes[0x1B] = ("SHL", Self::opcode_shl); + opcodes[0x1C] = ("SHR", Self::opcode_shr); + opcodes[0x1D] = ("SAR", Self::opcode_sar); + + opcodes[0x20] = ("KECCAK256", Self::opcode_sha3); + + opcodes[0x30] = ("ADDRESS", Self::opcode_address); + opcodes[0x31] = ("BALANCE", Self::opcode_balance); + opcodes[0x32] = ("ORIGIN", Self::opcode_origin); + opcodes[0x33] = ("CALLER", Self::opcode_caller); + opcodes[0x34] = ("CALLVALUE", Self::opcode_callvalue); + opcodes[0x35] = ("CALLDATALOAD", Self::opcode_calldataload); + opcodes[0x36] = ("CALLDATASIZE", Self::opcode_calldatasize); + opcodes[0x37] = ("CALLDATACOPY", Self::opcode_calldatacopy); + opcodes[0x38] = ("CODESIZE", Self::opcode_codesize); + opcodes[0x39] = ("CODECOPY", Self::opcode_codecopy); + opcodes[0x3A] = ("GASPRICE", Self::opcode_gasprice); + opcodes[0x3B] = ("EXTCODESIZE", Self::opcode_extcodesize); + opcodes[0x3C] = ("EXTCODECOPY", Self::opcode_extcodecopy); + opcodes[0x3D] = ("RETURNDATASIZE", Self::opcode_returndatasize); + opcodes[0x3E] = ("RETURNDATACOPY", Self::opcode_returndatacopy); + opcodes[0x3F] = ("EXTCODEHASH", Self::opcode_extcodehash); + opcodes[0x40] = ("BLOCKHASH", Self::opcode_blockhash); + opcodes[0x41] = ("COINBASE", Self::opcode_coinbase); + opcodes[0x42] = ("TIMESTAMP", Self::opcode_timestamp); + opcodes[0x43] = ("NUMBER", Self::opcode_number); + opcodes[0x44] = ("PREVRANDAO", Self::opcode_difficulty); + opcodes[0x45] = ("GASLIMIT", Self::opcode_gaslimit); + opcodes[0x46] = ("CHAINID", Self::opcode_chainid); + opcodes[0x47] = ("SELFBALANCE", Self::opcode_selfbalance); + opcodes[0x48] = ("BASEFEE", Self::opcode_basefee); + + opcodes[0x50] = ("POP", Self::opcode_pop); + opcodes[0x51] = ("MLOAD", Self::opcode_mload); + opcodes[0x52] = ("MSTORE", Self::opcode_mstore); + opcodes[0x53] = ("MSTORE8", Self::opcode_mstore8); + opcodes[0x54] = ("SLOAD", Self::opcode_sload); + opcodes[0x55] = ("SSTORE", Self::opcode_sstore); + opcodes[0x56] = ("JUMP", Self::opcode_jump); + opcodes[0x57] = ("JUMPI", Self::opcode_jumpi); + opcodes[0x58] = ("PC", Self::opcode_pc); + opcodes[0x59] = ("MSIZE", Self::opcode_msize); + opcodes[0x5A] = ("GAS", Self::opcode_gas); + opcodes[0x5B] = ("JUMPDEST", Self::opcode_jumpdest); + + opcodes[0x5F] = ("PUSH0", Self::opcode_push_0); + opcodes[0x60] = ("PUSH1", Self::opcode_push_1); + opcodes[0x61] = ("PUSH2", Self::opcode_push_2_31::<2>); + opcodes[0x62] = ("PUSH3", Self::opcode_push_2_31::<3>); + opcodes[0x63] = ("PUSH4", Self::opcode_push_2_31::<4>); + opcodes[0x64] = ("PUSH5", Self::opcode_push_2_31::<5>); + opcodes[0x65] = ("PUSH6", Self::opcode_push_2_31::<6>); + opcodes[0x66] = ("PUSH7", Self::opcode_push_2_31::<7>); + opcodes[0x67] = ("PUSH8", Self::opcode_push_2_31::<8>); + opcodes[0x68] = ("PUSH9", Self::opcode_push_2_31::<9>); + opcodes[0x69] = ("PUSH10", Self::opcode_push_2_31::<10>); + opcodes[0x6A] = ("PUSH11", Self::opcode_push_2_31::<11>); + opcodes[0x6B] = ("PUSH12", Self::opcode_push_2_31::<12>); + opcodes[0x6C] = ("PUSH13", Self::opcode_push_2_31::<13>); + opcodes[0x6D] = ("PUSH14", Self::opcode_push_2_31::<14>); + opcodes[0x6E] = ("PUSH15", Self::opcode_push_2_31::<15>); + opcodes[0x6F] = ("PUSH16", Self::opcode_push_2_31::<16>); + opcodes[0x70] = ("PUSH17", Self::opcode_push_2_31::<17>); + opcodes[0x71] = ("PUSH18", Self::opcode_push_2_31::<18>); + opcodes[0x72] = ("PUSH19", Self::opcode_push_2_31::<19>); + opcodes[0x73] = ("PUSH20", Self::opcode_push_2_31::<20>); + opcodes[0x74] = ("PUSH21", Self::opcode_push_2_31::<21>); + opcodes[0x75] = ("PUSH22", Self::opcode_push_2_31::<22>); + opcodes[0x76] = ("PUSH23", Self::opcode_push_2_31::<23>); + opcodes[0x77] = ("PUSH24", Self::opcode_push_2_31::<24>); + opcodes[0x78] = ("PUSH25", Self::opcode_push_2_31::<25>); + opcodes[0x79] = ("PUSH26", Self::opcode_push_2_31::<26>); + opcodes[0x7A] = ("PUSH27", Self::opcode_push_2_31::<27>); + opcodes[0x7B] = ("PUSH28", Self::opcode_push_2_31::<28>); + opcodes[0x7C] = ("PUSH29", Self::opcode_push_2_31::<29>); + opcodes[0x7D] = ("PUSH30", Self::opcode_push_2_31::<30>); + opcodes[0x7E] = ("PUSH31", Self::opcode_push_2_31::<31>); + opcodes[0x7F] = ("PUSH32", Self::opcode_push_32); + + opcodes[0x80] = ("DUP1", Self::opcode_dup_1_16::<1>); + opcodes[0x81] = ("DUP2", Self::opcode_dup_1_16::<2>); + opcodes[0x82] = ("DUP3", Self::opcode_dup_1_16::<3>); + opcodes[0x83] = ("DUP4", Self::opcode_dup_1_16::<4>); + opcodes[0x84] = ("DUP5", Self::opcode_dup_1_16::<5>); + opcodes[0x85] = ("DUP6", Self::opcode_dup_1_16::<6>); + opcodes[0x86] = ("DUP7", Self::opcode_dup_1_16::<7>); + opcodes[0x87] = ("DUP8", Self::opcode_dup_1_16::<8>); + opcodes[0x88] = ("DUP9", Self::opcode_dup_1_16::<9>); + opcodes[0x89] = ("DUP10", Self::opcode_dup_1_16::<10>); + opcodes[0x8A] = ("DUP11", Self::opcode_dup_1_16::<11>); + opcodes[0x8B] = ("DUP12", Self::opcode_dup_1_16::<12>); + opcodes[0x8C] = ("DUP13", Self::opcode_dup_1_16::<13>); + opcodes[0x8D] = ("DUP14", Self::opcode_dup_1_16::<14>); + opcodes[0x8E] = ("DUP15", Self::opcode_dup_1_16::<15>); + opcodes[0x8F] = ("DUP16", Self::opcode_dup_1_16::<16>); + + opcodes[0x90] = ("SWAP1", Self::opcode_swap_1_16::<1>); + opcodes[0x91] = ("SWAP2", Self::opcode_swap_1_16::<2>); + opcodes[0x92] = ("SWAP3", Self::opcode_swap_1_16::<3>); + opcodes[0x93] = ("SWAP4", Self::opcode_swap_1_16::<4>); + opcodes[0x94] = ("SWAP5", Self::opcode_swap_1_16::<5>); + opcodes[0x95] = ("SWAP6", Self::opcode_swap_1_16::<6>); + opcodes[0x96] = ("SWAP7", Self::opcode_swap_1_16::<7>); + opcodes[0x97] = ("SWAP8", Self::opcode_swap_1_16::<8>); + opcodes[0x98] = ("SWAP9", Self::opcode_swap_1_16::<9>); + opcodes[0x99] = ("SWAP10", Self::opcode_swap_1_16::<10>); + opcodes[0x9A] = ("SWAP11", Self::opcode_swap_1_16::<11>); + opcodes[0x9B] = ("SWAP12", Self::opcode_swap_1_16::<12>); + opcodes[0x9C] = ("SWAP13", Self::opcode_swap_1_16::<13>); + opcodes[0x9D] = ("SWAP14", Self::opcode_swap_1_16::<14>); + opcodes[0x9E] = ("SWAP15", Self::opcode_swap_1_16::<15>); + opcodes[0x9F] = ("SWAP16", Self::opcode_swap_1_16::<16>); + + opcodes[0xA0] = ("LOG0", Self::opcode_log_0_4::<0>); + opcodes[0xA1] = ("LOG1", Self::opcode_log_0_4::<1>); + opcodes[0xA2] = ("LOG2", Self::opcode_log_0_4::<2>); + opcodes[0xA3] = ("LOG3", Self::opcode_log_0_4::<3>); + opcodes[0xA4] = ("LOG4", Self::opcode_log_0_4::<4>); + + opcodes[0xF0] = ("CREATE", Self::opcode_create); + opcodes[0xF1] = ("CALL", Self::opcode_call); + opcodes[0xF2] = ("CALLCODE", Self::opcode_callcode); + opcodes[0xF3] = ("RETURN", Self::opcode_return); + opcodes[0xF4] = ("DELEGATECALL", Self::opcode_delegatecall); + opcodes[0xF5] = ("CREATE2", Self::opcode_create2); + + opcodes[0xFA] = ("STATICCALL", Self::opcode_staticcall); + + opcodes[0xFD] = ("REVERT", Self::opcode_revert); + opcodes[0xFE] = ("INVALID", Self::opcode_invalid); + + opcodes[0xFF] = ("SELFDESTRUCT", Self::opcode_selfdestruct); opcodes }; diff --git a/evm_loader/program/src/evm/stack.rs b/evm_loader/program/src/evm/stack.rs index 1181fe5fa..8b7eb2af1 100644 --- a/evm_loader/program/src/evm/stack.rs +++ b/evm_loader/program/src/evm/stack.rs @@ -8,9 +8,7 @@ use std::{ use ethnum::{I256, U256}; #[cfg(feature = "tracing")] -use crate::evm::tracing::event_listener::tracer::TracerType; -#[cfg(feature = "tracing")] -use crate::evm::tracing::EventListener; +use crate::evm::tracing::TracerTypeOpt; use crate::{error::Error, types::Address}; use super::tracing_event; @@ -23,11 +21,11 @@ pub struct Stack { end: *mut u8, top: *mut u8, #[cfg(feature = "tracing")] - tracer: TracerType, + tracer: TracerTypeOpt, } impl Stack { - pub fn new(#[cfg(feature = "tracing")] tracer: TracerType) -> Self { + pub fn new(#[cfg(feature = "tracing")] tracer: TracerTypeOpt) -> Self { let (begin, end) = unsafe { let layout = Layout::from_size_align_unchecked(STACK_SIZE, ELEMENT_SIZE); let begin = crate::allocator::EVM.alloc(layout); diff --git a/evm_loader/program/src/evm/tracing/event_listener/listener_tracer.rs b/evm_loader/program/src/evm/tracing/event_listener/listener_tracer.rs deleted file mode 100644 index 23b067396..000000000 --- a/evm_loader/program/src/evm/tracing/event_listener/listener_tracer.rs +++ /dev/null @@ -1,35 +0,0 @@ -use super::tracer::Tracer; -use crate::evm::tracing::event_listener::trace::FullTraceData; - -pub trait ListenerTracer { - fn begin_step(&mut self, stack: Vec<[u8; 32]>, memory: Vec); - fn end_step(&mut self, return_data: Option>); -} - -impl ListenerTracer for Tracer { - fn begin_step(&mut self, stack: Vec<[u8; 32]>, memory: Vec) { - let storage = self - .data - .last() - .map(|d| d.storage.clone()) - .unwrap_or_default(); - - self.data.push(FullTraceData { - stack, - memory, - storage, - return_data: None, - }); - } - - fn end_step(&mut self, return_data: Option>) { - let data = self - .data - .last_mut() - .expect("No data were pushed in `begin_step`"); - data.return_data = return_data; - if let Some((index, value)) = self.vm.step_diff().storage_access { - data.storage.insert(index, value); - } - } -} diff --git a/evm_loader/program/src/evm/tracing/event_listener/listener_vm_tracer.rs b/evm_loader/program/src/evm/tracing/event_listener/listener_vm_tracer.rs deleted file mode 100644 index e5e72ec03..000000000 --- a/evm_loader/program/src/evm/tracing/event_listener/listener_vm_tracer.rs +++ /dev/null @@ -1,70 +0,0 @@ -use crate::evm::tracing::event_listener::trace::{MemoryDiff, StorageDiff, VMTracer}; -use crate::evm::{Context, ExitStatus}; -use ethnum::U256; - -use super::vm_tracer::VmTracer; - -pub trait ListenerVmTracer { - fn begin_vm(&mut self, context: Context, code: Vec); - fn end_vm(&mut self, status: ExitStatus); - fn begin_step(&mut self, opcode: u8, pc: usize); - fn end_step(&mut self, gas_used: u64); - fn storage_access(&mut self, index: U256, value: [u8; 32]); - fn storage_set(&mut self, index: U256, value: [u8; 32]); - fn stack_push(&mut self, value: [u8; 32]); - fn memory_set(&mut self, offset: usize, data: Vec); -} - -impl ListenerVmTracer for VmTracer { - fn begin_vm(&mut self, _context: Context, code: Vec) { - self.push_step_diff(); - - self.tracer.prepare_subtrace(code); - } - - fn end_vm(&mut self, _status: ExitStatus) { - self.pop_step_diff(); - - self.tracer.done_subtrace(); - } - - fn begin_step(&mut self, opcode: u8, pc: usize) { - let diff = self.step_diff(); - diff.stack_push.clear(); - diff.memory_set = None; - diff.storage_set = None; - diff.storage_access = None; - - self.tracer.trace_prepare_execute(pc, opcode); - } - - fn end_step(&mut self, gas_used: u64) { - let gas_used = U256::from(gas_used); - let diff = self.step_diff().clone(); - - self.tracer - .trace_executed(gas_used, diff.stack_push, diff.memory_set, diff.storage_set); - } - - fn storage_access(&mut self, index: U256, value: [u8; 32]) { - self.step_diff().storage_access = Some((index, value)); - } - - fn storage_set(&mut self, index: U256, value: [u8; 32]) { - self.step_diff().storage_set = Some(StorageDiff { - location: index, - value, - }); - } - - fn stack_push(&mut self, value: [u8; 32]) { - self.step_diff().stack_push.push(value); - } - - fn memory_set(&mut self, offset: usize, data: Vec) { - self.step_diff().memory_set = Some(MemoryDiff { - offset, - data: data.into(), - }); - } -} diff --git a/evm_loader/program/src/evm/tracing/event_listener/mod.rs b/evm_loader/program/src/evm/tracing/event_listener/mod.rs deleted file mode 100644 index e61e5dc2d..000000000 --- a/evm_loader/program/src/evm/tracing/event_listener/mod.rs +++ /dev/null @@ -1,54 +0,0 @@ -mod listener_tracer; -mod listener_vm_tracer; -#[allow(clippy::all)] -pub mod trace; -pub mod tracer; -mod vm_tracer; - -use crate::evm::tracing::{Event, EventListener}; -use {listener_tracer::ListenerTracer, listener_vm_tracer::ListenerVmTracer, tracer::Tracer}; - -impl EventListener for Tracer { - fn enable_return_data(&self) -> bool { - self.enable_return_data - } - - fn event(&mut self, event: Event) { - match event { - Event::BeginVM { context, code } => { - self.vm.begin_vm(context, code); - } - Event::EndVM { status } => { - self.vm.end_vm(status); - } - Event::BeginStep { - opcode, - pc, - stack, - memory, - } => { - self.begin_step(stack, memory); - self.vm.begin_step(opcode, pc); - } - Event::EndStep { - gas_used, - return_data, - } => { - self.end_step(return_data); - self.vm.end_step(gas_used); - } - Event::StackPush { value } => { - self.vm.stack_push(value); - } - Event::MemorySet { offset, data } => { - self.vm.memory_set(offset, data); - } - Event::StorageSet { index, value } => { - self.vm.storage_set(index, value); - } - Event::StorageAccess { index, value } => { - self.vm.storage_access(index, value); - } - }; - } -} diff --git a/evm_loader/program/src/evm/tracing/event_listener/trace.rs b/evm_loader/program/src/evm/tracing/event_listener/trace.rs deleted file mode 100644 index 9b68c6372..000000000 --- a/evm_loader/program/src/evm/tracing/event_listener/trace.rs +++ /dev/null @@ -1,307 +0,0 @@ -use crate::account::EthereumAccount; -use crate::types::hexbytes::HexBytes; -use crate::types::Address; -use serde::{Deserialize, Serialize}; -use std::fmt::{Display, Formatter}; -use {ethnum::U256, std::collections::HashMap}; - -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq /*, RlpEncodable, RlpDecodable */)] -/// A diff of some chunk of memory. -pub struct MemoryDiff { - /// Offset into memory the change begins. - pub offset: usize, - /// The changed data. - pub data: HexBytes, -} - -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq /*, RlpEncodable, RlpDecodable */)] -/// A diff of some storage value. -pub struct StorageDiff { - /// Which key in storage is changed. - pub location: U256, - /// What the value has been changed to. - pub value: [u8; 32], -} - -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq /*, RlpEncodable, RlpDecodable */)] -/// A record of an executed VM operation. -pub struct VMExecutedOperation { - /// The total gas used. - pub gas_used: U256, - /// The stack item placed, if any. - pub stack_push: Vec<[u8; 32]>, - /// If altered, the memory delta. - pub mem_diff: Option, - /// The altered storage value, if any. - pub store_diff: Option, -} - -#[derive( - Serialize, Deserialize, Debug, Clone, PartialEq, Default /*, RlpEncodable, RlpDecodable */, -)] -/// A record of the execution of a single VM operation. -pub struct VMOperation { - /// The program counter. - pub pc: usize, - /// The instruction executed. - pub instruction: u8, - /// The gas cost for this instruction. - pub gas_cost: U256, - /// Information concerning the execution of the operation. - pub executed: Option, -} - -#[derive( - Serialize, Deserialize, Debug, Clone, PartialEq, Default /*, RlpEncodable, RlpDecodable */, -)] -/// A record of a full VM trace for a CALL/CREATE. -#[allow(clippy::module_name_repetitions)] -pub struct VMTrace { - /// The step (i.e. index into operations) at which this trace corresponds. - pub parent_step: usize, - /// The code to be executed. - pub code: HexBytes, - /// The operations executed. - pub operations: Vec, - /// The sub traces for each interior action performed as part of this call/create. - /// Thre is a 1:1 correspondance between these and a CALL/CREATE/CALLCODE/DELEGATECALL instruction. - pub subs: Vec, -} - -// OpenEthereum tracer ethcore/trace/src/executive_tracer.rs -#[derive(Debug)] -#[allow(clippy::module_name_repetitions)] -pub struct TraceData { - pub mem_written: Option<(usize, usize)>, - pub store_written: Option<(U256, [u8; 32])>, -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct FullTraceData { - pub stack: Vec<[u8; 32]>, - pub memory: Vec, - pub storage: HashMap, - pub return_data: Option>, -} - -/// Simple VM tracer. Traces all operations. -#[derive(Debug)] -pub struct ExecutiveVMTracer { - data: VMTrace, - pub depth: usize, - trace_stack: Vec, -} - -impl ExecutiveVMTracer { - /// Create a new top-level instance. - #[must_use] - pub fn toplevel() -> Self { - ExecutiveVMTracer { - data: VMTrace { - parent_step: 0, - code: HexBytes::default(), - operations: vec![VMOperation::default()], // prefill with a single entry so that prepare_subtrace can get the parent_step - subs: vec![], - }, - depth: 0, - trace_stack: vec![], - } - } - - fn with_trace_in_depth(trace: &mut VMTrace, depth: usize, f: F) { - if depth == 0 { - f(trace); - } else { - Self::with_trace_in_depth(trace.subs.last_mut().expect("self.depth is incremented with prepare_subtrace; a subtrace is always pushed; self.depth cannot be greater than subtrace stack; qed"), depth - 1, f); - } - } -} - -impl VMTracer for ExecutiveVMTracer { - type Output = VMTrace; - - fn trace_prepare_execute(&mut self, pc: usize, instruction: u8) { - Self::with_trace_in_depth(&mut self.data, self.depth, move |trace| { - trace.operations.push(VMOperation { - pc, - instruction, - gas_cost: U256::ZERO, - executed: None, - }); - }); - } - - fn trace_executed( - &mut self, - gas_used: U256, - stack_push: Vec<[u8; 32]>, - mem_diff: Option, - store_diff: Option, - ) { - self.trace_stack.push(TraceData { - mem_written: mem_diff.as_ref().map(|d| (d.offset, d.data.len())), - store_written: store_diff.as_ref().map(|d| (d.location, d.value)), - }); - - Self::with_trace_in_depth(&mut self.data, self.depth, move |trace| { - let operation = trace.operations.last_mut().expect("trace_executed is always called after a trace_prepare_execute; trace.operations cannot be empty; qed"); - operation.executed = Some(VMExecutedOperation { - gas_used, - stack_push, - mem_diff, - store_diff, - }); - }); - } - - fn prepare_subtrace(&mut self, code: Vec) { - Self::with_trace_in_depth(&mut self.data, self.depth, move |trace| { - let parent_step = trace.operations.len() - 1; // won't overflow since we must already have pushed an operation in trace_prepare_execute. - trace.subs.push(VMTrace { - parent_step, - code: code.into(), - operations: vec![], - subs: vec![], - }); - }); - self.depth += 1; - } - - fn done_subtrace(&mut self) { - self.depth -= 1; - } - - fn drain(mut self) -> Option { - self.data.subs.pop() - } -} - -// ethcore/src/trace/mod.rs -pub trait VMTracer: Send { - /// Data returned when draining the `VMTracer`. - type Output; - - /// Trace the preparation to execute a single valid instruction. - fn trace_prepare_execute(&mut self, _pc: usize, _instruction: u8) {} - - /// Trace the finalised execution of a single valid instruction. - fn trace_executed( - &mut self, - _gas_used: U256, - _stack_push: Vec<[u8; 32]>, - _mem_diff: Option, - _storage_diff: Option, - ) { - } - - /// Spawn subtracer which will be used to trace deeper levels of execution. - fn prepare_subtrace(&mut self, _code: Vec) {} - - /// Finalize subtracer. - fn done_subtrace(&mut self) {} - - /// Consumes self and returns the VM trace. - fn drain(self) -> Option; -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct TracedCall { - pub vm_trace: Option, - pub full_trace_data: Vec, - pub used_gas: u64, - pub result: Vec, - pub exit_status: String, -} - -impl Display for TracedCall { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!( - f, - "{{ exit_status: {}, used_gas: {}, vm_trace: {}, full_trace_data: {}, result: {} }}", - self.exit_status, - self.used_gas, - if self.vm_trace.is_some() { "yes" } else { "no" }, - self.full_trace_data.len(), - hex::encode(&self.result), - ) - } -} - -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct BlockOverrides { - pub number: Option, - #[allow(unused)] - pub difficulty: Option, // NOT SUPPORTED by Neon EVM - pub time: Option, - #[allow(unused)] - pub gas_limit: Option, // NOT SUPPORTED BY Neon EVM - #[allow(unused)] - pub coinbase: Option
, // NOT SUPPORTED BY Neon EVM - #[allow(unused)] - pub random: Option, // NOT SUPPORTED BY Neon EVM - #[allow(unused)] - pub base_fee: Option, // NOT SUPPORTED BY Neon EVM -} - -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct AccountOverride { - pub nonce: Option, - pub code: Option, - pub balance: Option, - pub state: Option>, - pub state_diff: Option>, -} - -impl AccountOverride { - pub fn apply(&self, ether_account: &mut EthereumAccount) { - if let Some(nonce) = self.nonce { - ether_account.trx_count = nonce; - } - if let Some(balance) = self.balance { - ether_account.balance = U256::from(balance); - } - #[allow(clippy::cast_possible_truncation)] - if let Some(code) = &self.code { - ether_account.code_size = code.len() as u32; - } - } -} - -pub type AccountOverrides = HashMap; - -#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)] -#[serde(rename_all = "camelCase")] -#[allow(clippy::module_name_repetitions, clippy::struct_excessive_bools)] -pub struct TraceConfig { - #[serde(default)] - pub enable_memory: bool, - #[serde(default)] - pub disable_storage: bool, - #[serde(default)] - pub disable_stack: bool, - #[serde(default)] - pub enable_return_data: bool, - pub tracer: Option, - pub timeout: Option, -} - -#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)] -#[serde(rename_all = "camelCase")] -#[allow(clippy::module_name_repetitions)] -pub struct TraceCallConfig { - #[serde(flatten)] - pub trace_config: TraceConfig, - pub block_overrides: Option, - pub state_overrides: Option, -} - -impl From for TraceCallConfig { - fn from(trace_config: TraceConfig) -> Self { - Self { - trace_config, - ..Self::default() - } - } -} diff --git a/evm_loader/program/src/evm/tracing/event_listener/tracer.rs b/evm_loader/program/src/evm/tracing/event_listener/tracer.rs deleted file mode 100644 index 153e33fc9..000000000 --- a/evm_loader/program/src/evm/tracing/event_listener/tracer.rs +++ /dev/null @@ -1,31 +0,0 @@ -use std::sync::{Arc, RwLock}; - -use crate::evm::tracing::event_listener::trace::{FullTraceData, VMTrace, VMTracer}; - -use super::vm_tracer::VmTracer; - -pub type TracerType = Option>>; - -#[derive(Debug)] -pub struct Tracer { - pub vm: VmTracer, - pub data: Vec, - pub enable_return_data: bool, -} - -impl Tracer { - #[must_use] - pub fn new(enable_return_data: bool) -> Self { - Tracer { - vm: VmTracer::init(), - data: vec![], - enable_return_data, - } - } - - #[must_use] - pub fn into_traces(self) -> (Option, Vec) { - let vm = self.vm.tracer.drain(); - (vm, self.data) - } -} diff --git a/evm_loader/program/src/evm/tracing/event_listener/vm_tracer.rs b/evm_loader/program/src/evm/tracing/event_listener/vm_tracer.rs deleted file mode 100644 index bb2861411..000000000 --- a/evm_loader/program/src/evm/tracing/event_listener/vm_tracer.rs +++ /dev/null @@ -1,39 +0,0 @@ -use crate::evm::tracing::event_listener::trace::{ExecutiveVMTracer, MemoryDiff, StorageDiff}; -use ethnum::U256; - -#[derive(Debug, Default, Clone)] -pub struct StepDiff { - pub storage_access: Option<(U256, [u8; 32])>, - pub storage_set: Option, - pub memory_set: Option, - pub stack_push: Vec<[u8; 32]>, -} - -#[derive(Debug)] -pub struct VmTracer { - pub tracer: ExecutiveVMTracer, - step_diff: Vec, -} - -impl VmTracer { - pub fn init() -> Self { - VmTracer { - tracer: ExecutiveVMTracer::toplevel(), - step_diff: Vec::new(), - } - } - - pub fn push_step_diff(&mut self) { - self.step_diff.push(StepDiff::default()); - } - - pub fn pop_step_diff(&mut self) { - self.step_diff.pop(); - } - - pub fn step_diff(&mut self) -> &mut StepDiff { - self.step_diff - .last_mut() - .expect("diff was pushed in begin_vm") - } -} diff --git a/evm_loader/program/src/evm/tracing/mod.rs b/evm_loader/program/src/evm/tracing/mod.rs index cfd02f75a..024e7d3ed 100644 --- a/evm_loader/program/src/evm/tracing/mod.rs +++ b/evm_loader/program/src/evm/tracing/mod.rs @@ -1,15 +1,35 @@ -use super::{Context, ExitStatus}; +use std::collections::HashMap; +use std::fmt::Debug; +use std::sync::{Arc, RwLock}; + +use crate::account::EthereumAccount; +use crate::executor::Action; +use crate::types::hexbytes::HexBytes; +use crate::types::Address; use ethnum::U256; +use serde_json::Value; + +use super::{Context, ExitStatus}; -pub mod event_listener; +pub mod tracers; -pub trait EventListener { - fn enable_return_data(&self) -> bool; +#[derive(Debug, Clone)] +pub struct EmulationResult { + pub exit_status: ExitStatus, + pub steps_executed: u64, + pub used_gas: u64, + pub actions: Vec, +} + +pub trait EventListener: Send + Sync + Debug { fn event(&mut self, event: Event); + fn into_traces(self: Box, emulation_result: EmulationResult) -> Value; } +pub type TracerType = Arc>>; +pub type TracerTypeOpt = Option; + /// Trace event -#[derive(Debug, Clone)] pub enum Event { BeginVM { context: Context, @@ -44,3 +64,83 @@ pub enum Event { value: [u8; 32], }, } + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct BlockOverrides { + pub number: Option, + #[allow(unused)] + pub difficulty: Option, // NOT SUPPORTED by Neon EVM + pub time: Option, + #[allow(unused)] + pub gas_limit: Option, // NOT SUPPORTED BY Neon EVM + #[allow(unused)] + pub coinbase: Option
, // NOT SUPPORTED BY Neon EVM + #[allow(unused)] + pub random: Option, // NOT SUPPORTED BY Neon EVM + #[allow(unused)] + pub base_fee: Option, // NOT SUPPORTED BY Neon EVM +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct AccountOverride { + pub nonce: Option, + pub code: Option, + pub balance: Option, + pub state: Option>, + pub state_diff: Option>, +} + +impl AccountOverride { + pub fn apply(&self, ether_account: &mut EthereumAccount) { + if let Some(nonce) = self.nonce { + ether_account.trx_count = nonce; + } + if let Some(balance) = self.balance { + ether_account.balance = balance; + } + #[allow(clippy::cast_possible_truncation)] + if let Some(code) = &self.code { + ether_account.code_size = code.len() as u32; + } + } +} + +pub type AccountOverrides = HashMap; + +#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "camelCase")] +#[allow(clippy::module_name_repetitions, clippy::struct_excessive_bools)] +pub struct TraceConfig { + #[serde(default)] + pub enable_memory: bool, + #[serde(default)] + pub disable_storage: bool, + #[serde(default)] + pub disable_stack: bool, + #[serde(default)] + pub enable_return_data: bool, + pub tracer: Option, + pub timeout: Option, + pub tracer_config: Value, +} + +#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "camelCase")] +#[allow(clippy::module_name_repetitions)] +pub struct TraceCallConfig { + #[serde(flatten)] + pub trace_config: TraceConfig, + pub block_overrides: Option, + pub state_overrides: Option, +} + +impl From for TraceCallConfig { + fn from(trace_config: TraceConfig) -> Self { + Self { + trace_config, + ..Self::default() + } + } +} diff --git a/evm_loader/program/src/evm/tracing/tracers/mod.rs b/evm_loader/program/src/evm/tracing/tracers/mod.rs new file mode 100644 index 000000000..3913a3061 --- /dev/null +++ b/evm_loader/program/src/evm/tracing/tracers/mod.rs @@ -0,0 +1,20 @@ +use crate::evm::tracing::tracers::struct_logger::StructLogger; +use crate::evm::tracing::TraceConfig; +use crate::evm::tracing::TracerType; +use std::sync::{Arc, RwLock}; + +pub mod struct_logger; + +pub fn new_tracer(trace_config: &TraceConfig) -> crate::error::Result { + Ok(Arc::new(RwLock::new( + match trace_config.tracer.as_deref() { + None | Some("") => Box::new(StructLogger::new(trace_config)), + _ => { + return Err(crate::error::Error::Custom(format!( + "Unsupported tracer: {:?}", + trace_config.tracer + ))) + } + }, + ))) +} diff --git a/evm_loader/program/src/evm/tracing/tracers/struct_logger.rs b/evm_loader/program/src/evm/tracing/tracers/struct_logger.rs new file mode 100644 index 000000000..6b5380e9b --- /dev/null +++ b/evm_loader/program/src/evm/tracing/tracers/struct_logger.rs @@ -0,0 +1,221 @@ +use std::collections::BTreeMap; + +use ethnum::U256; +use serde::Serialize; +use serde_json::Value; + +use crate::account_storage::ProgramAccountStorage; +use crate::evm::tracing::TraceConfig; +use crate::evm::tracing::{EmulationResult, Event, EventListener}; +use crate::evm::Machine; +use crate::executor::ExecutorState; +use crate::types::hexbytes::HexBytes; + +/// `StructLoggerResult` groups all structured logs emitted by the EVM +/// while replaying a transaction in debug mode as well as transaction +/// execution status, the amount of gas used and the return value +#[derive(Serialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct StructLoggerResult { + /// Is execution failed or not + pub failed: bool, + /// Total used gas but include the refunded gas + pub gas: u64, + /// The data after execution or revert reason + pub return_value: String, + /// Logs emitted during execution + pub struct_logs: Vec, +} + +/// `StructLog` stores a structured log emitted by the EVM while replaying a +/// transaction in debug mode +#[derive(Serialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct StructLog { + /// Program counter. + pc: u64, + /// Operation name + op: &'static str, + /// Amount of used gas + gas: Option, + /// Gas cost for this instruction. + gas_cost: u64, + /// Current depth + depth: usize, + /// Snapshot of the current memory sate + #[serde(skip_serializing_if = "Option::is_none")] + memory: Option>, // U256 sized chunks + /// Snapshot of the current stack sate + #[serde(skip_serializing_if = "Option::is_none")] + stack: Option>, + /// Result of the step + return_data: Option, + /// Snapshot of the current storage + #[serde(skip_serializing_if = "Option::is_none")] + storage: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + error: Option, +} + +impl StructLog { + #[must_use] + pub fn new( + opcode: u8, + pc: u64, + gas_cost: u64, + depth: usize, + memory: Option>, + stack: Option>, + storage: Option>, + ) -> Self { + let (op, _) = Machine::>::OPCODES[opcode as usize]; + Self { + pc, + op, + gas: None, + gas_cost, + depth, + memory, + stack, + return_data: None, + storage, + error: None, + } + } +} + +#[derive(Debug)] +#[allow(clippy::struct_excessive_bools)] +struct Config { + enable_memory: bool, + disable_storage: bool, + disable_stack: bool, + enable_return_data: bool, +} + +impl From<&TraceConfig> for Config { + fn from(trace_config: &TraceConfig) -> Self { + Self { + enable_memory: trace_config.enable_memory, + disable_storage: trace_config.disable_storage, + disable_stack: trace_config.disable_stack, + enable_return_data: trace_config.enable_return_data, + } + } +} + +#[derive(Debug)] +pub struct StructLogger { + config: Config, + logs: Vec, + depth: usize, + storage_access: Option<(U256, U256)>, +} + +impl StructLogger { + #[must_use] + pub fn new(trace_config: &TraceConfig) -> Self { + StructLogger { + config: trace_config.into(), + logs: vec![], + depth: 0, + storage_access: None, + } + } +} + +impl EventListener for StructLogger { + fn event(&mut self, event: Event) { + match event { + Event::BeginVM { .. } => { + self.depth += 1; + } + Event::EndVM { .. } => { + self.depth -= 1; + } + Event::BeginStep { + opcode, + pc, + stack, + memory, + } => { + let stack = if self.config.disable_stack { + None + } else { + Some( + stack + .iter() + .map(|entry| U256::from_be_bytes(*entry)) + .collect(), + ) + }; + + let memory = if !self.config.enable_memory || memory.is_empty() { + None + } else { + Some( + memory + .chunks(32) + .map(|slice| slice.to_vec().into()) + .collect(), + ) + }; + + let storage = if self.config.disable_storage { + None + } else { + self.logs + .last() + .and_then(|log| log.storage.clone()) + .or(None) + }; + + let log = StructLog::new(opcode, pc as u64, 0, self.depth, memory, stack, storage); + self.logs.push(log); + } + Event::EndStep { + gas_used, + return_data, + } => { + let last = self + .logs + .last_mut() + .expect("`EndStep` event before `BeginStep`"); + last.gas = Some(gas_used); + if !self.config.disable_storage { + if let Some((index, value)) = self.storage_access.take() { + last.storage + .get_or_insert_with(Default::default) + .insert(index, value); + }; + } + if self.config.enable_return_data { + last.return_data = return_data.map(Into::into); + } + } + Event::StorageAccess { index, value } if !self.config.disable_storage => { + self.storage_access = Some((index, U256::from_be_bytes(value))); + } + _ => (), + }; + } + + fn into_traces(self: Box, emulation_result: EmulationResult) -> Value { + let result = StructLoggerResult { + failed: !emulation_result + .exit_status + .is_succeed() + .expect("Emulation is not completed"), + gas: emulation_result.used_gas, + return_value: hex::encode( + emulation_result + .exit_status + .into_result() + .unwrap_or_default(), + ), + struct_logs: self.logs, + }; + + serde_json::to_value(result).expect("Conversion error") + } +} From 1f6e5daf1010df707faa407917b007f0f9f77565 Mon Sep 17 00:00:00 2001 From: s-medvedev <40623263+s-medvedev@users.noreply.github.com> Date: Wed, 30 Aug 2023 16:21:37 +0700 Subject: [PATCH 009/318] NDEV-2117 Check holder address (#176) * NDEV-2117 Check holder address * NDEV-2117 Fix tests * NDEV-2117 Fix tests --------- Co-authored-by: Semen Medvedev --- .../src/instruction/account_holder_create.rs | 22 +++++++++++++++---- evm_loader/tests/solana_utils.py | 5 +++-- evm_loader/tests/test_holder_account.py | 4 ++-- evm_loader/tests/utils/storage.py | 2 +- 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/evm_loader/program/src/instruction/account_holder_create.rs b/evm_loader/program/src/instruction/account_holder_create.rs index d31c26381..19bc61c7b 100644 --- a/evm_loader/program/src/instruction/account_holder_create.rs +++ b/evm_loader/program/src/instruction/account_holder_create.rs @@ -1,17 +1,31 @@ use crate::account::{Holder, Operator}; -use crate::error::Result; -use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; +use arrayref::array_ref; +use solana_program::{ + account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, + pubkey::Pubkey, +}; pub fn process<'a>( program_id: &'a Pubkey, accounts: &'a [AccountInfo<'a>], - _instruction: &[u8], -) -> Result<()> { + instruction: &[u8], +) -> ProgramResult { solana_program::msg!("Instruction: Create Holder Account"); let holder = &accounts[0]; let operator = unsafe { Operator::from_account_not_whitelisted(&accounts[1]) }?; + let seed_len = usize::from_le_bytes(*array_ref![instruction, 0, 8]); + let seed_bytes = instruction[8..8 + seed_len].to_vec(); + let seed = String::from_utf8(seed_bytes) + .map_err(|_| E!(ProgramError::InvalidArgument; "Seed bytes aren't valid UTF8"))?; + + let expected_holder = Pubkey::create_with_seed(operator.key, &seed, program_id) + .map_err(|_| E!(ProgramError::InvalidArgument; "Invalid seed bytes"))?; + if expected_holder != *holder.key { + return Err!(ProgramError::InvalidArgument; "Holder doesn't match seeds"); + } + Holder::init( program_id, holder, diff --git a/evm_loader/tests/solana_utils.py b/evm_loader/tests/solana_utils.py index eeed1efea..385e721c3 100644 --- a/evm_loader/tests/solana_utils.py +++ b/evm_loader/tests/solana_utils.py @@ -155,14 +155,15 @@ def create_account_with_seed(funding, base, seed, lamports, space, program=Publi )) -def create_holder_account(account, operator): +def create_holder_account(account, operator, seed): return TransactionInstruction( keys=[ AccountMeta(pubkey=account, is_signer=False, is_writable=True), AccountMeta(pubkey=operator, is_signer=True, is_writable=False), ], program_id=PublicKey(EVM_LOADER), - data=bytes.fromhex("24") + data=bytes.fromhex("24") + + len(seed).to_bytes(8, 'little') + seed ) diff --git a/evm_loader/tests/test_holder_account.py b/evm_loader/tests/test_holder_account.py index 41eef0dc3..23e74a2e4 100644 --- a/evm_loader/tests/test_holder_account.py +++ b/evm_loader/tests/test_holder_account.py @@ -44,10 +44,10 @@ def test_create_the_same_holder_account_by_another_user(operator_keypair, sessio trx.add( solana_utils.create_account_with_seed(session_user.solana_account.public_key, session_user.solana_account.public_key, seed, 10 ** 9, 128 * 1024), - solana_utils.create_holder_account(storage, session_user.solana_account.public_key) + solana_utils.create_holder_account(storage, session_user.solana_account.public_key, bytes(seed, 'utf8')) ) - with pytest.raises(solana.rpc.core.RPCException, match='already initialized'): + with pytest.raises(solana.rpc.core.RPCException, match="Holder doesn't match seeds"): solana_utils.send_transaction(solana_client, trx, session_user.solana_account) diff --git a/evm_loader/tests/utils/storage.py b/evm_loader/tests/utils/storage.py index 5298a5ecc..4876d459b 100644 --- a/evm_loader/tests/utils/storage.py +++ b/evm_loader/tests/utils/storage.py @@ -27,7 +27,7 @@ def create_holder(signer: Keypair, seed: str = None, size: int = None, fund: int trx = Transaction() trx.add( create_account_with_seed(signer.public_key, signer.public_key, seed, fund, size), - create_holder_account(storage, signer.public_key) + create_holder_account(storage, signer.public_key, bytes(seed, 'utf8')) ) send_transaction(solana_client, trx, signer) print(f"Created holder account: {storage}") From 98f9f18d20ec5336a4f19bbf7f18529637aa66dd Mon Sep 17 00:00:00 2001 From: Andrey Falaleev Date: Wed, 30 Aug 2023 20:39:26 +0000 Subject: [PATCH 010/318] Set version to v1.3.0-dev (#178) --- evm_loader/Cargo.lock | 4 ++-- evm_loader/cli/Cargo.toml | 2 +- evm_loader/program/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index e12996223..68eb73a2a 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -1198,7 +1198,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "evm-loader" -version = "1.1.0-dev" +version = "1.3.0-dev" dependencies = [ "arrayref", "bincode", @@ -2203,7 +2203,7 @@ dependencies = [ [[package]] name = "neon-cli" -version = "1.1.0-dev" +version = "1.3.0-dev" dependencies = [ "clap 2.34.0", "ethnum", diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index 15c800fd2..791c9d192 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "neon-cli" -version = "1.1.0-dev" +version = "1.3.0-dev" authors = ["NeonLabs Maintainers "] edition = "2021" diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 9cc0c70dc..94fb50cbe 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "evm-loader" -version = "1.1.0-dev" +version = "1.3.0-dev" description = "Neon EVM loader" authors = ["NeonLabs Maintainers "] edition = "2021" From b14d1ccaf3fd1f6dfe3b9b4c2f0cca913e73e85f Mon Sep 17 00:00:00 2001 From: Julian Pokrovsky Date: Fri, 1 Sep 2023 12:54:37 +0300 Subject: [PATCH 011/318] EIP2930: Tx envelop and AccessList tx support (#140) EIP2930: Tx envelop and AccessList transaction support - Uses individual structs for Transactions - Adds tests for different structure of access list - Changes Transaction core type and it's usage everywhere --- evm_loader/cli/src/main.rs | 20 +- evm_loader/cli/src/program_options.rs | 8 + evm_loader/lib/src/commands/emulate.rs | 70 ++- evm_loader/lib/src/types/indexer_db.rs | 1 + evm_loader/lib/src/types/mod.rs | 7 + evm_loader/lib/src/types/request_models.rs | 4 + evm_loader/program/src/account/holder.rs | 4 +- evm_loader/program/src/evm/mod.rs | 46 +- evm_loader/program/src/gasometer.rs | 2 +- .../src/instruction/transaction_execute.rs | 10 +- .../transaction_execute_from_account.rs | 6 +- .../transaction_execute_from_instruction.rs | 6 +- .../src/instruction/transaction_step.rs | 2 +- .../transaction_step_from_account.rs | 17 +- .../transaction_step_from_instruction.rs | 6 +- evm_loader/program/src/state_account.rs | 8 +- evm_loader/program/src/types/mod.rs | 4 + evm_loader/program/src/types/transaction.rs | 563 +++++++++++++++--- evm_loader/tests/conftest.py | 15 + evm_loader/tests/contracts/contracts.sol | 21 + .../test_execute_trx_from_instruction.py | 46 ++ .../test_transaction_step_from_account.py | 69 ++- ...ransaction_step_from_account_no_chainid.py | 24 + .../test_transaction_step_from_instruction.py | 73 ++- evm_loader/tests/utils/contract.py | 14 +- evm_loader/tests/utils/ethereum.py | 10 +- 26 files changed, 889 insertions(+), 167 deletions(-) diff --git a/evm_loader/cli/src/main.rs b/evm_loader/cli/src/main.rs index ae6efc045..25a57962c 100644 --- a/evm_loader/cli/src/main.rs +++ b/evm_loader/cli/src/main.rs @@ -12,7 +12,8 @@ use neon_lib::{ get_ether_account_data, get_neon_elf, get_neon_elf::CachedElfParams, get_storage_at, init_environment, trace, }, - errors, rpc, types, + errors, rpc, + types::{self, AccessListItem}, }; use clap::ArgMatches; @@ -319,9 +320,13 @@ fn parse_tx(params: &ArgMatches) -> (TxParams, TraceCallConfig) { ) }) .unwrap_or_default(); + let value = u256_of(params, "value"); + let gas_limit = u256_of(params, "gas_limit"); + let access_list = access_list_of(params, "access_list"); + let tx_params = TxParams { nonce: None, from, @@ -329,6 +334,7 @@ fn parse_tx(params: &ArgMatches) -> (TxParams, TraceCallConfig) { data, value, gas_limit, + access_list, }; (tx_params, trace_config) @@ -403,6 +409,18 @@ fn address_of(matches: &ArgMatches<'_>, name: &str) -> Option
{ .map(|value| Address::from_hex(value).unwrap()) } +fn access_list_of(matches: &ArgMatches<'_>, name: &str) -> Option> { + matches.value_of(name).map(|value| { + let address = Address::from_hex(value).unwrap(); + let keys = vec![]; + let item = AccessListItem { + address, + storage_keys: keys, + }; + vec![item] + }) +} + fn u256_of(matches: &ArgMatches<'_>, name: &str) -> Option { matches.value_of(name).map(|value| { if value.is_empty() { diff --git a/evm_loader/cli/src/program_options.rs b/evm_loader/cli/src/program_options.rs index dbce571ad..f8bea1704 100644 --- a/evm_loader/cli/src/program_options.rs +++ b/evm_loader/cli/src/program_options.rs @@ -151,6 +151,14 @@ fn trx_params<'a, 'b>(cmd: &'static str, desc: &'static str) -> App<'a, 'b> { .validator(is_valid_u256) .help("Gas limit"), ) + .arg( + Arg::with_name("access_list") + .long("access-list") + .takes_value(true) + .required(false) + .multiple(true) + .value_name("ADDRESS [STORAGE_KEYS ...]"), + ) .arg( Arg::with_name("cached_accounts") .value_name("CACHED_ACCOUNTS") diff --git a/evm_loader/lib/src/commands/emulate.rs b/evm_loader/lib/src/commands/emulate.rs index fdcbc41d2..9a1a5b3a5 100644 --- a/evm_loader/lib/src/commands/emulate.rs +++ b/evm_loader/lib/src/commands/emulate.rs @@ -202,19 +202,65 @@ pub(crate) async fn emulate_trx<'a>( ) -> Result { let (exit_status, actions, steps_executed) = { let mut backend = ExecutorState::new(storage); - let trx = Transaction { - nonce: tx_params - .nonce - .unwrap_or_else(|| storage.nonce(&tx_params.from)), - gas_price: U256::ZERO, - gas_limit: tx_params.gas_limit.unwrap_or(U256::MAX), - target: tx_params.to, - value: tx_params.value.unwrap_or_default(), - call_data: evm_loader::evm::Buffer::from_slice(&tx_params.data.unwrap_or_default()), - chain_id: Some(chain_id.into()), - ..Transaction::default() + let trx_payload = if tx_params.access_list.is_some() { + let access_list = tx_params + .access_list + .expect("access_list is present") + .into_iter() + .map(|item| { + ( + item.address, + item.storage_keys + .into_iter() + .map(|k| { + evm_loader::types::StorageKey::try_from(k) + .expect("key to be correct") + }) + .collect(), + ) + }) + .collect(); + evm_loader::types::TransactionPayload::AccessList(evm_loader::types::AccessListTx { + nonce: tx_params + .nonce + .unwrap_or_else(|| storage.nonce(&tx_params.from)), + gas_price: U256::ZERO, + gas_limit: tx_params.gas_limit.unwrap_or(U256::MAX), + target: tx_params.to, + value: tx_params.value.unwrap_or_default(), + call_data: evm_loader::evm::Buffer::from_slice(&tx_params.data.unwrap_or_default()), + r: U256::default(), + s: U256::default(), + chain_id: chain_id.into(), + recovery_id: u8::default(), + access_list, + }) + } else { + evm_loader::types::TransactionPayload::Legacy(evm_loader::types::LegacyTx { + nonce: tx_params + .nonce + .unwrap_or_else(|| storage.nonce(&tx_params.from)), + gas_price: U256::ZERO, + gas_limit: tx_params.gas_limit.unwrap_or(U256::MAX), + target: tx_params.to, + value: tx_params.value.unwrap_or_default(), + call_data: evm_loader::evm::Buffer::from_slice(&tx_params.data.unwrap_or_default()), + v: U256::default(), + r: U256::default(), + s: U256::default(), + chain_id: Some(chain_id.into()), + recovery_id: u8::default(), + }) }; - let mut evm = Machine::new(trx, tx_params.from, &mut backend, tracer)?; + + let mut trx = Transaction { + transaction: trx_payload, + byte_len: usize::default(), + hash: <[u8; 32]>::default(), + signed_hash: <[u8; 32]>::default(), + }; + + let mut evm = Machine::new(&mut trx, tx_params.from, &mut backend, tracer)?; let (result, steps_executed) = evm.execute(step_limit, &mut backend)?; if result == ExitStatus::StepLimit { diff --git a/evm_loader/lib/src/types/indexer_db.rs b/evm_loader/lib/src/types/indexer_db.rs index 3b2c84eab..9a716cee5 100644 --- a/evm_loader/lib/src/types/indexer_db.rs +++ b/evm_loader/lib/src/types/indexer_db.rs @@ -170,6 +170,7 @@ impl IndexerDb { data: Some(data), value: Some(value), gas_limit: Some(gas_limit), + access_list: None, }) } } diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index 4384207c9..6a70b09fa 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -33,6 +33,12 @@ pub struct ChDbConfig { pub indexer_password: String, } +#[derive(Clone, Serialize, Deserialize, Debug)] +pub struct AccessListItem { + pub address: Address, + pub storage_keys: Vec, +} + #[derive(Clone, Serialize, Deserialize, Debug)] pub struct TxParams { pub nonce: Option, @@ -41,6 +47,7 @@ pub struct TxParams { pub data: Option>, pub value: Option, pub gas_limit: Option, + pub access_list: Option>, } #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/evm_loader/lib/src/types/request_models.rs b/evm_loader/lib/src/types/request_models.rs index 2769dc3e3..b69048243 100644 --- a/evm_loader/lib/src/types/request_models.rs +++ b/evm_loader/lib/src/types/request_models.rs @@ -5,6 +5,8 @@ use evm_loader::types::Address; use serde::{Deserialize, Serialize}; use solana_sdk::pubkey::Pubkey; +use super::AccessListItem; + #[derive(Deserialize, Serialize, Debug, Default)] pub struct GetEtherRequest { pub ether: Address, @@ -25,6 +27,7 @@ pub struct TxParamsRequestModel { pub data: Option>, pub value: Option, pub gas_limit: Option, + pub access_list: Option>, } impl From for TxParams { @@ -36,6 +39,7 @@ impl From for TxParams { data: model.data, value: model.value, gas_limit: model.gas_limit, + access_list: model.access_list, } } } diff --git a/evm_loader/program/src/account/holder.rs b/evm_loader/program/src/account/holder.rs index 268d02803..55c8218e9 100644 --- a/evm_loader/program/src/account/holder.rs +++ b/evm_loader/program/src/account/holder.rs @@ -93,8 +93,8 @@ impl<'a> Holder<'a> { } pub fn validate_transaction(&self, trx: &Transaction) -> Result<()> { - if self.transaction_hash != trx.hash { - return Err(Error::HolderInvalidHash(self.transaction_hash, trx.hash)); + if self.transaction_hash != trx.hash() { + return Err(Error::HolderInvalidHash(self.transaction_hash, trx.hash())); } Ok(()) diff --git a/evm_loader/program/src/evm/mod.rs b/evm_loader/program/src/evm/mod.rs index f6f653d04..09505121f 100644 --- a/evm_loader/program/src/evm/mod.rs +++ b/evm_loader/program/src/evm/mod.rs @@ -192,7 +192,7 @@ impl Machine { } pub fn new( - trx: Transaction, + trx: &mut Transaction, origin: Address, backend: &mut B, #[cfg(feature = "tracing")] tracer: TracerTypeOpt, @@ -203,29 +203,29 @@ impl Machine { return Err(Error::NonceOverflow(origin)); } - if origin_nonce != trx.nonce { + if origin_nonce != trx.nonce() { return Err(Error::InvalidTransactionNonce( origin, origin_nonce, - trx.nonce, + trx.nonce(), )); } - if let Some(chain_id) = trx.chain_id { + if let Some(chain_id) = trx.chain_id() { if backend.chain_id() != chain_id { return Err(Error::InvalidChainId(chain_id)); } } - if backend.balance(&origin)? < trx.value { - return Err(Error::InsufficientBalance(origin, trx.value)); + if backend.balance(&origin)? < trx.value() { + return Err(Error::InsufficientBalance(origin, trx.value())); } if backend.code_size(&origin)? != 0 { return Err(Error::SenderHasDeployedCode(origin)); } - if trx.target.is_some() { + if trx.target().is_some() { Self::new_call( trx, origin, @@ -245,20 +245,20 @@ impl Machine { } fn new_call( - trx: Transaction, + trx: &mut Transaction, origin: Address, backend: &mut B, #[cfg(feature = "tracing")] tracer: TracerTypeOpt, ) -> Result { - assert!(trx.target.is_some()); + assert!(trx.target().is_some()); - let target = trx.target.unwrap(); + let target = trx.target().unwrap(); sol_log_data(&[b"ENTER", b"CALL", target.as_bytes()]); backend.increment_nonce(origin)?; backend.snapshot(); - backend.transfer(origin, target, trx.value)?; + backend.transfer(origin, target, trx.value())?; let execution_code = backend.code(&target)?; @@ -267,13 +267,13 @@ impl Machine { context: Context { caller: origin, contract: target, - value: trx.value, + value: trx.value(), code_address: Some(target), }, - gas_price: trx.gas_price, - gas_limit: trx.gas_limit, + gas_price: trx.gas_price(), + gas_limit: trx.gas_limit(), execution_code, - call_data: trx.call_data, + call_data: trx.extract_call_data(), return_data: Buffer::empty(), return_range: 0..0, stack: Stack::new( @@ -295,14 +295,14 @@ impl Machine { } fn new_create( - trx: Transaction, + trx: &mut Transaction, origin: Address, backend: &mut B, #[cfg(feature = "tracing")] tracer: TracerTypeOpt, ) -> Result { - assert!(trx.target.is_none()); + assert!(trx.target().is_none()); - let target = Address::from_create(&origin, trx.nonce); + let target = Address::from_create(&origin, trx.nonce()); sol_log_data(&[b"ENTER", b"CREATE", target.as_bytes()]); if (backend.nonce(&target)? != 0) || (backend.code_size(&target)? != 0) { @@ -313,18 +313,18 @@ impl Machine { backend.snapshot(); backend.increment_nonce(target)?; - backend.transfer(origin, target, trx.value)?; + backend.transfer(origin, target, trx.value())?; Ok(Self { origin, context: Context { caller: origin, contract: target, - value: trx.value, + value: trx.value(), code_address: None, }, - gas_price: trx.gas_price, - gas_limit: trx.gas_limit, + gas_price: trx.gas_price(), + gas_limit: trx.gas_limit(), return_data: Buffer::empty(), return_range: 0..0, stack: Stack::new( @@ -338,7 +338,7 @@ impl Machine { pc: 0_usize, is_static: false, reason: Reason::Create, - execution_code: trx.call_data, + execution_code: trx.extract_call_data(), call_data: Buffer::empty(), parent: None, phantom: PhantomData, diff --git a/evm_loader/program/src/gasometer.rs b/evm_loader/program/src/gasometer.rs index 797fba36b..8894b694f 100644 --- a/evm_loader/program/src/gasometer.rs +++ b/evm_loader/program/src/gasometer.rs @@ -57,7 +57,7 @@ impl Gasometer { } pub fn record_write_to_holder(&mut self, trx: &Transaction) { - let size: u64 = trx.rlp_len.try_into().expect("usize is 8 bytes"); + let size: u64 = trx.rlp_len().try_into().expect("usize is 8 bytes"); let cost: u64 = ((size + (HOLDER_MSG_SIZE - 1)) / HOLDER_MSG_SIZE) .saturating_mul(WRITE_TO_HOLDER_TRX_COST); diff --git a/evm_loader/program/src/instruction/transaction_execute.rs b/evm_loader/program/src/instruction/transaction_execute.rs index 5f3b9b305..28acefcb4 100644 --- a/evm_loader/program/src/instruction/transaction_execute.rs +++ b/evm_loader/program/src/instruction/transaction_execute.rs @@ -26,8 +26,8 @@ pub fn validate( trx: &Transaction, _caller_address: &Address, ) -> Result<()> { - if trx.chain_id != Some(CHAIN_ID.into()) { - return Err(Error::InvalidChainId(trx.chain_id.unwrap_or(U256::ZERO))); + if trx.chain_id() != Some(CHAIN_ID.into()) { + return Err(Error::InvalidChainId(trx.chain_id().unwrap_or(U256::ZERO))); } account_storage.check_for_blocked_accounts()?; @@ -39,7 +39,7 @@ pub fn execute<'a>( accounts: Accounts<'a>, account_storage: &mut ProgramAccountStorage<'a>, mut gasometer: Gasometer, - trx: Transaction, + trx: &mut Transaction, caller_address: Address, ) -> Result<()> { accounts.system_program.transfer( @@ -48,8 +48,8 @@ pub fn execute<'a>( crate::config::PAYMENT_TO_TREASURE, )?; - let gas_limit = trx.gas_limit; - let gas_price = trx.gas_price; + let gas_limit = trx.gas_limit(); + let gas_price = trx.gas_price(); let (exit_reason, apply_state) = { let mut backend = ExecutorState::new(account_storage); diff --git a/evm_loader/program/src/instruction/transaction_execute_from_account.rs b/evm_loader/program/src/instruction/transaction_execute_from_account.rs index c7771ede8..b9fb55277 100644 --- a/evm_loader/program/src/instruction/transaction_execute_from_account.rs +++ b/evm_loader/program/src/instruction/transaction_execute_from_account.rs @@ -30,12 +30,12 @@ pub fn process<'a>( }; holder.validate_owner(&accounts.operator)?; - let trx = Transaction::from_rlp(&holder.transaction())?; + let mut trx = Transaction::from_rlp(&holder.transaction())?; holder.validate_transaction(&trx)?; let caller_address = trx.recover_caller_address()?; - solana_program::log::sol_log_data(&[b"HASH", &trx.hash]); + solana_program::log::sol_log_data(&[b"HASH", &trx.hash()]); let mut account_storage = ProgramAccountStorage::new( program_id, @@ -54,7 +54,7 @@ pub fn process<'a>( accounts, &mut account_storage, gasometer, - trx, + &mut trx, caller_address, ) } diff --git a/evm_loader/program/src/instruction/transaction_execute_from_instruction.rs b/evm_loader/program/src/instruction/transaction_execute_from_instruction.rs index 528e006ea..2593bebb9 100644 --- a/evm_loader/program/src/instruction/transaction_execute_from_instruction.rs +++ b/evm_loader/program/src/instruction/transaction_execute_from_instruction.rs @@ -28,10 +28,10 @@ pub fn process<'a>( all_accounts: accounts, }; - let trx = Transaction::from_rlp(messsage)?; + let mut trx = Transaction::from_rlp(messsage)?; let caller_address = trx.recover_caller_address()?; - solana_program::log::sol_log_data(&[b"HASH", &trx.hash]); + solana_program::log::sol_log_data(&[b"HASH", &trx.hash()]); let mut account_storage = ProgramAccountStorage::new( program_id, @@ -49,7 +49,7 @@ pub fn process<'a>( accounts, &mut account_storage, gasometer, - trx, + &mut trx, caller_address, ) } diff --git a/evm_loader/program/src/instruction/transaction_step.rs b/evm_loader/program/src/instruction/transaction_step.rs index 286d98dd7..3396ec5d0 100644 --- a/evm_loader/program/src/instruction/transaction_step.rs +++ b/evm_loader/program/src/instruction/transaction_step.rs @@ -29,7 +29,7 @@ pub fn do_begin<'a>( mut storage: State<'a>, account_storage: &mut ProgramAccountStorage<'a>, gasometer: Gasometer, - trx: Transaction, + trx: &mut Transaction, caller: Address, ) -> Result<()> { debug_print!("do_begin"); diff --git a/evm_loader/program/src/instruction/transaction_step_from_account.rs b/evm_loader/program/src/instruction/transaction_step_from_account.rs index ee3f06f7c..9393cf4da 100644 --- a/evm_loader/program/src/instruction/transaction_step_from_account.rs +++ b/evm_loader/program/src/instruction/transaction_step_from_account.rs @@ -58,7 +58,7 @@ pub fn execute<'a>( ) -> Result<()> { match crate::account::tag(program_id, holder_or_storage_info)? { Holder::TAG => { - let trx = { + let mut trx = { let holder = Holder::from_account(program_id, holder_or_storage_info)?; holder.validate_owner(&accounts.operator)?; @@ -70,11 +70,11 @@ pub fn execute<'a>( trx }; - if trx.chain_id != expected_chain_id { - return Err(Error::InvalidChainId(trx.chain_id.unwrap_or(U256::ZERO))); + if trx.chain_id() != expected_chain_id { + return Err(Error::InvalidChainId(trx.chain_id().unwrap_or(U256::ZERO))); } - solana_program::log::sol_log_data(&[b"HASH", &trx.hash]); + solana_program::log::sol_log_data(&[b"HASH", &trx.hash()]); let caller = trx.recover_caller_address()?; let mut storage = @@ -91,7 +91,14 @@ pub fn execute<'a>( gasometer.record_iterative_overhead(); gasometer.record_write_to_holder(&trx); - do_begin(accounts, storage, account_storage, gasometer, trx, caller) + do_begin( + accounts, + storage, + account_storage, + gasometer, + &mut trx, + caller, + ) } State::TAG => { let (storage, _blocked_accounts) = State::restore( diff --git a/evm_loader/program/src/instruction/transaction_step_from_instruction.rs b/evm_loader/program/src/instruction/transaction_step_from_instruction.rs index 621243492..dfcee2ae1 100644 --- a/evm_loader/program/src/instruction/transaction_step_from_instruction.rs +++ b/evm_loader/program/src/instruction/transaction_step_from_instruction.rs @@ -40,10 +40,10 @@ pub fn process<'a>( match crate::account::tag(program_id, storage_info)? { Holder::TAG | FinalizedState::TAG => { - let trx = Transaction::from_rlp(message)?; + let mut trx = Transaction::from_rlp(message)?; let caller = trx.recover_caller_address()?; - solana_program::log::sol_log_data(&[b"HASH", &trx.hash]); + solana_program::log::sol_log_data(&[b"HASH", &trx.hash()]); let storage = State::new(program_id, storage_info, &accounts, caller, &trx)?; @@ -57,7 +57,7 @@ pub fn process<'a>( storage, &mut account_storage, gasometer, - trx, + &mut trx, caller, ) } diff --git a/evm_loader/program/src/state_account.rs b/evm_loader/program/src/state_account.rs index c0328ebce..e93407ba1 100644 --- a/evm_loader/program/src/state_account.rs +++ b/evm_loader/program/src/state_account.rs @@ -48,7 +48,7 @@ impl<'a> State<'a> { } FinalizedState::TAG => { let finalized_storage = FinalizedState::from_account(program_id, info)?; - if !finalized_storage.is_outdated(&trx.hash) { + if !finalized_storage.is_outdated(&trx.hash()) { return Err!(Error::StorageAccountFinalized.into(); "Transaction already finalized"); } @@ -65,10 +65,10 @@ impl<'a> State<'a> { let data = crate::account::state::Data { owner, - transaction_hash: trx.hash, + transaction_hash: trx.hash(), caller, - gas_limit: trx.gas_limit, - gas_price: trx.gas_price, + gas_limit: trx.gas_limit(), + gas_price: trx.gas_price(), gas_used: U256::ZERO, operator: *accounts.operator.key, slot: Clock::get()?.slot, diff --git a/evm_loader/program/src/types/mod.rs b/evm_loader/program/src/types/mod.rs index 2a7e7579e..422350278 100644 --- a/evm_loader/program/src/types/mod.rs +++ b/evm_loader/program/src/types/mod.rs @@ -1,5 +1,9 @@ pub use address::Address; +pub use transaction::AccessListTx; +pub use transaction::LegacyTx; +pub use transaction::StorageKey; pub use transaction::Transaction; +pub use transaction::TransactionPayload; mod address; pub mod hexbytes; diff --git a/evm_loader/program/src/types/transaction.rs b/evm_loader/program/src/types/transaction.rs index 63c17ef3e..7d4d5a664 100644 --- a/evm_loader/program/src/types/transaction.rs +++ b/evm_loader/program/src/types/transaction.rs @@ -1,11 +1,68 @@ -use crate::error::Error; use ethnum::U256; use std::convert::TryInto; +use crate::error::Error; + use super::Address; -#[derive(Debug, Default, Clone)] -pub struct Transaction { +#[repr(transparent)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +pub struct StorageKey([u8; 32]); + +impl rlp::Decodable for StorageKey { + fn decode(rlp: &rlp::Rlp) -> Result { + rlp.decoder().decode_value(|bytes| { + let array: [u8; 32] = bytes + .try_into() + .map_err(|_| rlp::DecoderError::RlpInvalidLength)?; + Ok(Self(array)) + }) + } +} + +impl TryFrom for StorageKey { + type Error = String; + + fn try_from(hex: crate::types::hexbytes::HexBytes) -> Result { + let bytes = hex.0; + + if bytes.len() != 32 { + return Err(String::from("Hex string must be 32 bytes")); + } + + let mut array = [0; 32]; + array.copy_from_slice(&bytes); + + Ok(StorageKey(array)) + } +} + +#[derive(Debug, Clone)] +pub enum TransactionEnvelope { + Legacy, + AccessList, + DynamicFee, +} + +impl TransactionEnvelope { + pub fn get_type(bytes: &[u8]) -> (Option, &[u8]) { + // Legacy transaction format + if rlp::Rlp::new(bytes).is_list() { + (None, bytes) + // It's an EIP-2718 typed TX envelope. + } else { + match bytes[0] { + 0x00 => (Some(TransactionEnvelope::Legacy), &bytes[1..]), + 0x01 => (Some(TransactionEnvelope::AccessList), &bytes[1..]), + 0x02 => (Some(TransactionEnvelope::DynamicFee), &bytes[1..]), + byte => panic!("Unsupported EIP-2718 Transaction type | First byte: {byte}"), + } + } + } +} + +#[derive(Debug, Clone)] +pub struct LegacyTx { pub nonce: u64, pub gas_price: U256, pub gas_limit: U256, @@ -17,36 +74,10 @@ pub struct Transaction { pub s: U256, pub chain_id: Option, pub recovery_id: u8, - pub rlp_len: usize, - pub hash: [u8; 32], - pub signed_hash: [u8; 32], } -impl Transaction { - pub fn from_rlp(transaction: &[u8]) -> Result { - rlp::decode(transaction).map_err(Error::from) - } - - pub fn recover_caller_address(&self) -> Result { - use solana_program::keccak::{hash, Hash}; - use solana_program::secp256k1_recover::secp256k1_recover; - - let signature = [self.r.to_be_bytes(), self.s.to_be_bytes()].concat(); - let public_key = secp256k1_recover(&self.signed_hash, self.recovery_id, &signature)?; - - let Hash(address) = hash(&public_key.to_bytes()); - let address: [u8; 20] = address[12..32].try_into()?; - - Ok(Address::from(address)) - } -} - -impl rlp::Decodable for Transaction { +impl rlp::Decodable for LegacyTx { fn decode(rlp: &rlp::Rlp) -> Result { - if !rlp.is_list() { - return Err(rlp::DecoderError::RlpExpectedToBeList); - } - let rlp_len = { let info = rlp.payload_info()?; info.header_len + info.value_len @@ -93,10 +124,7 @@ impl rlp::Decodable for Transaction { return Err(rlp::DecoderError::RlpExpectedToBeData); }; - let hash = solana_program::keccak::hash(rlp.as_raw()).to_bytes(); - let signed_hash = signed_hash(rlp, chain_id)?; - - let tx = Self { + let tx = LegacyTx { nonce, gas_price, gas_limit, @@ -108,79 +136,446 @@ impl rlp::Decodable for Transaction { s, chain_id, recovery_id, - rlp_len, - hash, - signed_hash, }; Ok(tx) } } -fn signed_hash( - transaction: &rlp::Rlp, - chain_id: Option, -) -> Result<[u8; 32], rlp::DecoderError> { - let raw = transaction.as_raw(); - let payload_info = transaction.payload_info()?; - let (_, v_offset) = transaction.at_with_offset(6)?; - - let middle = &raw[payload_info.header_len..v_offset]; - - let trailer = chain_id.map_or_else(Vec::new, |chain_id| { - let chain_id = { - let leading_empty_bytes = (chain_id.leading_zeros() as usize) / 8; - let bytes = chain_id.to_be_bytes(); - bytes[leading_empty_bytes..].to_vec() +#[derive(Debug, Clone)] +pub struct AccessListTx { + pub nonce: u64, + pub gas_price: U256, + pub gas_limit: U256, + pub target: Option
, + pub value: U256, + pub call_data: crate::evm::Buffer, + pub r: U256, + pub s: U256, + pub chain_id: U256, + pub recovery_id: u8, + pub access_list: Vec<(Address, Vec)>, +} + +impl rlp::Decodable for AccessListTx { + fn decode(rlp: &rlp::Rlp) -> Result { + let rlp_len = { + let info = rlp.payload_info()?; + info.header_len + info.value_len }; - let mut trailer = Vec::with_capacity(64); - match chain_id.len() { - 0 => { - trailer.extend_from_slice(&[0x80]); + if rlp.as_raw().len() != rlp_len { + return Err(rlp::DecoderError::RlpInconsistentLengthAndData); + } + + let chain_id: U256 = u256(&rlp.at(0)?)?; + let nonce: u64 = rlp.val_at(1)?; + let gas_price: U256 = u256(&rlp.at(2)?)?; + let gas_limit: U256 = u256(&rlp.at(3)?)?; + let target: Option
= { + let target = rlp.at(4)?; + if target.is_empty() { + if target.is_data() { + None + } else { + return Err(rlp::DecoderError::RlpExpectedToBeData); + } + } else { + Some(target.as_val()?) } - 1 if chain_id[0] < 0x80 => { - trailer.extend_from_slice(&chain_id); + }; + + let value: U256 = u256(&rlp.at(5)?)?; + let call_data = crate::evm::Buffer::from_slice(rlp.at(6)?.data()?); + + let rlp_access_list = rlp.at(7)?; + let mut access_list = vec![]; + + for entry in rlp_access_list.iter() { + // Check if entry is a list + if entry.is_list() { + // Parse address from first element + let address: Address = entry.at(0)?.as_val()?; + + // Get storage keys from second element + let mut storage_keys: Vec = vec![]; + + for key in entry.at(1)?.iter() { + storage_keys.push(key.as_val()?); + } + + access_list.push((address, storage_keys)); + } else { + return Err(rlp::DecoderError::RlpExpectedToBeList); } - len @ 1..=55 => { - let len: u8 = len.try_into().unwrap(); + } + + let y_parity: u8 = rlp.at(8)?.as_val()?; + let r: U256 = u256(&rlp.at(9)?)?; + let s: U256 = u256(&rlp.at(10)?)?; + + if rlp.at(11).is_ok() { + return Err(rlp::DecoderError::RlpIncorrectListLen); + } - trailer.extend_from_slice(&[0x80 + len]); - trailer.extend_from_slice(&chain_id); + let tx = AccessListTx { + nonce, + gas_price, + gas_limit, + target, + value, + call_data, + r, + s, + chain_id, + recovery_id: y_parity, + access_list, + }; + + Ok(tx) + } +} + +// TODO: Will be added as a part of EIP-1559 +// struct DynamicFeeTx {} + +#[derive(Debug, Clone)] +pub enum TransactionPayload { + Legacy(LegacyTx), + AccessList(AccessListTx), +} + +#[derive(Debug, Clone)] +pub struct Transaction { + pub transaction: TransactionPayload, + pub byte_len: usize, + pub hash: [u8; 32], + pub signed_hash: [u8; 32], +} + +impl Transaction { + pub fn from_payload( + transaction_type: &Option, + chain_id: Option, + transaction_rlp: &rlp::Rlp, + transaction: TransactionPayload, + ) -> Result { + let (hash, signed_hash) = match *transaction_type { + // Legacy transaction wrapped in envelop + Some(TransactionEnvelope::Legacy) => { + let hash = + solana_program::keccak::hashv(&[&[0x00], transaction_rlp.as_raw()]).to_bytes(); + let signed_hash = Self::calculate_legacy_signature(transaction_rlp, chain_id)?; + + (hash, signed_hash) } - _ => { - unreachable!("chain_id.len() <= 32") + // Access List transaction + Some(TransactionEnvelope::AccessList) => { + let hash = + solana_program::keccak::hashv(&[&[0x01], transaction_rlp.as_raw()]).to_bytes(); + let signed_hash = Self::eip2718_signed_hash(&[0x01], transaction_rlp, 8)?; + + (hash, signed_hash) } - } + // Legacy trasaction + None => { + let hash = solana_program::keccak::hash(transaction_rlp.as_raw()).to_bytes(); + let signed_hash = Self::calculate_legacy_signature(transaction_rlp, chain_id)?; - trailer.extend_from_slice(&[0x80, 0x80]); - trailer - }); + (hash, signed_hash) + } + _ => unimplemented!(), + }; - let header: Vec = { - let len = middle.len() + trailer.len(); - if len <= 55 { - let len: u8 = len.try_into().unwrap(); - vec![0xC0 + len] + let info = transaction_rlp.payload_info()?; + let byte_len = if transaction_type.is_none() { + // Legacy transaction + info.header_len + info.value_len } else { - let len_bytes = { - let leading_empty_bytes = (len.leading_zeros() as usize) / 8; - let bytes = len.to_be_bytes(); + // Transaction in the type envelope + info.header_len + info.value_len + 1 // + 1 byte for type + }; + + Ok(Transaction { + transaction, + byte_len, + hash, + signed_hash, + }) + } + + fn eip2718_signed_hash( + transaction_type: &[u8], + transaction: &rlp::Rlp, + middle_offset: usize, + ) -> Result<[u8; 32], rlp::DecoderError> { + let raw = transaction.as_raw(); + let payload_info = transaction.payload_info()?; + let (_, middle_offset) = transaction.at_with_offset(middle_offset)?; + + let body = &raw[payload_info.header_len..middle_offset]; + + let header: Vec = { + let len = body.len(); + if len <= 55 { + let len: u8 = len.try_into().unwrap(); + vec![0xC0 + len] + } else { + let len_bytes = { + let leading_empty_bytes = (len.leading_zeros() as usize) / 8; + let bytes = len.to_be_bytes(); + bytes[leading_empty_bytes..].to_vec() + }; + let len_bytes_len: u8 = len_bytes.len().try_into().unwrap(); + + let mut header = Vec::with_capacity(10); + header.extend_from_slice(&[0xF7 + len_bytes_len]); + header.extend_from_slice(&len_bytes); + + header + } + }; + + let hash = solana_program::keccak::hashv(&[transaction_type, &header, body]).to_bytes(); + + Ok(hash) + } + + fn calculate_legacy_signature( + transaction: &rlp::Rlp, + chain_id: Option, + ) -> Result<[u8; 32], rlp::DecoderError> { + let raw = transaction.as_raw(); + let payload_info = transaction.payload_info()?; + let (_, v_offset) = transaction.at_with_offset(6)?; + + let middle = &raw[payload_info.header_len..v_offset]; + + let trailer = chain_id.map_or_else(Vec::new, |chain_id| { + let chain_id = { + let leading_empty_bytes = (chain_id.leading_zeros() as usize) / 8; + let bytes = chain_id.to_be_bytes(); bytes[leading_empty_bytes..].to_vec() }; - let len_bytes_len: u8 = len_bytes.len().try_into().unwrap(); - let mut header = Vec::with_capacity(10); - header.extend_from_slice(&[0xF7 + len_bytes_len]); - header.extend_from_slice(&len_bytes); + let mut trailer = Vec::with_capacity(64); + match chain_id.len() { + 0 => { + trailer.extend_from_slice(&[0x80]); + } + 1 if chain_id[0] < 0x80 => { + trailer.extend_from_slice(&chain_id); + } + len @ 1..=55 => { + let len: u8 = len.try_into().unwrap(); + + trailer.extend_from_slice(&[0x80 + len]); + trailer.extend_from_slice(&chain_id); + } + _ => { + unreachable!("chain_id.len() <= 32") + } + } + + trailer.extend_from_slice(&[0x80, 0x80]); + trailer + }); + + let header: Vec = { + let len = middle.len() + trailer.len(); + if len <= 55 { + let len: u8 = len.try_into().unwrap(); + vec![0xC0 + len] + } else { + let len_bytes = { + let leading_empty_bytes = (len.leading_zeros() as usize) / 8; + let bytes = len.to_be_bytes(); + bytes[leading_empty_bytes..].to_vec() + }; + let len_bytes_len: u8 = len_bytes.len().try_into().unwrap(); + + let mut header = Vec::with_capacity(10); + header.extend_from_slice(&[0xF7 + len_bytes_len]); + header.extend_from_slice(&len_bytes); - header + header + } + }; + + let hash = solana_program::keccak::hashv(&[&header, middle, &trailer]).to_bytes(); + + Ok(hash) + } +} + +impl Transaction { + pub fn from_rlp(transaction: &[u8]) -> Result { + let (transaction_type, transaction) = TransactionEnvelope::get_type(transaction); + + let tx = match transaction_type { + Some(TransactionEnvelope::Legacy) => { + let legacy_tx = rlp::decode::(transaction).map_err(Error::from)?; + let chain_id = legacy_tx.chain_id; + let tx = TransactionPayload::Legacy(legacy_tx); + Transaction::from_payload( + &Some(TransactionEnvelope::Legacy), + chain_id, + &rlp::Rlp::new(transaction), + tx, + )? + } + Some(TransactionEnvelope::AccessList) => { + let access_list_tx = + rlp::decode::(transaction).map_err(Error::from)?; + let chain_id = access_list_tx.chain_id; + let tx = TransactionPayload::AccessList(access_list_tx); + Transaction::from_payload( + &Some(TransactionEnvelope::AccessList), + Some(chain_id), + &rlp::Rlp::new(transaction), + tx, + )? + } + None => { + let legacy_tx = rlp::decode::(transaction).map_err(Error::from)?; + let chain_id = legacy_tx.chain_id; + let tx = TransactionPayload::Legacy(legacy_tx); + Transaction::from_payload(&None, chain_id, &rlp::Rlp::new(transaction), tx)? + } + Some(TransactionEnvelope::DynamicFee) => unimplemented!(), + }; + + Ok(tx) + } + + pub fn recover_caller_address(&self) -> Result { + use solana_program::keccak::{hash, Hash}; + use solana_program::secp256k1_recover::secp256k1_recover; + + let signature = [self.r().to_be_bytes(), self.s().to_be_bytes()].concat(); + let public_key = secp256k1_recover(&self.signed_hash(), self.recovery_id(), &signature)?; + + let Hash(address) = hash(&public_key.to_bytes()); + let address: [u8; 20] = address[12..32].try_into()?; + + Ok(Address::from(address)) + } + + #[must_use] + pub fn nonce(&self) -> u64 { + match self.transaction { + TransactionPayload::Legacy(LegacyTx { nonce, .. }) + | TransactionPayload::AccessList(AccessListTx { nonce, .. }) => nonce, + } + } + + #[must_use] + pub fn gas_price(&self) -> U256 { + match self.transaction { + TransactionPayload::Legacy(LegacyTx { gas_price, .. }) + | TransactionPayload::AccessList(AccessListTx { gas_price, .. }) => gas_price, + } + } + + #[must_use] + pub fn gas_limit(&self) -> U256 { + match self.transaction { + TransactionPayload::Legacy(LegacyTx { gas_limit, .. }) + | TransactionPayload::AccessList(AccessListTx { gas_limit, .. }) => gas_limit, + } + } + + #[must_use] + pub fn target(&self) -> Option
{ + match self.transaction { + TransactionPayload::Legacy(LegacyTx { target, .. }) + | TransactionPayload::AccessList(AccessListTx { target, .. }) => target, + } + } + + #[must_use] + pub fn value(&self) -> U256 { + match self.transaction { + TransactionPayload::Legacy(LegacyTx { value, .. }) + | TransactionPayload::AccessList(AccessListTx { value, .. }) => value, + } + } + + #[must_use] + pub fn call_data(&self) -> &crate::evm::Buffer { + match &self.transaction { + TransactionPayload::Legacy(LegacyTx { call_data, .. }) + | TransactionPayload::AccessList(AccessListTx { call_data, .. }) => call_data, + } + } + + // Mem replace for call_data to avoid cloning it + #[must_use] + pub fn extract_call_data(&mut self) -> crate::evm::Buffer { + match self.transaction { + TransactionPayload::Legacy(LegacyTx { + ref mut call_data, .. + }) + | TransactionPayload::AccessList(AccessListTx { + ref mut call_data, .. + }) => std::mem::take(call_data), } - }; + } - let hash = solana_program::keccak::hashv(&[&header, middle, &trailer]).to_bytes(); + #[must_use] + pub fn r(&self) -> U256 { + match self.transaction { + TransactionPayload::Legacy(LegacyTx { r, .. }) + | TransactionPayload::AccessList(AccessListTx { r, .. }) => r, + } + } - Ok(hash) + #[must_use] + pub fn s(&self) -> U256 { + match self.transaction { + TransactionPayload::Legacy(LegacyTx { s, .. }) + | TransactionPayload::AccessList(AccessListTx { s, .. }) => s, + } + } + + #[must_use] + pub fn chain_id(&self) -> Option { + match self.transaction { + TransactionPayload::Legacy(LegacyTx { chain_id, .. }) => chain_id, + TransactionPayload::AccessList(AccessListTx { chain_id, .. }) => Some(chain_id), + } + } + + #[must_use] + pub fn recovery_id(&self) -> u8 { + match self.transaction { + TransactionPayload::Legacy(LegacyTx { recovery_id, .. }) + | TransactionPayload::AccessList(AccessListTx { recovery_id, .. }) => recovery_id, + } + } + + #[must_use] + pub fn rlp_len(&self) -> usize { + self.byte_len + } + + #[must_use] + pub fn hash(&self) -> [u8; 32] { + self.hash + } + + #[must_use] + pub fn signed_hash(&self) -> [u8; 32] { + self.signed_hash + } + + #[must_use] + pub fn access_list(&self) -> Option<&Vec<(Address, Vec)>> { + match &self.transaction { + TransactionPayload::AccessList(AccessListTx { access_list, .. }) => Some(access_list), + TransactionPayload::Legacy(_) => None, + } + } } #[inline] diff --git a/evm_loader/tests/conftest.py b/evm_loader/tests/conftest.py index 254653dcb..ef25a219a 100644 --- a/evm_loader/tests/conftest.py +++ b/evm_loader/tests/conftest.py @@ -146,6 +146,21 @@ def string_setter_contract(evm_loader: EvmLoader, operator_keypair: Keypair, ses return deploy_contract(operator_keypair, session_user, "string_setter.binary", evm_loader, treasury_pool) +@pytest.fixture(scope="session") +def calculator_contract(evm_loader: EvmLoader, operator_keypair: Keypair, session_user: Caller, + treasury_pool) -> Contract: + return deploy_contract(operator_keypair, session_user, "Calculator.binary", evm_loader, treasury_pool) + + +@pytest.fixture(scope="session") +def calculator_caller_contract(evm_loader: EvmLoader, operator_keypair: Keypair, session_user: Caller, + treasury_pool, calculator_contract) -> Contract: + constructor_args = eth_abi.encode(['address'], [calculator_contract.eth_address.hex()]) + + return deploy_contract(operator_keypair, session_user, "CalculatorCaller.binary", evm_loader, treasury_pool, + encoded_args=constructor_args) + + @pytest.fixture(scope="session") def neon_api_client(request): client = NeonApiClient(url=request.config.getoption("--neon-api-uri")) diff --git a/evm_loader/tests/contracts/contracts.sol b/evm_loader/tests/contracts/contracts.sol index b51e10c60..988e55d12 100644 --- a/evm_loader/tests/contracts/contracts.sol +++ b/evm_loader/tests/contracts/contracts.sol @@ -100,3 +100,24 @@ contract rw_lock_caller { } } + +contract Calculator { + uint public x = 20; + uint public y = 20; + + function getSum() public view returns (uint256) { + return x + y; + } +} + +contract CalculatorCaller { + Calculator calculator; + + constructor(address _calc) { + calculator = Calculator(_calc); + } + + function callCalculator() public view returns (uint sum) { + sum = calculator.getSum(); + } +} diff --git a/evm_loader/tests/test_execute_trx_from_instruction.py b/evm_loader/tests/test_execute_trx_from_instruction.py index 534b3348d..9af502aeb 100644 --- a/evm_loader/tests/test_execute_trx_from_instruction.py +++ b/evm_loader/tests/test_execute_trx_from_instruction.py @@ -4,8 +4,10 @@ import pytest import solana import eth_abi +from eth_account.datastructures import SignedTransaction from eth_keys import keys as eth_keys from eth_utils import abi, to_text +from hexbytes import HexBytes from solana.keypair import Keypair from solana.publickey import PublicKey from solana.rpc.commitment import Confirmed @@ -275,3 +277,47 @@ def test_operator_does_not_have_enough_founds(self, sender_with_tokens, evm_load [sender_with_tokens.solana_account_address, session_user.solana_account_address], operator_without_money.solana_account) + + def test_transaction_with_access_list(self, operator_keypair, treasury_pool, sender_with_tokens, + evm_loader, calculator_contract, calculator_caller_contract): + access_list = ( + { + "address": '0x' + calculator_contract.eth_address.hex(), + "storageKeys": ( + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000001", + ) + }, + ) + signed_tx = make_contract_call_trx(sender_with_tokens, calculator_caller_contract, "callCalculator()", [], + access_list=access_list) + + resp = execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, + signed_tx, + [sender_with_tokens.solana_account_address, + calculator_caller_contract.solana_address, + calculator_contract.solana_address], + operator_keypair) + + check_transaction_logs_have_text(resp.value, "exit_status=0x12") + + def test_old_trx_type_with_leading_zeros(self, sender_with_tokens, operator_keypair, evm_loader, + calculator_caller_contract, calculator_contract, treasury_pool, + holder_acc): + signed_tx = make_contract_call_trx(sender_with_tokens, calculator_caller_contract, "callCalculator()", []) + new_raw_trx = HexBytes('0x' + (b'\x00' + bytes.fromhex(signed_tx.rawTransaction.hex()[2:])).hex()) + signed_tx_new = SignedTransaction( + rawTransaction=new_raw_trx, + hash=signed_tx.hash, + r=signed_tx.r, + s=signed_tx.s, + v=signed_tx.v, + ) + + resp = execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, + signed_tx_new, + [sender_with_tokens.solana_account_address, + calculator_caller_contract.solana_address, + calculator_contract.solana_address], + operator_keypair) + check_transaction_logs_have_text(resp.value, "exit_status=0x12") diff --git a/evm_loader/tests/test_transaction_step_from_account.py b/evm_loader/tests/test_transaction_step_from_account.py index 4141e60ab..09ccf8322 100644 --- a/evm_loader/tests/test_transaction_step_from_account.py +++ b/evm_loader/tests/test_transaction_step_from_account.py @@ -1,4 +1,3 @@ -import json import random import string import time @@ -15,6 +14,7 @@ from .solana_utils import get_neon_balance, solana_client, neon_cli, execute_transaction_steps_from_account, \ write_transaction_to_holder_account, create_treasury_pool_address, send_transaction_step_from_account +from .test_cli import gen_hash_of_block from .utils.assert_messages import InstructionAsserts from .utils.constants import TAG_FINALIZED_STATE from .utils.contract import make_deployment_transaction, make_contract_call_trx, deploy_contract @@ -26,6 +26,17 @@ from .utils.types import TreasuryPool +def generate_access_lists(): + addr1 = gen_hash_of_block(20) + addr2 = gen_hash_of_block(20) + key1, key2, key3, key4 = (f"0x000000000000000000000000000000000000000000000000000000000000000{item}" for item in + (0, 1, 2, 3)) + return (({"address": addr1, "storageKeys": []},), + ({"address": addr1, "storageKeys": (key1, key2, key3, key4)},), + ({"address": addr1, "storageKeys": (key1, key2)}, {"address": addr2, "storageKeys": []}), + ({"address": addr1, "storageKeys": (key1, key2)}, {"address": addr2, "storageKeys": (key3,)})) + + class TestTransactionStepFromAccount: def test_simple_transfer_transaction(self, operator_keypair, treasury_pool, evm_loader, @@ -307,6 +318,49 @@ def test_incorrect_holder_account(self, sender_with_tokens, operator_keypair, ev [sender_with_tokens.solana_account_address, session_user.solana_account_address], 1, operator_keypair) + def test_transaction_with_access_list(self, operator_keypair, holder_acc, treasury_pool, + sender_with_tokens, evm_loader, calculator_contract, + calculator_caller_contract): + access_list = ( + { + "address": '0x' + calculator_contract.eth_address.hex(), + "storageKeys": ( + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000001", + ) + }, + ) + signed_tx = make_contract_call_trx(sender_with_tokens, calculator_caller_contract, "callCalculator()", [], + access_list=access_list) + write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) + + resp = execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, + [calculator_caller_contract.solana_address, + calculator_contract.solana_address, + sender_with_tokens.solana_account_address]) + + check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) + check_transaction_logs_have_text(resp.value.transaction.transaction.signatures[0], "exit_status=0x12") + + @pytest.mark.parametrize("access_list", generate_access_lists()) + def test_access_list_structure(self, operator_keypair, holder_acc, treasury_pool, evm_loader, + sender_with_tokens, string_setter_contract, access_list): + text = ''.join(random.choice(string.ascii_letters) for _ in range(10)) + + signed_tx = make_contract_call_trx(sender_with_tokens, string_setter_contract, "set(string)", [text], + value=10, access_list=access_list) + write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) + resp = execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, + [string_setter_contract.solana_address, + sender_with_tokens.solana_account_address]) + + check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) + check_transaction_logs_have_text(resp.value.transaction.transaction.signatures[0], "exit_status=0x11") + + assert text in to_text( + neon_cli().call_contract_get_function(evm_loader, sender_with_tokens, string_setter_contract, + "get()")) + class TestAccountStepContractCallContractInteractions: def test_contract_call_unchange_storage_function(self, rw_lock_contract, rw_lock_caller, session_user, evm_loader, @@ -358,9 +412,9 @@ def test_contract_call_update_storage_map_function(self, rw_lock_contract, sessi func_name = abi.function_signature_to_4byte_selector('update_storage_map(uint256)') data = func_name + eth_abi.encode(['uint256'], [3]) result = neon_cli().emulate(evm_loader.loader_id, - session_user.eth_address.hex(), - rw_lock_caller.eth_address.hex(), - data.hex()) + session_user.eth_address.hex(), + rw_lock_caller.eth_address.hex(), + data.hex()) additional_accounts = [session_user.solana_account_address, rw_lock_contract.solana_address, rw_lock_caller.solana_address] for acc in result['solana_accounts']: @@ -469,9 +523,10 @@ def test_next_operator_can_continue_trx_after_some_time(self, rw_lock_contract, # next operator can't continue trx during OPERATOR_PRIORITY_SLOTS*0.4 with pytest.raises(solana.rpc.core.RPCException, - match=rf"{InstructionAsserts.INVALID_OPERATOR_KEY}|{InstructionAsserts.INVALID_HOLDER_OWNER}"): send_transaction_step_from_account(second_operator_keypair, evm_loader, treasury_pool, new_holder_acc, - [user_account.solana_account_address, - rw_lock_contract.solana_address], 500, second_operator_keypair) + match=rf"{InstructionAsserts.INVALID_OPERATOR_KEY}|{InstructionAsserts.INVALID_HOLDER_OWNER}"): send_transaction_step_from_account( + second_operator_keypair, evm_loader, treasury_pool, new_holder_acc, + [user_account.solana_account_address, + rw_lock_contract.solana_address], 500, second_operator_keypair) time.sleep(15) send_transaction_step_from_account(second_operator_keypair, evm_loader, treasury_pool, new_holder_acc, diff --git a/evm_loader/tests/test_transaction_step_from_account_no_chainid.py b/evm_loader/tests/test_transaction_step_from_account_no_chainid.py index c53ab0528..f51399942 100644 --- a/evm_loader/tests/test_transaction_step_from_account_no_chainid.py +++ b/evm_loader/tests/test_transaction_step_from_account_no_chainid.py @@ -1,11 +1,13 @@ import random import string +import solana import pytest from eth_utils import to_text from .solana_utils import write_transaction_to_holder_account, get_neon_balance, solana_client, \ execute_transaction_steps_from_account_no_chain_id, neon_cli +from .utils.assert_messages import InstructionAsserts from .utils.constants import TAG_FINALIZED_STATE from .utils.contract import make_deployment_transaction, make_contract_call_trx from .utils.ethereum import make_eth_transaction, create_contract_address @@ -88,3 +90,25 @@ def test_call_contract_function_with_neon_transfer(self, operator_keypair, treas assert text in to_text( neon_cli().call_contract_get_function(evm_loader, sender_with_tokens, string_setter_contract, "get()")) + + def test_transaction_with_access_list(self, operator_keypair, treasury_pool, + sender_with_tokens, calculator_contract, calculator_caller_contract, + holder_acc, evm_loader): + access_list = ( + { + "address": '0x' + calculator_contract.eth_address.hex(), + "storageKeys": ( + "0x0000000000000000000000000000000000000000000000000000000000000000", + ) + }, + ) + signed_tx = make_contract_call_trx(sender_with_tokens, calculator_caller_contract, "callCalculator()", [], + chain_id=None, access_list=access_list) + write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) + with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.INVALID_CHAIN_ID): + execute_transaction_steps_from_account_no_chain_id(operator_keypair, evm_loader, treasury_pool, + holder_acc, + [calculator_contract.solana_address, + calculator_caller_contract.solana_address, + sender_with_tokens.solana_account_address] + ) diff --git a/evm_loader/tests/test_transaction_step_from_instruction.py b/evm_loader/tests/test_transaction_step_from_instruction.py index f3564bd68..76e808bf6 100644 --- a/evm_loader/tests/test_transaction_step_from_instruction.py +++ b/evm_loader/tests/test_transaction_step_from_instruction.py @@ -1,4 +1,3 @@ -import json import random import string import time @@ -307,6 +306,54 @@ def test_incorrect_holder_account(self, sender_with_tokens, operator_keypair, ev [sender_with_tokens.solana_account_address, session_user.solana_account_address], 1, operator_keypair) + @pytest.mark.parametrize("value", [0, 10]) + def test_transaction_with_access_list(self, operator_keypair, treasury_pool, sender_with_tokens, + evm_loader, holder_acc, + string_setter_contract, value): + access_list = ( + { + "address": '0x' + string_setter_contract.eth_address.hex(), + "storageKeys": ( + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000001", + ) + }, + ) + signed_tx = make_contract_call_trx(sender_with_tokens, string_setter_contract, "set(string)", ["text"], + value=value, access_list=access_list) + resp = execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, + signed_tx, [string_setter_contract.solana_address, + sender_with_tokens.solana_account_address] + ) + + check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) + check_transaction_logs_have_text(resp.value, "exit_status=0x11") + + def test_deploy_contract_with_access_list(self, operator_keypair, holder_acc, treasury_pool, evm_loader, + sender_with_tokens): + contract_filename = "small.binary" + contract = create_contract_address(sender_with_tokens, evm_loader) + + access_list = ( + { + "address": contract.eth_address.hex(), + "storageKeys": ( + "0x0000000000000000000000000000000000000000000000000000000000000000", + ) + }, + ) + signed_tx = make_deployment_transaction(sender_with_tokens, contract_filename, access_list=access_list) + contract_path = pytest.CONTRACTS_PATH / contract_filename + with open(contract_path, 'rb') as f: + contract_code = f.read() + + steps_count = neon_cli().get_steps_count(evm_loader, sender_with_tokens, "deploy", contract_code.hex()) + resp = execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, + signed_tx, [contract.solana_address, + sender_with_tokens.solana_account_address], + steps_count) + check_transaction_logs_have_text(resp.value, "exit_status=0x12") + class TestInstructionStepContractCallContractInteractions: def test_contract_call_unchange_storage_function(self, rw_lock_contract, session_user, evm_loader, operator_keypair, @@ -502,5 +549,25 @@ def test_add_waste_to_trx_without_decoding(self, sender_with_tokens, operator_ke ) with pytest.raises(RPCException, match="Program log: RLP error: RlpInconsistentLengthAndData"): execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, - signed_tx_new, [sender_with_tokens.solana_account_address, - string_setter_contract.solana_address]) + signed_tx_new, [sender_with_tokens.solana_account_address, + string_setter_contract.solana_address]) + + def test_old_trx_type_with_leading_zeros(self, sender_with_tokens, operator_keypair, evm_loader, + string_setter_contract, treasury_pool, holder_acc): + text = ''.join(random.choice(string.ascii_letters) for _ in range(10)) + + signed_tx = make_contract_call_trx(sender_with_tokens, string_setter_contract, "set(string)", [text]) + new_raw_trx = HexBytes('0x' + (b'\x00' + bytes.fromhex(signed_tx.rawTransaction.hex()[2:])).hex()) + signed_tx_new = SignedTransaction( + rawTransaction=new_raw_trx, + hash=signed_tx.hash, + r=signed_tx.r, + s=signed_tx.s, + v=signed_tx.v, + ) + + resp = execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, + signed_tx_new, [string_setter_contract.solana_address, + sender_with_tokens.solana_account_address] + ) + check_transaction_logs_have_text(resp.value, "exit_status=0x11") diff --git a/evm_loader/tests/utils/contract.py b/evm_loader/tests/utils/contract.py index d01d0bbcf..21bc071c4 100644 --- a/evm_loader/tests/utils/contract.py +++ b/evm_loader/tests/utils/contract.py @@ -10,7 +10,7 @@ from .types import Caller, TreasuryPool from ..solana_utils import solana_client, \ get_transaction_count, EvmLoader, write_transaction_to_holder_account, \ - send_transaction_step_from_account, neon_cli + send_transaction_step_from_account from .storage import create_holder from .ethereum import create_contract_address, make_eth_transaction @@ -21,7 +21,7 @@ def make_deployment_transaction( user: Caller, contract_path: tp.Union[pathlib.Path, str], encoded_args=None, - gas: int = 999999999, chain_id=111 + gas: int = 999999999, chain_id=111, access_list=None ) -> SignedTransaction: if isinstance(contract_path, str): contract_path = pathlib.Path(contract_path) @@ -41,13 +41,17 @@ def make_deployment_transaction( 'nonce': get_transaction_count(solana_client, user.solana_account_address), 'data': data } - if chain_id is not None: + if chain_id: tx['chainId'] = chain_id + if access_list: + tx['accessList'] = access_list + tx['type'] = 1 print(tx) return w3.eth.account.sign_transaction(tx, user.solana_account.secret_key[:32]) -def make_contract_call_trx(user, contract, function_signature, params=None, value=0, chain_id=111): +def make_contract_call_trx(user, contract, function_signature, params=None, value=0, chain_id=111, access_list=None, + trx_type=None): data = abi.function_signature_to_4byte_selector(function_signature) if params is not None: @@ -58,7 +62,7 @@ def make_contract_call_trx(user, contract, function_signature, params=None, valu data += eth_abi.encode(['string'], [param]) signed_tx = make_eth_transaction(contract.eth_address, data, user.solana_account, user.solana_account_address, - value=value, chain_id=chain_id) + value=value, chain_id=chain_id, access_list=access_list, type=trx_type) return signed_tx diff --git a/evm_loader/tests/utils/ethereum.py b/evm_loader/tests/utils/ethereum.py index cb3b01a7b..0c8cb4a0f 100644 --- a/evm_loader/tests/utils/ethereum.py +++ b/evm_loader/tests/utils/ethereum.py @@ -1,4 +1,3 @@ -from dataclasses import dataclass from typing import Union from base58 import b58encode @@ -13,8 +12,6 @@ from ..solana_utils import EvmLoader, solana_client, get_transaction_count - - def create_contract_address(user: Caller, evm_loader: EvmLoader) -> Contract: # Create contract address from (caller_address, nonce) user_nonce = get_transaction_count(solana_client, user.solana_account_address) @@ -31,7 +28,7 @@ def create_contract_address(user: Caller, evm_loader: EvmLoader) -> Contract: def make_eth_transaction(to_addr: bytes, data: Union[bytes, None], signer: Keypair, from_solana_user: PublicKey, - value: int = 0, chain_id = 111, gas = 9999999999): + value: int = 0, chain_id=111, gas=9999999999, access_list=None, type=None): nonce = get_transaction_count(solana_client, from_solana_user) tx = {'to': to_addr, 'value': value, 'gas': gas, 'gasPrice': 0, 'nonce': nonce} @@ -42,5 +39,8 @@ def make_eth_transaction(to_addr: bytes, data: Union[bytes, None], signer: Keypa if data is not None: tx['data'] = data + if access_list is not None: + tx['accessList'] = access_list + if type is not None: + tx['type'] = type return w3.eth.account.sign_transaction(tx, signer.secret_key[:32]) - From 8c20d642a59a2e7daa3db0a4d4849fa01afc779e Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 4 Sep 2023 14:56:27 +0300 Subject: [PATCH 012/318] NDEV-2059: Improve performance of get_account_rooted_slot, get_branch_slots, get_sol_sig_rooted_slot (#181) --- evm_loader/lib/src/types/tracer_ch_db.rs | 63 +++++++++++++++--------- 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/evm_loader/lib/src/types/tracer_ch_db.rs b/evm_loader/lib/src/types/tracer_ch_db.rs index d3596d561..62f08b05d 100644 --- a/evm_loader/lib/src/types/tracer_ch_db.rs +++ b/evm_loader/lib/src/types/tracer_ch_db.rs @@ -49,6 +49,22 @@ pub struct SlotParent { pub status: u8, } +#[derive(Debug, Row, serde::Deserialize, Clone)] +pub struct SlotParentRooted { + pub slot: u64, + pub parent: Option, +} + +impl From for SlotParent { + fn from(slot_parent_rooted: SlotParentRooted) -> Self { + SlotParent { + slot: slot_parent_rooted.slot, + parent: slot_parent_rooted.parent, + status: SlotStatus::Rooted as u8, + } + } +} + impl SlotParent { fn is_rooted(&self) -> bool { self.status == SlotStatus::Rooted as u8 @@ -170,13 +186,12 @@ impl ClickHouseDb { SELECT DISTINCT ON (slot, parent) slot, parent, status FROM events.update_slot WHERE slot >= ( - SELECT slot - ? - FROM events.update_slot - WHERE status = 'Rooted' - ORDER BY slot DESC - LIMIT 1 - ) - AND isNotNull(parent) + SELECT slot - ? + FROM events.rooted_slots + ORDER BY slot DESC + LIMIT 1 + ) + AND isNotNull(parent) ORDER BY slot DESC, status DESC "#; let time_start = Instant::now(); @@ -229,18 +244,19 @@ impl ClickHouseDb { async fn get_account_rooted_slot(&self, key: &str, slot: u64) -> ChResult> { info!("get_account_rooted_slot {{ key: {key}, slot: {slot} }}"); + let query = r#" - SELECT DISTINCT slot - FROM events.update_account_distributed - WHERE pubkey = ? - AND slot <= ? - AND slot IN ( - SELECT slot - FROM events.update_slot - WHERE status = 'Rooted' - ) - ORDER BY slot DESC - LIMIT 1 + SELECT DISTINCT uad.slot + FROM events.update_account_distributed AS uad + WHERE uad.pubkey = ? + AND uad.slot <= ? + AND ( + SELECT COUNT(slot) + FROM events.rooted_slots + WHERE slot = ? + ) >= 1 + ORDER BY uad.slot DESC + LIMIT 1 "#; let time_start = Instant::now(); @@ -249,6 +265,7 @@ impl ClickHouseDb { .query(query) .bind(key) .bind(slot) + .bind(slot) .fetch_one::() .await, )?; @@ -368,14 +385,13 @@ impl ClickHouseDb { async fn get_sol_sig_rooted_slot(&self, sol_sig: &[u8; 64]) -> ChResult> { let query = r#" - SELECT slot, parent, status - FROM events.update_slot + SELECT slot, parent + FROM events.rooted_slots WHERE slot IN ( SELECT slot FROM events.notify_transaction_distributed WHERE signature = ? ) - AND status = 'Rooted' ORDER BY slot DESC LIMIT 1 "#; @@ -384,9 +400,12 @@ impl ClickHouseDb { self.client .query(query) .bind(sol_sig.as_slice()) - .fetch_one::() + .fetch_one::() .await, ) + .map(|slot_parent_rooted_opt| { + slot_parent_rooted_opt.map(|slot_parent_rooted| slot_parent_rooted.into()) + }) .map_err(|e| { println!("get_sol_sig_rooted_slot error: {e}"); ChError::Db(e) From e2b78b2bac827c13581efdf449843c724aa3a205 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Tue, 5 Sep 2023 10:00:51 +0300 Subject: [PATCH 013/318] NDEV-2115: Replace default_features with default-features (#174) --- evm_loader/api/Cargo.toml | 4 ++-- evm_loader/cli/Cargo.toml | 4 ++-- evm_loader/lib/Cargo.toml | 8 ++++---- evm_loader/program/Cargo.toml | 12 ++++++------ 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 464d8a992..73492c2ed 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -7,11 +7,11 @@ edition = "2021" [dependencies] clap = "2.33.3" -evm-loader = { path = "../program", default_features = false, features = ["log"] } +evm-loader = { path = "../program", default-features = false, features = ["log"] } solana-sdk = "=1.14.20" serde = "1.0.186" serde_json = "1.0.85" -ethnum = { version = "1", default_features = false, features = ["serde"] } +ethnum = { version = "1", default-features = false, features = ["serde"] } tokio = { version = "1", features = ["full"] } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index 791c9d192..424f5b466 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] clap = "2.33.3" -evm-loader = { path = "../program", default_features = false, features = ["log"] } +evm-loader = { path = "../program", default-features = false, features = ["log"] } solana-sdk = "=1.14.20" solana-client = "=1.14.20" solana-clap-utils = "=1.14.20" @@ -17,6 +17,6 @@ serde = "1.0.186" serde_json = "1.0.85" log = "0.4.17" fern = "0.6" -ethnum = { version = "1", default_features = false, features = ["serde"] } +ethnum = { version = "1", default-features = false, features = ["serde"] } tokio = { version = "1", features = ["full"] } neon-lib = { path = "../lib" } diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 87ae35a45..aeb7dc738 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -8,22 +8,22 @@ edition = "2021" [dependencies] thiserror = "1.0" bincode = "1.3.1" -evm-loader = { path = "../program", default_features = false, features = ["log", "tracing"] } +evm-loader = { path = "../program", default-features = false, features = ["log", "tracing"] } solana-sdk = "=1.14.20" solana-client = "=1.14.20" solana-clap-utils = "=1.14.20" solana-cli-config = "=1.14.20" solana-cli = "=1.14.20" solana-transaction-status = "=1.14.20" -spl-token = { version = "~3.5", default_features = false, features = ["no-entrypoint"] } -spl-associated-token-account = { version = "~1.1", default_features = false, features = ["no-entrypoint"] } +spl-token = { version = "~3.5", default-features = false, features = ["no-entrypoint"] } +spl-associated-token-account = { version = "~1.1", default-features = false, features = ["no-entrypoint"] } bs58 = "0.4.0" hex = "0.4.2" serde = "1.0.186" serde_json = "1.0.105" log = "0.4.17" rand = "0.8" -ethnum = { version = "1", default_features = false, features = ["serde"] } +ethnum = { version = "1", default-features = false, features = ["serde"] } goblin = { version = "0.6.0" } scroll = "0.11.0" tokio = { version = "1", features = ["full"] } diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 94fb50cbe..220833e80 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -37,12 +37,12 @@ default = ["custom-heap"] tracing = ["serde_json"] [dependencies] -linked_list_allocator = { version = "0.10", default_features = false } +linked_list_allocator = { version = "0.10", default-features = false } evm-loader-macro = { path = "../program-macro" } -solana-program = { version = "=1.14.20", default_features = false } -spl-token = { version = "~3.5", default_features = false, features = ["no-entrypoint"] } -spl-associated-token-account = { version = "~1.1", default_features = false, features = ["no-entrypoint"] } -mpl-token-metadata = { version = "1.12", default_features = false, features = ["no-entrypoint"] } +solana-program = { version = "=1.14.20", default-features = false } +spl-token = { version = "~3.5", default-features = false, features = ["no-entrypoint"] } +spl-associated-token-account = { version = "~1.1", default-features = false, features = ["no-entrypoint"] } +mpl-token-metadata = { version = "1.12", default-features = false, features = ["no-entrypoint"] } thiserror = "1.0" arrayref = "0.3.6" hex = "0.4.2" @@ -54,7 +54,7 @@ bincode = "1" serde_bytes = "0.11.12" serde = { version = "1.0.186", default-features = false, features = ["derive", "rc"] } serde_json = { version = "1.0.105", optional = true } -ethnum = { version = "1", default_features = false, features = ["serde"] } +ethnum = { version = "1", default-features = false, features = ["serde"] } const_format = { version = "0.2.21" } cfg-if = { version = "1.0" } log = { version = "0.4", default-features = false, optional = true } From 85312dad5c94b50f3f8791bb64db99f4de9d3e24 Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 5 Sep 2023 18:41:05 +0300 Subject: [PATCH 014/318] NDEV-2160: Improve account data printing (#183) --- evm_loader/lib/src/types/tracer_ch_db.rs | 42 ++++++++++++++++++++---- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/evm_loader/lib/src/types/tracer_ch_db.rs b/evm_loader/lib/src/types/tracer_ch_db.rs index 62f08b05d..4571f7439 100644 --- a/evm_loader/lib/src/types/tracer_ch_db.rs +++ b/evm_loader/lib/src/types/tracer_ch_db.rs @@ -13,6 +13,7 @@ use std::{ Ordering::{Equal, Greater, Less}, }, convert::TryFrom, + fmt, sync::Arc, time::Instant, }; @@ -71,14 +72,41 @@ impl SlotParent { } } -#[derive(Debug, Row, serde::Deserialize, Clone)] +#[derive(Row, serde::Deserialize, Clone)] pub struct AccountRow { - owner: Vec, - lamports: u64, - executable: bool, - rent_epoch: u64, - data: Vec, - txn_signature: Vec>, + pub owner: Vec, + pub lamports: u64, + pub executable: bool, + pub rent_epoch: u64, + pub data: Vec, + pub txn_signature: Vec>, +} + +impl fmt::Display for AccountRow { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "AccountRow {{\n owner: {},\n lamports: {},\n executable: {},\n rent_epoch: {},\n}}", + bs58::encode(&self.owner).into_string(), + self.lamports, + self.executable, + self.rent_epoch, + ) + } +} + +impl fmt::Debug for AccountRow { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Account") + .field( + "owner", + &format!("{}", bs58::encode(&self.owner).into_string()), + ) + .field("lamports", &self.lamports) + .field("executable", &self.executable) + .field("rent_epoch", &self.rent_epoch) + .finish() + } } impl TryInto for AccountRow { From 690fd47be2364e2f2a41deeba22a56cf41a5c76e Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Wed, 6 Sep 2023 09:43:00 +0300 Subject: [PATCH 015/318] NDEV-2155: Use neon-evm-1 runners (#182) --- .github/workflows/pipeline.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index 1eed8e3c1..ed3814394 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -20,7 +20,7 @@ concurrency: cancel-in-progress: true jobs: build-neon-evm: - runs-on: build-runner + runs-on: neon-evm-1 steps: - uses: actions/checkout@v3 with: @@ -66,7 +66,7 @@ jobs: --is_draft=${{github.event.pull_request.draft}} \ --labels='${{ toJson(github.event.pull_request.labels.*.name) }}' finalize-image: - runs-on: build-runner + runs-on: neon-evm-1 needs: - trigger-proxy-tests - run-neon-evm-tests From 12bbb9ba12b034f838f422c464b4ce27825e36ba Mon Sep 17 00:00:00 2001 From: Denis Date: Wed, 6 Sep 2023 13:38:33 +0300 Subject: [PATCH 016/318] NDEV-2133: Implement a mechanism to obtain NEON_REVISION (#184) * NDEV-2133: Implement a mechanism to obtain NEON_REVISION * NDEV-2133: Make get_elf_parameter fail-safe --- evm_loader/Cargo.lock | 1 + evm_loader/lib/Cargo.toml | 1 + evm_loader/lib/src/commands/get_neon_elf.rs | 63 ++++++++++++++++++++- evm_loader/lib/src/types/tracer_ch_db.rs | 45 +++++++++++++++ 4 files changed, 108 insertions(+), 2 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 68eb73a2a..af1448be4 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -2225,6 +2225,7 @@ dependencies = [ name = "neon-lib" version = "0.1.0" dependencies = [ + "anyhow", "async-trait", "axum", "bincode", diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index aeb7dc738..e0057cae0 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" [dependencies] thiserror = "1.0" +anyhow = "1.0" bincode = "1.3.1" evm-loader = { path = "../program", default-features = false, features = ["log", "tracing"] } solana-sdk = "=1.14.20" diff --git a/evm_loader/lib/src/commands/get_neon_elf.rs b/evm_loader/lib/src/commands/get_neon_elf.rs index 54aada9f6..7e5f039d1 100644 --- a/evm_loader/lib/src/commands/get_neon_elf.rs +++ b/evm_loader/lib/src/commands/get_neon_elf.rs @@ -1,11 +1,11 @@ -use std::{collections::HashMap, convert::TryFrom, fs::File, io::Read}; - +use anyhow::{Context as AContext, Result}; use solana_sdk::{ account_utils::StateMut, bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable::{self, UpgradeableLoaderState}, pubkey::Pubkey, }; +use std::{collections::HashMap, convert::TryFrom, fs::File, io::Read}; use crate::{context::Context, errors::NeonError, Config, NeonResult}; @@ -82,6 +82,65 @@ pub fn read_elf_parameters(_config: &Config, program_data: &[u8]) -> GetNeonElfR result } +pub fn get_elf_parameter(data: &[u8], elf_parameter: &str) -> Result { + let offset = UpgradeableLoaderState::size_of_programdata_metadata(); + let program_data = &data[offset..]; + + let elf = goblin::elf::Elf::parse(program_data).context("Unable to parse ELF file")?; + let ctx = goblin::container::Ctx::new( + if elf.is_64 { + goblin::container::Container::Big + } else { + goblin::container::Container::Little + }, + if elf.little_endian { + scroll::Endian::Little + } else { + scroll::Endian::Big + }, + ); + + let (num_syms, offset) = elf + .section_headers + .into_iter() + .find(|section| section.sh_type == goblin::elf::section_header::SHT_DYNSYM) + .map(|section| (section.sh_size / section.sh_entsize, section.sh_offset)) + .ok_or_else(|| anyhow::anyhow!("SHT_DYNSYM section not found"))?; + + let dynsyms = goblin::elf::Symtab::parse( + program_data, + offset.try_into().context("Offset too large")?, + num_syms.try_into().context("Count too large")?, + ctx, + ) + .context("Error parsing Symtab")?; + + for sym in dynsyms.iter() { + let name = &elf.dynstrtab[sym.st_name]; + if name == elf_parameter { + let end = program_data.len(); + let from: usize = usize::try_from(sym.st_value) + .map_err(|_| anyhow::anyhow!("Unable to cast usize from u64:{:?}", sym.st_value))?; + let to: usize = usize::try_from(sym.st_value + sym.st_size).map_err(|err| { + anyhow::anyhow!( + "Unable to cast usize from u64:{:?}. Error: {err}", + sym.st_value + sym.st_size + ) + })?; + + if to < end && from < end { + let buf = &program_data[from..to]; + let value = std::str::from_utf8(buf).context("Read ELF value error")?; + return Ok(String::from(value)); + } else { + return Err(anyhow::anyhow!("{name} is out of bounds")); + } + } + } + + Err(anyhow::anyhow!("ELF parameter not found")) +} + pub async fn read_elf_parameters_from_account( config: &Config, context: &Context, diff --git a/evm_loader/lib/src/types/tracer_ch_db.rs b/evm_loader/lib/src/types/tracer_ch_db.rs index 4571f7439..25172cf0f 100644 --- a/evm_loader/lib/src/types/tracer_ch_db.rs +++ b/evm_loader/lib/src/types/tracer_ch_db.rs @@ -1,3 +1,5 @@ +use crate::commands::get_neon_elf::get_elf_parameter; + use super::ChDbConfig; use clickhouse::{Client, Row}; use log::{debug, info}; @@ -563,6 +565,49 @@ impl ClickHouseDb { } } + pub async fn get_neon_revision(&self, slot: Slot, pubkey: &Pubkey) -> ChResult { + let query = r#"SELECT data + FROM events.update_account_distributed + WHERE + pubkey = ? + ORDER BY + abs(? - slot) ASC, + pubkey ASC, + slot ASC, + write_version ASC + LIMIT 1 + "#; + + let pubkey_str = format!("{:?}", pubkey.to_bytes()); + + let data = Self::row_opt( + self.client + .query(query) + .bind(pubkey_str) + .bind(slot) + .fetch_one::>() + .await, + )?; + + match data { + Some(data) => { + let neon_revision = + get_elf_parameter(data.as_slice(), "NEON_REVISION").map_err(|e| { + ChError::Db(clickhouse::error::Error::Custom(format!( + "Failed to get NEON_REVISION, error: {e:?}", + ))) + })?; + Ok(neon_revision) + } + None => { + let err = clickhouse::error::Error::Custom(format!( + "get_neon_revision: for slot {slot} and pubkey {pubkey} not found", + )); + Err(ChError::Db(err)) + } + } + } + fn row_opt(result: clickhouse::error::Result) -> clickhouse::error::Result> { match result { Ok(row) => Ok(Some(row)), From 2716ff06d099f366fa9f32b56ce27cdbde6a025c Mon Sep 17 00:00:00 2001 From: Kristina Nikolaeva <112946046+kristinaNikolaevaa@users.noreply.github.com> Date: Wed, 6 Sep 2023 14:07:26 +0300 Subject: [PATCH 017/318] Changing file permissions (#185) --- evm_loader/create-test-accounts.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 evm_loader/create-test-accounts.sh diff --git a/evm_loader/create-test-accounts.sh b/evm_loader/create-test-accounts.sh old mode 100644 new mode 100755 From b5663a322227c7a874a27bf8c5b191e766911650 Mon Sep 17 00:00:00 2001 From: Stanislav Tkach Date: Fri, 8 Sep 2023 17:06:52 +0200 Subject: [PATCH 018/318] Update the 'ethnum' crate version and remove serialization workaround (#187) --- evm_loader/Cargo.lock | 4 +- evm_loader/api/Cargo.toml | 2 +- evm_loader/cli/Cargo.toml | 2 +- evm_loader/lib/Cargo.toml | 2 +- evm_loader/program/Cargo.toml | 2 +- evm_loader/program/src/executor/action.rs | 63 ++--------------------- 6 files changed, 9 insertions(+), 66 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index af1448be4..c71ce4ef5 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -1183,9 +1183,9 @@ dependencies = [ [[package]] name = "ethnum" -version = "1.3.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0198b9d0078e0f30dedc7acbb21c974e838fc8fae3ee170128658a98cb2c1c04" +checksum = "6c8ff382b2fa527fb7fb06eeebfc5bbb3f17e3cc6b9d70b006c41daa8824adac" dependencies = [ "serde", ] diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 73492c2ed..e164c5040 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -11,7 +11,7 @@ evm-loader = { path = "../program", default-features = false, features = ["log"] solana-sdk = "=1.14.20" serde = "1.0.186" serde_json = "1.0.85" -ethnum = { version = "1", default-features = false, features = ["serde"] } +ethnum = { version = "1.4", default-features = false, features = ["serde"] } tokio = { version = "1", features = ["full"] } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index 424f5b466..5f3ec4e4e 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -17,6 +17,6 @@ serde = "1.0.186" serde_json = "1.0.85" log = "0.4.17" fern = "0.6" -ethnum = { version = "1", default-features = false, features = ["serde"] } +ethnum = { version = "1.4", default-features = false, features = ["serde"] } tokio = { version = "1", features = ["full"] } neon-lib = { path = "../lib" } diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index e0057cae0..0123bd96a 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -24,7 +24,7 @@ serde = "1.0.186" serde_json = "1.0.105" log = "0.4.17" rand = "0.8" -ethnum = { version = "1", default-features = false, features = ["serde"] } +ethnum = { version = "1.4", default-features = false, features = ["serde"] } goblin = { version = "0.6.0" } scroll = "0.11.0" tokio = { version = "1", features = ["full"] } diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 220833e80..65c02e5bf 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -54,7 +54,7 @@ bincode = "1" serde_bytes = "0.11.12" serde = { version = "1.0.186", default-features = false, features = ["derive", "rc"] } serde_json = { version = "1.0.105", optional = true } -ethnum = { version = "1", default-features = false, features = ["serde"] } +ethnum = { version = "1.4", default-features = false, features = ["serde"] } const_format = { version = "0.2.21" } cfg-if = { version = "1.0" } log = { version = "0.4", default-features = false, optional = true } diff --git a/evm_loader/program/src/executor/action.rs b/evm_loader/program/src/executor/action.rs index 30bd51c3d..45405f946 100644 --- a/evm_loader/program/src/executor/action.rs +++ b/evm_loader/program/src/executor/action.rs @@ -17,17 +17,17 @@ pub enum Action { NeonTransfer { source: Address, target: Address, - #[serde(with = "serde_u256")] + #[serde(with = "ethnum::serde::bytes::le")] value: U256, }, NeonWithdraw { source: Address, - #[serde(with = "serde_u256")] + #[serde(with = "ethnum::serde::bytes::le")] value: U256, }, EvmSetStorage { address: Address, - #[serde(with = "serde_u256")] + #[serde(with = "ethnum::serde::bytes::le")] index: U256, #[serde(with = "serde_bytes_32")] value: [u8; 32], @@ -92,63 +92,6 @@ mod serde_bytes_32 { } } -mod serde_u256 { - use ethnum::U256; - use serde::{ - de::{self, SeqAccess, Visitor}, - Deserializer, Serializer, - }; - - pub fn serialize(value: &U256, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_bytes(&value.to_le_bytes()) - } - - pub fn deserialize<'de, D>(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - deserializer.deserialize_bytes(U256Visitor {}) - } - - struct U256Visitor {} - - impl<'de> Visitor<'de> for U256Visitor { - type Value = U256; - - fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.write_str("32 bytes in little endian") - } - - fn visit_bytes(self, v: &[u8]) -> Result - where - E: de::Error, - { - let bytes = v - .try_into() - .map_err(|_| E::invalid_length(v.len(), &self))?; - Ok(U256::from_le_bytes(bytes)) - } - - fn visit_seq(self, mut seq: S) -> Result - where - S: SeqAccess<'de>, - { - let mut bytes = Vec::with_capacity(32); - while let Some(b) = seq.next_element()? { - bytes.push(b); - } - Ok(U256::from_le_bytes( - bytes - .try_into() - .map_err(|_| de::Error::custom("Invalid U256 value"))?, - )) - } - } -} - #[cfg(test)] mod tests { use super::*; From 3f334b232920694bb83db413d5d8d739794e32cb Mon Sep 17 00:00:00 2001 From: Andrey Falaleev Date: Sun, 10 Sep 2023 22:25:28 +0000 Subject: [PATCH 019/318] Set version v1.5.0-dev (#190) --- evm_loader/Cargo.lock | 4 ++-- evm_loader/cli/Cargo.toml | 2 +- evm_loader/program/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index c71ce4ef5..bef2baac8 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -1198,7 +1198,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "evm-loader" -version = "1.3.0-dev" +version = "1.5.0-dev" dependencies = [ "arrayref", "bincode", @@ -2203,7 +2203,7 @@ dependencies = [ [[package]] name = "neon-cli" -version = "1.3.0-dev" +version = "1.5.0-dev" dependencies = [ "clap 2.34.0", "ethnum", diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index 5f3ec4e4e..695e10fb6 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "neon-cli" -version = "1.3.0-dev" +version = "1.5.0-dev" authors = ["NeonLabs Maintainers "] edition = "2021" diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 65c02e5bf..bd82f4696 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "evm-loader" -version = "1.3.0-dev" +version = "1.5.0-dev" description = "Neon EVM loader" authors = ["NeonLabs Maintainers "] edition = "2021" From aa95abaeeca05e76f66ced6682eae56afe7c1f18 Mon Sep 17 00:00:00 2001 From: Denis Date: Mon, 11 Sep 2023 12:41:37 +0300 Subject: [PATCH 020/318] NDEV-2176: Change the ordering in neon_revision SQL (#189) --- evm_loader/lib/src/types/tracer_ch_db.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/evm_loader/lib/src/types/tracer_ch_db.rs b/evm_loader/lib/src/types/tracer_ch_db.rs index 25172cf0f..0b141696f 100644 --- a/evm_loader/lib/src/types/tracer_ch_db.rs +++ b/evm_loader/lib/src/types/tracer_ch_db.rs @@ -569,9 +569,8 @@ impl ClickHouseDb { let query = r#"SELECT data FROM events.update_account_distributed WHERE - pubkey = ? + pubkey = ? AND slot <= ? ORDER BY - abs(? - slot) ASC, pubkey ASC, slot ASC, write_version ASC From b76129187b61d3f5c07bbe8ec1e830caeec26912 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Mon, 11 Sep 2023 15:36:21 +0300 Subject: [PATCH 021/318] NDEV-2175: Use tracing::instrument and request id on neon-api endpoints (#188) * NDEV-2175: Use tracing::instrument on neon-api endpoints * Add request id * cargo clippy * Custom Debug implementation for TxParamsRequestModel --- evm_loader/Cargo.lock | 84 +++++++++++++++---- evm_loader/api/Cargo.toml | 4 + .../api/src/api_server/handlers/emulate.rs | 1 + .../src/api_server/handlers/emulate_hash.rs | 1 + .../handlers/get_ether_account_data.rs | 1 + .../src/api_server/handlers/get_storage_at.rs | 1 + .../api/src/api_server/handlers/trace.rs | 1 + .../api/src/api_server/handlers/trace_hash.rs | 1 + .../api_server/handlers/trace_next_block.rs | 1 + evm_loader/api/src/main.rs | 30 ++++++- evm_loader/lib/src/types/request_models.rs | 22 ++++- evm_loader/lib/src/types/tracer_ch_db.rs | 5 +- 12 files changed, 131 insertions(+), 21 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index bef2baac8..59dc491d6 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -241,7 +241,7 @@ checksum = "f8175979259124331c1d7bf6586ee7e0da434155e4b2d48ec2c8386281d8df39" dependencies = [ "async-trait", "axum-core", - "bitflags", + "bitflags 1.3.2", "bytes", "futures-util", "http", @@ -321,6 +321,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + [[package]] name = "bitmaps" version = "2.1.0" @@ -575,7 +581,7 @@ checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ "ansi_term", "atty", - "bitflags", + "bitflags 1.3.2", "strsim 0.8.0", "textwrap 0.11.0", "unicode-width", @@ -589,7 +595,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" dependencies = [ "atty", - "bitflags", + "bitflags 1.3.2", "clap_lex", "indexmap", "once_cell", @@ -1633,6 +1639,12 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "http-range-header" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" + [[package]] name = "httparse" version = "1.8.0" @@ -1653,9 +1665,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.26" +version = "0.14.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" dependencies = [ "bytes", "futures-channel", @@ -2190,12 +2202,16 @@ dependencies = [ "clap 2.34.0", "ethnum", "evm-loader", + "http", + "hyper", "neon-lib", "serde", "serde_json", "solana-sdk", "tokio", "tower", + "tower-http", + "tower-request-id", "tracing", "tracing-appender", "tracing-subscriber", @@ -2262,7 +2278,7 @@ version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "libc", "memoffset 0.6.5", @@ -2274,7 +2290,7 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "libc", "static_assertions", @@ -2463,7 +2479,7 @@ version = "0.10.50" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e30d8bc91859781f0a943411186324d580f2bbeb71b452fe91ae344806af3f1" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "foreign-types", "libc", @@ -3001,7 +3017,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -3010,7 +3026,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -3201,7 +3217,7 @@ version = "0.37.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f79bef90eb6d984c72722595b5b1348ab39275a5e5123faca6863bf07d75a4e0" dependencies = [ - "bitflags", + "bitflags 1.3.2", "errno", "io-lifetimes", "libc", @@ -3332,7 +3348,7 @@ version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "core-foundation-sys", "libc", @@ -4012,7 +4028,7 @@ checksum = "51ad5f48743ce505f6139a07e20aecdc689def12da7230fed661c2073ab97df8" dependencies = [ "base64 0.13.1", "bincode", - "bitflags", + "bitflags 1.3.2", "blake3", "borsh", "borsh-derive", @@ -4119,7 +4135,7 @@ dependencies = [ "assert_matches", "base64 0.13.1", "bincode", - "bitflags", + "bitflags 1.3.2", "borsh", "bs58", "bytemuck", @@ -4780,12 +4796,43 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower-http" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" +dependencies = [ + "bitflags 2.4.0", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "pin-project-lite", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tower-layer" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +[[package]] +name = "tower-request-id" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a4fbab3421649e92056980671a04d83aa76e3bd4e7b755a9d9ae24eb2015b25" +dependencies = [ + "http", + "tower-layer", + "tower-service", + "ulid", +] + [[package]] name = "tower-service" version = "0.3.2" @@ -4900,6 +4947,15 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +[[package]] +name = "ulid" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9d3475df4ff8a8f7804c0fc3394b44fdcfc4fb635717bf05fbb7c41c83a376" +dependencies = [ + "rand 0.8.5", +] + [[package]] name = "unicode-bidi" version = "0.3.13" diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index e164c5040..84980e74c 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -19,3 +19,7 @@ tracing-appender = "0.2.2" axum = "0.6" tower = { version = "0.4", features = ["make"] } neon-lib = { path = "../lib" } +tower-request-id = "0.2.1" +http = "0.2.9" +hyper = "0.14.27" +tower-http = { version = "0.4.4", features = ["trace"] } diff --git a/evm_loader/api/src/api_server/handlers/emulate.rs b/evm_loader/api/src/api_server/handlers/emulate.rs index 083e40075..962cdaa20 100644 --- a/evm_loader/api/src/api_server/handlers/emulate.rs +++ b/evm_loader/api/src/api_server/handlers/emulate.rs @@ -8,6 +8,7 @@ use crate::{ use super::{parse_emulation_params, process_error, process_result}; +#[tracing::instrument(skip(state))] pub async fn emulate( axum::extract::State(state): axum::extract::State, Json(emulate_request): Json, diff --git a/evm_loader/api/src/api_server/handlers/emulate_hash.rs b/evm_loader/api/src/api_server/handlers/emulate_hash.rs index 4d425d877..b97538d6e 100644 --- a/evm_loader/api/src/api_server/handlers/emulate_hash.rs +++ b/evm_loader/api/src/api_server/handlers/emulate_hash.rs @@ -8,6 +8,7 @@ use crate::{ use super::{parse_emulation_params, process_error, process_result}; +#[tracing::instrument(skip(state))] pub async fn emulate_hash( axum::extract::State(state): axum::extract::State, Json(emulate_hash_request): Json, diff --git a/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs b/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs index 8b9ed735a..2ab577298 100644 --- a/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs +++ b/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs @@ -9,6 +9,7 @@ use std::convert::Into; use super::{process_error, process_result}; +#[tracing::instrument(skip(state))] pub async fn get_ether_account_data( Query(req_params): Query, State(state): State, diff --git a/evm_loader/api/src/api_server/handlers/get_storage_at.rs b/evm_loader/api/src/api_server/handlers/get_storage_at.rs index 8db99466b..57559cc4f 100644 --- a/evm_loader/api/src/api_server/handlers/get_storage_at.rs +++ b/evm_loader/api/src/api_server/handlers/get_storage_at.rs @@ -10,6 +10,7 @@ use crate::commands::get_storage_at as GetStorageAtCommand; use super::{process_error, process_result}; +#[tracing::instrument(skip(state))] pub async fn get_storage_at( Query(req_params): Query, State(state): State, diff --git a/evm_loader/api/src/api_server/handlers/trace.rs b/evm_loader/api/src/api_server/handlers/trace.rs index ad10577af..06cb4974e 100644 --- a/evm_loader/api/src/api_server/handlers/trace.rs +++ b/evm_loader/api/src/api_server/handlers/trace.rs @@ -6,6 +6,7 @@ use crate::{context, types::request_models::TraceRequestModel, NeonApiState}; use super::{parse_emulation_params, process_error, process_result}; +#[tracing::instrument(skip(state))] pub async fn trace( axum::extract::State(state): axum::extract::State, Json(trace_request): Json, diff --git a/evm_loader/api/src/api_server/handlers/trace_hash.rs b/evm_loader/api/src/api_server/handlers/trace_hash.rs index b3fac176c..7501ac865 100644 --- a/evm_loader/api/src/api_server/handlers/trace_hash.rs +++ b/evm_loader/api/src/api_server/handlers/trace_hash.rs @@ -6,6 +6,7 @@ use neon_lib::commands::trace::trace_transaction; use super::{parse_emulation_params, process_error, process_result}; +#[tracing::instrument(skip(state))] pub async fn trace_hash( axum::extract::State(state): axum::extract::State, Json(trace_hash_request): Json, diff --git a/evm_loader/api/src/api_server/handlers/trace_next_block.rs b/evm_loader/api/src/api_server/handlers/trace_next_block.rs index d5fc2e8c4..67d483ec4 100644 --- a/evm_loader/api/src/api_server/handlers/trace_next_block.rs +++ b/evm_loader/api/src/api_server/handlers/trace_next_block.rs @@ -11,6 +11,7 @@ use std::sync::Arc; use super::{parse_emulation_params, process_result}; +#[tracing::instrument(skip(state))] pub async fn trace_next_block( axum::extract::State(state): axum::extract::State, Json(trace_next_block_request): Json, diff --git a/evm_loader/api/src/main.rs b/evm_loader/api/src/main.rs index 0e5aea434..8a97b5096 100644 --- a/evm_loader/api/src/main.rs +++ b/evm_loader/api/src/main.rs @@ -21,7 +21,12 @@ use std::{env, net::SocketAddr, str::FromStr}; pub use config::Config; pub use context::Context; +use http::Request; +use hyper::Body; use tokio::signal::{self}; +use tower_http::trace::TraceLayer; +use tower_request_id::{RequestId, RequestIdLayer}; +use tracing::info_span; type NeonApiResult = Result; type NeonApiState = Arc; @@ -35,7 +40,10 @@ async fn main() -> NeonApiResult<()> { .lossy(false) .finish(std::io::stdout()); - tracing_subscriber::fmt().with_writer(non_blocking).init(); + tracing_subscriber::fmt() + .with_thread_ids(true) + .with_writer(non_blocking) + .init(); let api_config = config::load_api_config_from_enviroment(); @@ -45,7 +53,25 @@ async fn main() -> NeonApiResult<()> { let app = Router::new() .nest("/api", api_server::routes::register(state.clone())) - .with_state(state.clone()); + .with_state(state.clone()) + .layer( + // Let's create a tracing span for each request + TraceLayer::new_for_http().make_span_with(|request: &Request| { + // We get the request id from the extensions + let request_id = request + .extensions() + .get::() + .map_or_else(|| "unknown".into(), ToString::to_string); + // And then we put it along with other information into the `request` span + info_span!( + "request", + id = %request_id, + ) + }), + ) + // This layer creates a new id for each request and puts it into the request extensions. + // Note that it should be added after the Trace layer. + .layer(RequestIdLayer); let listener_addr = options .value_of("host") diff --git a/evm_loader/lib/src/types/request_models.rs b/evm_loader/lib/src/types/request_models.rs index b69048243..d1b76da52 100644 --- a/evm_loader/lib/src/types/request_models.rs +++ b/evm_loader/lib/src/types/request_models.rs @@ -3,7 +3,9 @@ use ethnum::U256; use evm_loader::evm::tracing::{TraceCallConfig, TraceConfig}; use evm_loader::types::Address; use serde::{Deserialize, Serialize}; +use solana_sdk::debug_account_data::debug_account_data; use solana_sdk::pubkey::Pubkey; +use std::fmt; use super::AccessListItem; @@ -20,7 +22,7 @@ pub struct GetStorageAtRequest { pub slot: Option, } -#[derive(Deserialize, Serialize, Debug, Default)] +#[derive(Deserialize, Serialize, Default)] pub struct TxParamsRequestModel { pub sender: Address, pub contract: Option
, @@ -30,6 +32,24 @@ pub struct TxParamsRequestModel { pub access_list: Option>, } +impl fmt::Debug for TxParamsRequestModel { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut f = f.debug_struct("TxParamsRequestModel"); + + f.field("sender", &self.sender) + .field("contract", &self.contract); + + if let Some(data) = &self.data { + debug_account_data(&data[..], &mut f); + } + + f.field("value", &self.value) + .field("gas_limit", &self.gas_limit) + .field("access_list", &self.access_list) + .finish_non_exhaustive() + } +} + impl From for TxParams { fn from(model: TxParamsRequestModel) -> Self { Self { diff --git a/evm_loader/lib/src/types/tracer_ch_db.rs b/evm_loader/lib/src/types/tracer_ch_db.rs index 0b141696f..fce66629e 100644 --- a/evm_loader/lib/src/types/tracer_ch_db.rs +++ b/evm_loader/lib/src/types/tracer_ch_db.rs @@ -100,10 +100,7 @@ impl fmt::Display for AccountRow { impl fmt::Debug for AccountRow { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Account") - .field( - "owner", - &format!("{}", bs58::encode(&self.owner).into_string()), - ) + .field("owner", &bs58::encode(&self.owner).into_string()) .field("lamports", &self.lamports) .field("executable", &self.executable) .field("rent_epoch", &self.rent_epoch) From dc026720d51a0f2e7bcaa4cc7a76007cc8fe72d5 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Tue, 12 Sep 2023 13:09:42 +0300 Subject: [PATCH 022/318] NDEV-2081: More useful CI logs (#191) --- evm_loader/deploy-evm.sh | 5 +++-- evm_loader/wait-for-neon.sh | 5 ++++- evm_loader/wait-for-solana.sh | 8 +++++--- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/evm_loader/deploy-evm.sh b/evm_loader/deploy-evm.sh index f431a1b5b..e89df5c6d 100755 --- a/evm_loader/deploy-evm.sh +++ b/evm_loader/deploy-evm.sh @@ -11,7 +11,7 @@ if [ -z "$EVM_LOADER" ]; then exit 1 fi -echo "Deployed from " $(solana address) " with " $(solana balance) +echo "Deploying from " $(solana address) " with " $(solana balance) if [ "$SKIP_EVM_DEPLOY" != "YES" ]; then echo "Deploying evm_loader at address $EVM_LOADER..." if ! solana program deploy --url $SOLANA_URL \ @@ -20,6 +20,7 @@ if [ "$SKIP_EVM_DEPLOY" != "YES" ]; then echo "Failed to deploy evm_loader" exit 1 fi + echo "Deployed evm_loader at address $EVM_LOADER..." sleep 30 else echo "Skip deploying of evm_loader" @@ -28,4 +29,4 @@ fi echo "Deployed finished from " $(solana address) " with " $(solana balance) neon-cli --url $SOLANA_URL --evm_loader $EVM_LOADER \ --keypair evm_loader-keypair.json \ - --loglevel warn init-environment --send-trx --keys-dir keys/ \ No newline at end of file + --loglevel warn init-environment --send-trx --keys-dir keys/ diff --git a/evm_loader/wait-for-neon.sh b/evm_loader/wait-for-neon.sh index f3d2da8aa..3554fb277 100755 --- a/evm_loader/wait-for-neon.sh +++ b/evm_loader/wait-for-neon.sh @@ -8,13 +8,16 @@ set -euo pipefail if [ $# -eq 0 ]; then if neon-cli --url $SOLANA_URL --evm_loader $EVM_LOADER --loglevel off init-environment > /dev/null; then + echo "Executed neon-cli init-environment successfully" exit 0 fi else WAIT_TIME=$1 echo "Waiting $WAIT_TIME seconds for NeonEVM to be available at $SOLANA_URL:$EVM_LOADER" for i in $(seq 1 $WAIT_TIME); do + echo "Try neon-cli init-environment count=$i" if neon-cli --url $SOLANA_URL --evm_loader $EVM_LOADER --loglevel off init-environment > /dev/null; then + echo "Executed neon-cli init-environment successfully after count=$i" exit 0 fi sleep 1 @@ -22,4 +25,4 @@ else fi echo "unable to connect to NeonEVM at $SOLANA_URL:$EVM_LOADER" -exit 1 \ No newline at end of file +exit 1 diff --git a/evm_loader/wait-for-solana.sh b/evm_loader/wait-for-solana.sh index 072911fa4..081873b49 100755 --- a/evm_loader/wait-for-solana.sh +++ b/evm_loader/wait-for-solana.sh @@ -9,12 +9,14 @@ else WAIT_TIME=$1 echo "Waiting $WAIT_TIME seconds for solana cluster to be available at $SOLANA_URL" for i in $(seq 1 $WAIT_TIME); do - if solana -u $SOLANA_URL cluster-version >/dev/null 2>&1; then exit 0; fi + echo "Try solana cluster-version count=$i" + if solana -u $SOLANA_URL cluster-version; then + echo "Executed solana cluster-version successfully after count=$i" + exit 0 + fi sleep 1 done fi echo "unable to connect to solana cluster $SOLANA_URL" exit 1 - - From 3800125bca6679e449e88deead85bf87fe19656d Mon Sep 17 00:00:00 2001 From: Oleg Date: Tue, 12 Sep 2023 19:15:57 +0300 Subject: [PATCH 023/318] Update neonevm from base develop (#192) * Neon EVM Whitepaper has been added to repository --- Neon_EVM_Whitepaper.pdf | Bin 0 -> 340275 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Neon_EVM_Whitepaper.pdf diff --git a/Neon_EVM_Whitepaper.pdf b/Neon_EVM_Whitepaper.pdf new file mode 100644 index 0000000000000000000000000000000000000000..8148d297262efd90bb8f9c40a88cdfed9dae4295 GIT binary patch literal 340275 zcmeFXWmH_b zzCZWJt-&tV-g~WCYs#8yKF{7{pGC##nCMwy$mULtwqTeD83}Cx7BIZL3@YYMR>p*s zBDQw!gtjJx^2W9{gkoRhs9+dAJJ=dI8yY(hQYu@T8!&(*5Lz=au@Fkw+M0rfh}s%D z5-J(n7#TYlJ5cfS!+@HM;OGd z44jNbjSX#$jA0mLjcrVw%m`W7I9T}k2_2mrj18<|+%nH})@*jfQM{Mb4xxIhFG#D^ z^-qni+hN~&_TSUSg&MsPsE-1zXSaz?Sieb0e<4r33L|0H@GhMzmRHR%{PFtS+3?0zH_wH<;#`r`}i}qFSe_Bhv1DTvyy`xUk-2k>S6<-i{RJY z5yD9JuZwfVE}!`yJ1>1heA&7P0zMBC2jASDtGGH}d>Cz~jIEV5lwF$`Rp-d(+_CUb>%38#s(*D25w&0mwzDk3Tv?J}(aWP_T7^8dQZIeVq_Y#Lckhdw zvIGI?h9BmnI7?%#bAr+juk*B%183w8qV|-B(+ok&o}t=`=H!GLr zJKhS7oFF{@4utOlxdA6^rwBM~JwtmnU_S8pzl4I`dm^QOi2f#nI5`2Vd@ZZV)5Bi!%wGqx~^8jG(AVVEc;P#3iGnkX~~4Pvt8?1 zJeFpFC_)_I-YbaAWMYRneCS3<-Ac50nD5-bRDgI){`9y8Pk$Sl2(euC1~FdF8wmSO zk$&Rw;8Hx$fbi+Pk0mrX853%L^k%duXSL1GuOexqta_tzri}qC=VhNmJc2TkLwYC!*{2X)A#>`cl`MSCs?KW zJGnenvBm=UHWg9yM)7G>BfYOa-6p{PFQJ5zD1t{E@iVS3A~SAi@XNNl)p>avq!!R} z=JU)VVT=auhpI>L$NirI^|tVE@#6Z&N$#gv=ah-Di8>t6jPx!RkCj2HiUBstb9-^rOlp=9kL3aJ)b=>0YX_QHbk=h_xi-4?-8P>je zv`~Wc38fr19PAm>bV$D%`a}NPe8UKv08HuaXwKXEX+(O!q!>yc1dy=iZ7JnLG_ob@ zb`VL8N`W=90+lqjT4JN;KxD8UF)sVz9+AL8q#z;%1)tK9jl zqutcAdl*ef*%3i%k=l8>0GU+QTvb5(i<1lt#a9+HDj0ldJA~YG%KjTVGV$fCbCdIE z2`?Hm#bMKlY80vM^37A%k_>FCdZV9E+>AkfVBgi^h$gS|sE3#GbOm>T>-&}=kslaG z(TYo}J$;B@xwILN+}3cOd@Y;V__I>Jygwp?q`~nH0R|VHt;VpgWarsc`xl9>%t%on zUVT!h`lS$(sPZJh>{BCiUFOwqDYBjKW(IpBhXgY_jBw8u>xX<*BKfYas+jZM9v4iy zX3N><4dNZri1I>$-w66a*5f7KdejM(aVPcs<|`lG;W*Ohp;#a5T!IUi-B!gT5<`eX z{sR)H*f7ym#OMC~uX{H|k`ZuFF`1N6GVJ-73b<6gZ*X4W33`A(@7s-eu<} zQ%_jShXdC*ONk+7dKAXr2CJRiHVd_QoUZ}av3hOMD8|(yyd5;9l|Z^j@7Sc3%)3q| z_kab>L+!(-7$3Xul)GWLW9S48)d4_CH`+mLt@G zZvY=>o!1_Oc({9YA}>Nw&5#?3F)Xx6sM9cj>V%_}6EungtHz>M_<72#y4ji6Gxy}E zMP`_8^QPO4@740%od}PVC|S7;J3+ic{oN!~uJeqAJ@FzD|1oogPD=PeAUn9)PZ^b< zKHYr8l-;@NbeM(+3&%BLFuPL|BP3m5UPiH)oQHGJA|+cE@pw#dr*MjOLXT9+z#>g3(9-WGx$U-XO($#mI~nouQza2p3dC23iPL>t zu2})+P)>hjo_Y7laqp=}F47P~W)65I8gUppL9_WS^(wfnsUlPm_Uj|}PB}0_AVK*G z4o6cc0G!!YC)sb(GUo{=%>E7vxYwhq65LY=NzeR;AlG)f8s+HxBKB1Nrv(uum0s`&buB zmk^v;$s<QT|QCX@#y@S&%Afcc0W8_RfbSTtF9#+K4P@S06xQ>3FT7E8=^(kH6>lt$PKw7$j z{+-;V|L0SYmXGhY`XAI0x2?#u3LBY-CNEa;7j)Rl+6G5k*>6b)6ABZ&wD`MTd?wq} z{a^e?`j9+?fKd2aWv)Q%Hy^K=5D60%rl%X>U9WH1M~(CB}y zverCyQ<#ojY?{94vD8Lyz_5gCjyh#=qroWcg<N$XZ@v4=4(hl zBjR=*-0F114w1YP(1_m;hpTu5QtuPNvT1$HO;Y?F%o)|QaK|Ze$LA?L|73LOA4YZn zkAWwL*=#eU0BH8cR>B^$Tm#7LBx@j`k$412tSNScV zfW5!`UvuxuJ*wYbDdxVz5kAUN7bf6hcPxSvB+qOA^{5N;JR0MTPy2J4pqea?g|t@h zwi}UuvLKY-P2)ORYAGeUvC3zZ6E6{aq&~?A?m}Vv^ZH5h)jL?n2<9xX zuk`CWVk~sStpV+iiUprt1lu*Eg}Eaw56>YLO;{O=Cq7)N*5NhO#{e)Xo(01{=$Md_ z@WyYoHXz6_e8v}yA&;|m@2Dm&9;DIM_xVJMYVN!U7lqSPa#k2Vwcu||Wvy5%S|^Vw z1V2-b27nKWJY-8*AgFGrciDa#O*|N2kl3%SkwChHBd7|?%UC{FCuiHcfHB#QRmu9m zQbR9~@k5i+&n4UIp2g{IT0;2TG)01IX8fbV&Y^!l+zb=^0&`TQ>XJNZ5Jq8Y2|AM^ z?@juirCCq#Dl|fvukuEN#cdzSF%=dLD}^L#_8M7dg~xJ|Bt(HTb#Fl~SL?N1m_VHP z#YfBMApBIpj(K?5=%{QL z#$9CqX>6k_LVdMN-P@X`y7`k4J0sf}-|$pg-rGayCo&4*n zp+%oPz7P)JJXQKP%UslxYZGLOW2f(R9+fTKetF;2F-;noFH`bJ6p>}zUnMP*Vy}-s z6hC~37^KL4_p?$hV%=kU?Y!LsNBL<^{;3afd8?lSHhYyS%#M3#Bkywn-)kfVIy)G# z*pnJ+fgia35Aawcf5GmI`rK-5w851%H+1S`R zfd)APoc^54n%h{yFo+Yfg2vlAfKV@?79(g3qYey%lChx^p%w=-AsZ(bJtHd@7Z)KD z8w))%8yhnVDP9lfEgHG{Q*gQc+(gRzqt2xmK63mAe>vZ<|uJD-GswJ{kptGKz1fsNtsma3Dv zmAR9-u_LH0_h*!ymBF7o3cm;czN~C(Xl`HyYKXZRni<%b{vHOB1F$l;F$Fax%}ved z9LyapL2WeyD=T9sP~)?M`EMbNDh>vQmc|aCD{{t0<_4hu(zXE5b!B4%2SYP*kUR$` zK4(W`2XedLBlt`VtQ?KWoy@I``M4NC{J=lKKhtl!{eyn^KeII#3q2PX8xs>D3o{cv zGsxf|i!*c5GlM>?tb{Bqtn~jIgByXU40=afD+3#YKQ=cqb}_cHwF4Q2!PbTjq?x%5 zot=ZNse^&FBZIArv4e}bvFpF8^q(1(|1*_96Q^fk`c1I>Qzuq7E_yCjb}rDh|D{UC zHuSFMmgaW9T}5x}V9N0Oj6v8K6iime?s}hp`_f78FYe`EHDUh0b`CQa6FnCv3kwtB z@77=5VdY|`XJKapDZ==_^Uc3kMB3TWi4NqI-{GYPS|)bpAod8fqW)Et|3pRok1P|& z!2gA1idp-cWfFc!l6x-%HpO{=bN-Cz!to9x<2TK;yeP>6h;+@`n}FIU&j7O3k|byMC6V%O}ipSC=n=V}~S zOGE4XQ-};tBhQnCyMYAv8*dG7D_FL^E52`2lj-ybJ%yV$DKQGYm$ycTR`rVoTYExI zhyDL^M%!Y^5^UFop`kLb-c0#spD!DnPFV}cuDa->B}_$PT+=78A`7Bocx4Ns zHe27qd!P*{eSF60lr6|bdz~91^ zQXTpWLgcIugmVTQc$eg>0K`1UmOT6WH0+Fic1I zlC)VqA+z6&|C%5*nz`u66Iq|OJ!{ZbN7UT*9uAprb z3b(Fpcqn>AU?eMeUb(pyXRE>wxFnd?YQs(NB=%N5!a$i|2=GsMi?yTkeA4yhhpG`S zto2^YNP*Q%w(`$W`=2T~(9Bk8zZ@ouf2@h`kPQgkT!EWZSp~BTZDe-i{K_N?Wi5_O zpL>Aoh3|u&sVxTn(H*R?)n7HXv4wD}Z*F2TB!2{DomD?)x@2ZO_%ouP)GvT=hFBg} z;8O?#HDfs9Sh5uF1}z$tfUnXrSiU>5sN*Yg{#_Me`kC-2?+7T#`=A-^Ln}t_>}%nN zV)|W@PLBIKO6Gf9?ZsMquZ|M6&g;`>9HpEWw>eORRR;(c37yPP#KP>? zzmYs3)Tl?^-wSiVY0BN+fGvczvlBP5t~;PucJD4arjz8LD>4@ebPWp_wllS^Kj`aK z)PRYE(c(BU+Gy01xek{00YkE;!DKhy<(&$x_^lcIia^Mfg{jDcV`XplV??}6gD z74#8g>n)SuAvDj&$fm|Yy(;+t&WtZz4IY|R%l8-pVS;$;zO|t1e0*g8Ih}`gsr1|X zV>zST>f_S*%=P$IVvMlcipD0&ZxsRQPIZp{d+)8Lg;Ow1*mh~ea^~>uDfM4JonxnG z*loUsnxfP}#?YN&xfI~0=mfwvQQkuJL46)$Anc^2sH3r&n10gt(!CrgtjhH@;6|UC zksv%N8bllaRaWhJC4|8niO}j4AJ_<35-J~cJR}Wj0ASH3)q9xsOwwC(T?ikXrdFwp zIq7u#{7#{TSXCT#dd99?kB-pxu!4X!jNa_&SLQ| zLf=>2Pq*y&pa26#MFL)c!B^~E6IC#U^Px04VE zXz(r3xAqHpzIRd39Q)G0E9@N-W!-GQI;@wMBJdJh@fxf3M9qF+VrAfK`yN;3QIy-( ztv*0rgpLRMG#;Q&b+QFuqEa{|5n&U{gH_8_w`p-5k&~yBrNq>!7VRy@T=e2W*a(fP zNG0jupmQSx!;(3ZQ^vO@!FQY?ggi)`_e5{(5GsUJglk>C?g{buCAXS0(HTCeF#I!p zDQGr)Q&Q}cY%pD%3lwW@_b4x5TBqVJ*=O{rib*yuih!m(T2kb}m;PO_>?nWt( z!jN?Om5eIiHHz0XHX_X`cb2<``Xo`KgZ7ZvSDRnoIva#GZfKYdBOtxDa@H537>)+gvtm@J*AfooQtO(qu_8LFs1 zy&|DzE6IckXyuSz!5ps_O155qaB|f`@W_d27ex*1zeorOm_%O(NDQ)Xn$@DBce`xa zp|d6c;SXI-6u92#1NHA_p$zF!vPv=W^)CHoZo!Tu0W-r(8nU;Oyg*_-dx;&?Dyg{T zvP3ds56jZ|nzzxfRn?G0tE%py8qkKi2eAEg4 zhbF8v@wt-eQQ|i7h=?b>%v+_$~2^FOaJn>L#v&>lv_8#&n(p% zCkxD4mxUpsPQ$9?;)f`HBhK!>=(3oED@-`#w1iVD-LVzC_C8fTl=LQzELIR_)!2d0 z43y4G%6kRVvCD3qd^*Hg#RT`GMOil+TGHxL?(Z%$6@w3FDHR5jpdhi?>D7dFK1!sl zk45j2vbDL(hfeee)N5lsghB->KmgMLHVKvxscs# zUqkEYWgR)r&Bth5J%-bU=Qf!n_bOhliecl|jfBh9#1x~bgDHj4!|R)`x6OgKL3v$B z*)(*S>+`NQcCVbefx*SA8*E^m`T^$>J-A&z>5Er}PZB_8E_qfLq z7^AbU3}ge|U6+I@EO(NReP5(ag<<{(56K}3-mi5qxfOr%uq5OhETjY+5v%T^-u#$x zllT6i?hwi0_$cn3htoki_RWBo*Lfz((+6GMZwIpgOjCCFahhx4X?B$xu+DeJ2$dM0 zTHK91#XMu5G~plRrG|!8b_e&!aI>4eykjt<1gXbUdrWj!C^>7AVL0jL&yx-CI_f7~ zX>Gtf$(OJ^*BefmKZ_|y&uiMeE!w3N{bz2|OAO#Ot;tCwt0u6h;Xx>GJ1-wB29s>nozHYT9}l~EUF zbg<->)!zayz!kGGK!(r6VXK%@@TdWVMkA+DEiQclPtB969?_|zVjyZ92TL3K{EC5 zIFAtlOUe2u18nlVByIP2fRou4>2!$x;+W|pxjQW2-NkL!n3JQH8Jb)l`GhRG!K|wL z{iR~NpE&iYf5#DX1oP`PdCAAooUE<~D#eu(KXDA?-pnHlTt+VTx5m z6YV;Yh-OW7IG{&BN(pNvTI7N{U)`<*`Iv*GnzTv=xlrsS-_d$waksDN!3cbkruVQO zfRrpVG~PN{bW@y+v?;&5j9%&lX-GC3i-FiFjkd#8VXmXt>!VDBDfT!q#@Vgd*pekT zH4qvu;Ki+Q2(xdF_aY`erFTe@iONRPWBv8${3f9CW6W*DjkS-vPvoymI@V_0a0WhG znV*STwwR&iGIvrGb=xddrDR=x3kl2GhUgHK8&d1kU2T)Hf5jOM;6e{4a1@30_NB2 z-pS2S-t8a9gnMcViFq0wXvHr|u5(&kUx@UPhM%%iqR8gp(*BTRf=$j4G0JN&k1Q_J z?-=xaG2fU*jC1bjCHQ!Ac{7SnU#aPW&_Ox+;9%~?c|Yp>RAv*Z%0;Eo*&&Kx)RK=D zi39Fkn_JogovxXa%ZV1euUm=wAq`ePQ1k3%FI9nK=o{TYy`PgTKfi8wx!NPmBOpi1 zj>|@UT{YH>6t=R}Xl)b^%&M|kYhA=v9pxrV>)^ol5muvDY#+IideFlV9NR9`UVqYU*Iys>J5eW;VLr;Q;a% zB27n~*nelYnArX+{#I82Sbzwo|3pPeSsR#wXe>2zBhWh%Al`!=hC$L8#N9X%GO_$7 zxcN_5C+j!=1z{EjU7ZlaM{+z*v5&F6U1lz4{u*EGjlOB zvi)ade3}KNuA;Uc+Vx|?#I=rY#p>C{ql$b6jZIux_7unS0$o&8s2~g-HbR9e;C9{f zqT_)chUw zdcQWI)#d!=@oi_n3hb|s`(gVNjgBzrd4`UB>^(YP0O14vGuqrxOX1I=lCN4H|LPS7 zu4u}kBb(bgFrZrVy}^`OLmx{~~njD^@8hAhhDARw+iXiH^bHCbUf+D<-+#b2-HB8PgW z+iTqtx*?1nkgTLDqwAeuW$k`9QExx*EAp3i1CZiTgc0#SnYID)j*HIrfI`N6NhBYI z{zPchZ=&wba(&jVK(EXtrRC{FFOB{$V%}kNsIw^$@DpEu;iCMR0VO*l;Dch+_gLhE zB@Qyx@PKPK`S9o%=!XC`ZVJwv6dzSyQ5xfyWE2~jmfWdf+rqf3t5Y0%N&cLQi093$ z9(bDFgo4;-TggAta+m+1Po~Zsnhvp@lnpO|x+DFjZgotVtBkd52^xZ?fVpjOZbNkq zS8-!$>e@z_xu-?LFkNup7ia#GLGq$?n!p4lI-I+WxIZEVYy6Q(!T?6&I80o&LL!dO zs`hU2-4qFHQ;r7xe|qSn{nf)LdO7Z6c^<=v!bODQXF9HOPaKMxvMyw`k7*f&%2i<^ zu#fjw@Pj=KTVh@-?->Dq1~W$dnK5&%xD}43C7zA~!b$q~!}ReMSgKDOwEH6)QI_7> zFJxayNP0xFEwrOm zrY51um9!w=hSOqbM_4l=elz?=MnZ01iNqL-u69e$=cPts5_z{`$tkf^=h=mG-so|i zbq|QG+_>+t#QN+I*87^CT-+4+U^mQM3-R2}CQ6h4j_vzK@7$jW7{Y+!lu}%LF-*$v z)zPiSSlEN6`2Ku%feoGYwwzFVw7jTaHb2Ql>@;D7438YyVf!zeybr7c9**zW<+~&zN7r4$uf7fM6v8C#uHjox_RR1u0AF8 zN2KoV0*7Mg(IIJq;lsQ*gP9>$S78o?Qkx2JGTf?7CABf}>KQXxc&(KBIHUf@_z7P} z#i3{W-njXZhOp*pLI9+Rl$rV7tZ@;G$Jn&xG5VQI1G=N;;aEA&{tsFy8ZqD(qn}^s z&8YSpK|eIMD5w>}>HJ6CSd4$zn}?iL91VK7@!UW#?l$@Zb*J_)KMyU>JIs|zMk1FVk45-;(2%_BXi5M;E4$bQK^kxf_SQRF%z=+9OnT@*TLi5Nyp|X zV~-}%4eE_L)UsOF$LTAoC6F%JZ1!aWt*%wWfTE_|fmhPR2*oxhYT^ip+3W&6>`S{`IQ zqS5wAx7XZPsNZ&Q+x7diBBHRER>-&vy@IC&GKN6vTlR2^Q=HHrk*%1(AquA3seO+E`%Dy13lc{P z^odeyz|c@ypSc-%N-?lgLwj|MNpY3FZl2ltYIHLM{ZeW~qbkulrB!Eo8cmPhN#V?V zi7i-!Zq`5XR;M8Xfp@Q#k~HUH*3-m`xrM3lJ&69#QW4Pbsy0e9Utyl-=%U5PgUG`0 z7$fTRmq*A#wMc}S-irH@fH#y39dP5G4XisLT*=DaHyfIM541!cxhr|Yg#2wSyPSV4 zaM@L?FT)gc!0!g0t_9n&48u$#WFys40Txj72clY00hZ7=)!fwV(_tg&bi~J}0I4~g zPpG)GBqt^K7=7!jQGu3tJGg<4X)W!L{Jb*KsTSV;OhQ&94(CiiINtxq3o7B*S zSp)Ipj}FHkUSFh{Qff4T9uAI;V#jnNxmwIa#O*O$LD^-gTc?}6;K6$$_rJ@)e-c;mW-v#C*iDR&xWqh|e2u8lfv> zDviK?=PGAj@YS$WNrP{ie%h${3|>wpcFG92v`HW4aS5H+w|HmHCl-W zT-W-25~nU~lx&FCFVaDtsgcCX^olE(q6r*ZM2#CGNiddcG2LZt&E{67cD%S1Brze% zA-lRw{LU_$e4H`?KXPEKi<)wsI?`|$>ELsAbhs^np z!p7wyDM+cfKG>&uYjf-+Gh4|EV8b9klHyB3zj%R}n&q}n$5BrwFwbR>| zjiLrd0rhvew>k4yQ5Da&ZD4?vVVWN_H2xk>jXZ8L z&>G{5#447m^nk}P_I%jU?le7B%D`(fB{0zxpMdg7+<~W+)J;<0i@wJ8_T5linp{gJM0>1T_?r@IN#@LD<`qf(mx z6#q{X`@%+|L4NOKP2rU~zqk8w5V@IHo@S+!w)Jt?JI zdFnYNE!M_Bmodr27ZJ~#_&V7g_8ZRRUj9eoB0o$Xm6aGDht+Yx1dIg*#$@t;AR!-s z9o~{QZN)e1Kh0by@N^A!7jJ%!5x2tsa**8{PL1&y6+AZaI}2s3DW>mQ*h))Lq2Zy( zX6AD0XChiNGh!J$9&y>Bbz2Rxzg0&0hsq30MI(j>Ux;g3X~+WUdTw%~mnoa?m1uAD zX{qqFOmdOy7HOv#IgSLfpc=FN#l48yCuy=|C`7rd8fd|zmsM)z6F>yKNXl_FHm$e3=|D%v4Wjq%35Q`Bv zA*Dd~zI)ojWkSCk-BhBP1+R%HkEFu{f=MrAA5-nKnl3S#NW(}4pC&yh9J*BOUc z_Jih%Ear8b>aHF;qBKMt`NYMx&8&ODEdeYVQTi$aVb$go(g%x8lDzK7ABG&t1gofs z_!FB+3vs2=$%pZ;$#nC9{hjM;qWf7#T$R41L3r)?YnN}ZG$L+-QOonl6q*cZKo>vgQ`JVU@pvv?8Q)6Bu>T=-3D#tyb&Eq+BGz~aOnszX!fLE zT3pd{RnDS-e48d{)&&ZO3HoB-@Hv-Px67rjGBWTcRnffktoKjQf}OwnM-)kc;i2M6 z$^_m#_B=TVag(ztV=!-bYvV&F=0zcgqFs*sRHr5tX(BP}SD{EN)x(ITz1F@clgd8& zgd)N%-Z=9Tvfu1LbY@Ieqr+`9t9#6wmNlOqYT2)1y?9qtE!-*R#77e~Un$}RE=8k7 zhn_oGtb-iC2Bdw6(OUuqsAWG0JZ}Xz{fS*+w+dItP}=N@;-DqNMf{^r+_Kyt2mW5^ zf9KNpcs78cc>nP*)XI#kJKO~aT~LFOQQl?P+bj_Q<5RB>NGcsZqD53 z{UlR5&EF}c88V*Yl9wIlN&Y2V5`~Y9UJ60dIxTde=7bzTs$RZcP1Rvq(vM^Q88Q>E6xR*D7XUh}+Y(y;>%HG4qu z7Wy%6IlgVAnVNLq!baWrTN&Dju7 zYUs*xv=|OcWQEIlN7le>9bU^DPm`siK|S>hz}kO6gGP_sl@mqOp!#Bbfjd&#IF;p z6;{^P$&M|GR7`8+^UM60qb*;g@AS9$IJ~9!c2pwORO+WVeRk#gud#~73b<}7phm`~ z!LF=_)7TnFeFj0jMkaVPO z#VUy2JiRcFlTy*M8g(VqH`SUnQhY|=7jKDMvu~3deU)W18Y#qp+T*_DmdmmuSw{vSFUUzRrQk%F~PqxswMK zhl|&RQ=rHPPpw*C1dbie9AJUx)7`j=nhH=h*?N_>zSx;X3U$8K@I6ZnI+Y7@abXTo zvYpoOP~eSQLENcs!8!=^IHzk!xcMv0tZ^hFA3}YEsBBHIdzGv?wtRS=U7a(C&`)exN_FcOU$tN;T1Dej=U9*5 z;{VWW-&y{_H(|0e7GW#)KS-O}PCAlKhB9eC^?AKS}Aq;jM2-Oi~=xd5l+uo&QP=lX{Twkye$b; zpwq}zB?nNbgXgC}xyD&(RjZ5E#tuIxCXto5sWiq&RuCF6Y|AHU_#r z;iL!Lb`xL860svhXlPDvsGF0&wi~ygKUCJPPgJUGLT2J=INGVt;X!rNNy?-7Dtb-5 zk#qy)iAO@eIQA>;Hfyn7$18mro43aN!!IM?5VKEY|FwrSupwR(xUg>iy-~P(a(!Gy z-nrJ3Oywhp04x1g*v`{R=Xl}_PSQBrfkKlOGW=^45_bXbBl_3gdf2n&Ih(?;81A+Z z4X6li_7d2KGcQ=4J63l}Eoe{8>ytF>?&YRK8SYPwKHTUlY~xZ1tCjV#Ubbmyjc~;+ zdM7HfnuxG>b$V(30;KabnX79uU;g-<_b-kO#Bz?~V2q%xd|B@h{+ax}hY6cyk7bpH zP70tkZcUW{H#yt3=e9wh%qX#P$6^8azhhrijrZoB{gGz{?H ztue?_sI4e$U@quY>#C9|p^gR?5v^ua?(5~?dA0?JPZ-S1Fk00%cuDcE8lK?z+w!fibe4HKfT!i+Qc@ z;k5o z#k8E!*mm()_T*2`kN+*N1F0ARjM@Ikf%XtlprT;+ z9q9P*`;h|jZ%w&`G8jSW2Mj~{|pc`O_PGDv~Zwv!HYj~O*EH` zp3$m$y9&qG9~1r(H#&2{j`i{1&tfap`6i0MHXbeGG2#dFV~@A>5?PYMXnFY@zvE;T zO_Nh;js@EdCPb2>M8}#w;lEWqIW#YNnOwTWay7qTuG2&Uv&Kek33_e6TM6q*9Te0g zkk?=&kPh#Em%^ZFM49UMU)xcTAasmFmu_RZM>d^be0Q%Fc~v>t@5pjY`Od39eVjE0 zTZ#3W9q7{?X3#H)uiq~y|M!EUz$>^Yb$k$oL6nr)&3vx-ZC?Y{#^%S8!7kaC8Oxks zuN69)XED%TUBcs4Z2SM-cC%%vb0d!O&U2$8=Mzu2&l*l6!{z zR@3YHXicB=pWkW`412f-=>(>_T6Dhl^-JsmM=v;_FnNkjlg1pwFh5VI2%wWJhnMp? zx)m&!i_V?M%)HN#+#0YWdiA8zG{f#qtcOF^jX-WTy#|+QIo;I}+SA?;&eqB7o>y~X z5bN z(42<>UyNtDH>86{f;(>94!-x}s&FSct=^4m9#;5p$V15tCNg{oN5E-R%7Rr}SFg@A zsIxeD2X4Y&>8C`m#WhlXJmXS(iU-A==)9&HTVJJiuHC#nD4rzWuwxx^4u~DkX3H*_ zk*N{BQ?{O8%Yx!@iYncgZ(JR)Y<-Z1N!W>fZown@x9&#cM7njXBQdFtmG`p|EUIjpzLH^1Ys`dEqZ= zjp)qhGBp8)m>DCE9H-~nErpg(MdyVlZ7J4=MVO)En%Z-ZK4RnarkUv_Ed!P| zn#J_it8-GX8cp9UZ`LQlO*KpX3?SsTepdat_NeR z4iJa6bhsCr{H(vQIh#LaL_~^53%$d+%G9#~h9@j!SDUk6qp<8OElxxqeK&g7&M(l zq}qPWr!cL=NyjMgPZ0^_dele5c^vd0EIIA_>m9vl-rK)_m6?#B%|J|RNQH_hQH-U{ zHYC>5X!71Jc&k`ja2~7~;nzi4wCo2h^cR!oiXW|KyS=-0d8(gKv~=c@ouzdICZAQ8 z3I@7@WX{&{NpyV-Q(Qu8nmDVYPL#WyrMEA*zKf^JzL(c2jQJnb64o_8q+jRo;4-T?GejMnxt2Ry}>c&HEst^2?7D}Hj5%fD=Zf>?qs!#Y36phLXf z=ts1>jLmUc!{W<^@7uH(q;j}s& zJZ%_Fh5`_^SQXy#Vv&{Ktx@)5lUOSk|In-{{rNbsUsnkbLA-K@UR&VlOn+I6n9vz2 z&#?X)MAYG`0hQ>GCK3J>;(%|U7%wA6lWi`B!V24*j6}C4%^mbY6Ic0Cn3|0NJ`=zB z2I(0ESA!Ogo>bdwB!jQ=j3otLW8@jrc2(!E=tiwjSU!)781hnq1M+q6u(WK;lrL>* zU1tA-B8y=QF-;X}=d*0aCebEMp}Ho7&Sy>dH6rbsLDqASNt0E@FZUC-TA%>Vtb5%5 zu4^*>;yhdMHlgPtqLGreK;4{wU=DbY?KG~o>+-?vXfRud-otGJS*Gv-Mgkf zhDp5g#&ZALEzZPVdOyd-Y}KDuSzTnjZEsnFJ%#K6yrwjRs7;wl6ktk%;6BlP}&JFhM zO_=?7Q;T#wlEzp}?T8lZ{x(FW7}_&l?3&Ul$sMO}K>44Ofp|qeSfJ2|)giH&y0iSq zQE|`BPN~+epnb!mLtsKJ?O-)_bw-bnP&|3QeHrs2s938kx4Dv@>-fUCmMmL!p3if> zrhzn{cs?23*t+jp#{Sq&*i*?imO+humvD0ldIjTO11?47mxfx+aeSlRmyPA(jYV6{ zeGsQOsoL(~_^|kj7s^l%szBDnp+T8jiB=>?Tz4C^@z!H%G`ix)>ZCqK8O}vS|2Ro% zJ)}c12>sx1iIcOc#J9?B57ZVvRU3Ae-=90z^SQ%aI8B~R;g{f@4g>9uko0oWt7k_2 z7DH>a0S5hy+clQ`FPs^>sFB`{?E;j)c=(|eU%8JS8PF$Jzhj-;Yx}w%pN=D<6mzOI zABtLxht0lpc54>W&!^7+l;6vk{a*Q;J<7a_R(@?9b+0hcXaT=vvOE9P#{r-Jza_%> zfx3@?bJOg)!~Ga=yp()07GqT@lSS!00!~Ly6S`v3cT^PNm#4uTt`;upA6?3Q*!}gNdgA^Q{`WA@W~JMF z9g^)HslXq5Oj_Y0i-y(8BE$cBc~iA2UZ16Ladbbf>B&9C$>J!TPzPG5e6^3D@&i@D@A_ja^*+eKDrKXUu_qOz ziY8%NiZrh2IHb(1-M51Y1?c!EMJ$Chd9in8__)wP+gdhGWsODxKhbDA?I2FMYWxb= zXpEJNu7biEHs64O{4dpPU0hmg(bWi(Z|dC%DEC3i%NcbF?Tx<|2QH*=7kpz_5ru|s zK(#h%YpY)cm6Jl~->b*GEewl2_$^j=J$oiVX%jAUz^Js|J{LJ*3dcR1{hJG%$I>lm zk5g(po$Hy8^Mzg-mMQnBx306GKrf1cP_s*0DfU#;Bla%p9pnd4A7zg;Az<1FOke#_ z=sM^6J~`>ZcYNSJ?~fd7PvY{pXTCvqF+`B9w&#8UuXx{+`MY1ud5dA0JQ8}!_y zYU8o3vNRd+|Iqc;aZ$ES*zm201%jwZgSv!tcdV$ClyrA@cdXLV-67rGEwFU6bhC8F zl1uD&c|Xq`&-cFXAO85u-RnAM=9pt#Nu= z$?yB$9zYD=8dyp>Q6))n*VCPi2R=2jm@Nb`E=#TJKxO~M%h5W&F$4z@pQVrmPX%-b4?^8mY;-Xc zhvFtRLNu-IHs-bR`SzU$0##PyRpS`$v!~W`f^wu^dgR!aOpa|*RPLy9Yn5P6d4r0Z zc(|zfv#Tn6K;f0FVGTG@(~9+EQamlwdi!RYM2i{sr*5Qb^<5W)cE5lc0zb}Gc=(E8 zwUdj`EJctxXOhEzpIEIl2@q0`{#zja#1F^8o3w$^6nJE;7SHqXw`aa%u^po=iDtuc z7{mm{b^??onT~6dk}_(cWVBqziK>1_?3%I|K@X6Bpgv*jd|ce_lU2CZ4()v0#dav4 z1k^MmpWLApD!1}P`S#Z6-L(EjL=@wI*WzfFLdyV}@jWO$f21X$ILc#I$&nwPl1QSu zsTSifH%04IKx{h2Y*LPi^DuHn(FTcstkhaOGn1|Nj+#0@c|2+UN;dcx??ouu%<8kN zkh)-6n!I)LIQa)uxsATUv(A^!!k@d>@uKj;N^oFQ{FJ%B7O8&C4))KFcCwT6(b3aZ z-`FxE#PF6(N=2pv#6i6}ozz3?L$gmrUe}enOt`@sxpU@rK1qr?G>T8pWRZwzlp?oa zT@BAyX&0$VoJn%&li!QWnvAWO-Q|{Er>%6(R_QxOf|kO^XJS{WM9XqD^4zO8%L`km zXw@AM^wAmBhCGZOzo(I(;POg4o4ALoS(^{`W$|=B8x-(|Rg?<#N{zXc<-5xzs_Cuy znwILBUzxS!?tBXI{c$c&<*;g~vX+~-rWxT9b;4nM&j9*9P%94WYr+B2&z}hNiO= zz6px66fuVpz4NF6hG<}vqUCWr2QY(;@9&aC->Pv}e=M$)vkm!Oi1k=O(W^s#2pM2` zet#6UUAoY4+s%#GLVse*EzQ^9Bq_JsCbqp6^5Xq^&#Vp&-?!vF*;tPvrRko` zpCv4vhkZPE$IZU_)IKVd?v~5N;0X*eqhg|XjgmFQ*PA(8Bu5y2h~NpEcpf&Mc|V^h z-FC>{eY>qOGhS|XXT&m8j99v3Ruiy4T+7mHjpinPPCi||ei<1bhBWcV@xK16=kgVE zi>E&CyU5g$8&JT#EOpyMf;%cFBf*b&M0~4A{pL zSg*eed3?6*g6F7Mzm22cxIUzM3UHR;d%WPY*-H)=+62lUG>!9RZ$?{s97_*lFH++8 z$@17D&MA09ffDBIG_XC$tta5oP?69Wjf8EHJ#VzNyl#LG}RZ8aO^ zQ$`ig0RxuVFh(7zHOKzIPMOD&vxU2V5udD{Fu;+@c`AEafalq6LB^Cd%LQ6Y^wf#f z0$7$;Z12rJ`Upb)iOMPGWSkipN6fdRt7H+bVktY2LAbak_qKn*%w)M4f z>2zGYo28PX*Qm5Ssf8^$U#DzpIv@Aurn+w4VtZ-Q}V-P)LeV zAa&a-r@BJ|k{3^8cAQqa)R+x*zL~nUEd}*Z^Q4GADK4lcx$?Y>1w{XHJNIU4^hjxS$+=iyHU{ARW^!CIGAv zwhtCGhZ^9Qfaa>TPNR!(Y7JfF8fUta@)t&$q8Vc0{8P=T236%0 zFmczQGi9`Ybq>FhZ^_Oa!L!lD<65tVcu^M+)P+CzW`z;r0za!=Ohhg??bhs%@Ed5G z98i^Qd*g&jYD2LftAH3*f6P$%dPj~W-~Tv3oa`W#I#VZiXDsEGaj)hp3~=Rfy|) z^;9d;aJE1)No*&?Vqe3%qeHfGtd9|=rWAH9@a+w%*-R@4*`QnXcU++3VI!fA~d#%NhK}>$)Aaofw5)U6QT|BGC zt#W(ugK67Nt%OX>X5;Faew}cc^oL^&0?uCwKoR-S__H0FiC9-xgXNOpy$uxT?ubt_`58M8$6*RkdjDMo zy?PR3k-JGE<&x?4E(ytrOM-AP045a7G3VWU*HyK2s*#Pi#*tS&0af#yv3 zmMnoVAIEnb@EiS*cs}O*y7^J?<+9DKf!UNa()EPMsugjA!FY$r&sBzHg<+dP$)qmr z{dWY^q?ej@pJ5|Gbl5TNu`H>gw@0IZ&##n1u9LFD#%Gppw}EfH2HzbY8l`z$O-$uT zpe)z@21SMmTzo_*V&wT~g!eA{VSv+#@--XO~F$u@9i=YW0dm;`p_WbbKWdt)1*saK|!?G<3X9q^~Zh#lV+bY^e z&R4%wtQ)Vf$XRAGz@?l+2u}fo?JlxG)Zk?68-zu`K)}iBn7kEkQ4u4dG8sT&*vzcF zPFs-Xo`7dGm%1r^7FB?!DWCm%|Md;4s@cZb2Q-_4{^xdD9RY3AkN(>ecdpXjj2#Figd+_ZD$-@f~@djzJr zBDcY)bw)Jao8MkAvzdlkUVRcN5`00z&epKD5)=8VD__)@I*h~ti1&cQDx|DhC>d@~ zV;Rf{;WpH-r9CiZ-uR|Xa}t)9K|Oq;P~H&nP)Z=z$GLILvlsL*}8?s6$^OL0jiIXnLWkD6Kx-U)DK&^&eb@c#LKO-$MY{A#>3N`Uu}R> zsDMhIut*4$k3+ht91$pjq7$L-69+6JgHMh2)e-woMDWJW#Stjd^g9dRLM+CioJMl@ zacO~I{Qr)Qfe}Zhknd0K`YM(;Z#y|TMtNDJ0*yWgdqct#GJ^_YhxUY8o9-sn&`P7W zO;KTC;5(=m3OU}I>Uj*@2eAbkrj$%Qna5yk59lTYh|VxEDF*NLX^Qq{_j%uXeb$M` ziHl&QLV|EJO7Hb#KpNz@GoQ8P8kuCJ<%TH!9ZhM{0#|XZe8>LXq(t)m)M2P?X_Wg; z{$?s?5kMV>L2mkALOf3LA^g9c!<}WNTct91 zn1osqdu=^z^pTQ32mBzTtj0X8KUDPM`9%xw@g5R1!Ex22nrh@3p=0I;GS z!ea-Bw@(Mcqt;WK6GcWodK%k3JHg=3o|T@C$9&J}$aZBzE~dRyYQ#DKGPnL%r9iB7*CT-2utEe&qh^jXTW@d47@KcS zqPLd@H81-MOIz;&^P>mAT7wT>sVb}0@z{j`@^afK^%l4{);Sj&Bk6Y*=uY#v+s9_z zWYBD|o(U}f*HFTQpHK_b!)$1PsmwBGGo4L4uHd2~@i( zfhaG??a0B;WK(7}9#YK{$SCm8z)Z9L+iOc3XtCUj&#&X{!#adW>`EZ-A$r_{7!aQG1%&&Q8k#vYv^Ykh`&UamCVX z@%8kO_!3lpD&Vbh6Js&+?EECaAn-{Mj&v%=LQmJ?ve((kGa~SnyY69Tozp;fn)JNK z^3VEAGh35wA`0z! zbCdk|%(R`=ZGLTyR0|yN7Cq<*QTZA-JPmLs%i85$0Vhc#=Sg3DncWhP!^Dlxs%!D) zPZoIVmo#9Jy^Zb|MUIW9&1R~T0eTKbqX!xKxt>6gRJD2KgzGy`M-&9f{C8tn*r%Px z(zP=t3w{C+(tzOPpHTT1nw!7A+G-MElgYW|vf>pfOW`N%q;Pi!AMK<~^0|Jz9f@e3 zZLn`HE=tcY^3+c1TRh`+EH9d`b2%0kU^A5p-oOj0UxQYP81H+U%^RCb@J9+7I z+QrnO`)+UU-2_Tn6M(7OR#b|<%gHIhDX))b@3b=#x{0e^(noa7YPQfD0A#tOG4=kG z>Ki9_c*6-et6YeqU@hjt5DJhH%#Jg`Mk;OwPd~Qv#HH<6329TW@w(3yA0iPIn+74u z@y1#!MI=tfSfJIum-+2Ld=Gj3+`tTL_-c4L?XqnLu)#w^A}cI~+gZ=HD1B&1#Ov{` zkgW0wg|SeGRh_S+0t^` z)g1Kx*x_W}Ll|Sr%`k0g)9Fb+^qLI90!;Lm?zj;C+;-a<4f+d3MIVJFls2yIvD27X z8kg6EmAM)LrXXUt-nsU=YcsCr<6?@cVvMRIcl8a2$$FevZ&VQN){ax@dHQfGvSG=1 z6rAcF$q=bzK5f6@RqZ6N?z$dxljyg#cYh3!65>;p3Ev=Y&;`XzgwC4wXxYnMgid=W zIGMF-EN{EhAiom>&qx3md0Lrbx)axQ)77I6Q+NTIP38;w=nDG-N3jejuw(q z&enFJTKeuV9u?zafQ@>4C@Y&n+sV64hcl1;H%HHzs;Lb^AJsGCiFulNW6DVv|I|(0 z)yy3Vh)m%<@wU`Gqxc7DFa@*AvOkWw^(TtcY@sKO&DFAFxw)GQEt_XtMJ>< zw9s&9&TPniwk11%1gALBqE#9WA{9u*Va6fgeqk%7+V7n4RIu`fgu!xo?&|VzHdjCg zn62qefjr?q;;Z{yA-uN=)$ciWGpB9{vwoV^NYoy zbNK-yt&;SeBU0_Kg^E{`Z*uZ?bpUiXoXm)S6P#m!-s^(5AxK!7rt6gfa(Vd5;Mh@t z{gc_;FCTeiXXn95UQvsF>k&0jCHe0sC0aBkWGQ?B2*<12?1)D#Ko1%}lRZj9uny=J zE(X`J_XoY=0xHJ5ohcxoI(LTpnADYYYr#|IZdK>f0CCN-1a=}=iIWdB4~j_A1^Bh6 zjJ|()33R0y8}d~3D>)C_rFIm+Aj|&q^n(aGx!aZNoCrdr)TOVwxv7?AJn{~Lu5P@@W5O>3Ea+fwf*IM++W&!4r{tX zb{VQPL%tAdJl(1LUGhddqV6sr0Jkzs`w@S)DgnSP2dMxc%b8I!4cc)rXihr?S_>AN zH!&$`GX_^dmW5ieztL?-JPomUDV2P%r<>F~VEaqxE$0^y&@*oQvt?=Kg;_adg}DSC z^w=*vFw;DnI~Lno%paWvKcbe-zyd79KCVIB6;eaflt)<19>ud-wWfmP{HVv1@7lD; z*WEb`(4mmXqmuS;01Dm3*WVA4%`4u$Tl{MC-4kGfQdQY&&$}|P0BOt3 zU$Pd3$n=SU{wXo+4p`;wYUKPU(7p#6od(~~-1K%*Jeh!5o(DX-VNu3*W#JJP%|5tH zL%{-8vH(=P%GDXBXv8!!dtxFS|tGAO0))@N~JlRVuubh64XsibL!dz zvd$Q^uUvf!_jHu3Uln8-tRdENWPBlgvZQLOmMNLww_7-WR>wR^;&QKcY4C`=FuS%Q zm_zfNt39ZBI)d!8pSY|9y(TabbheQONUa#v>s*4OA?7(vTNB8luSPFY+)koK{g`Jc ztZ`fge_*n!NRil5(X>=>edZ2e62<3yv96}Ru(8b^N6>g~+;o1FVC8xeY+?6fND$+G zX5Y+-JiUrbedTM1Oki@@z`TjV}({tSEIRUk|>)E#zIBdIe+5pqflZPCkK$9c8Ku_!^2-BBqS-z#{!87C<75E z?1lpurWT85NH0|>8MM+mnXi2~v4|wn8=0!;W9W8_k~~}W*8Nm<=gNve0POS?HC0_4 zbVzE0X$kA5I+%5L^VV>`6p%?Fcfh5sSBINge`p(Py6%TuPv`5+E76yadY!5^3FwQI% zYDkQV&4Gr!+?T?wDXDGkw9|4c=tAc}V26Ihr;*6*nbh4WmFMo6S=|%~3JG7@c@f^C zN>2>WH`<@)o1DAFNnD+m73p*5hTiX@L}SNbt+FWK zKB!&4EMI>jQ}GhK$T6p1*?)pZUPw1cXUF%R9e$uoL-rZBkJ#&x+vD-x1Lpdz7s2?L zz`6{uy{rvgeb5j}K}&8DGDwdpHl%IX_7t<)5y4VX4K}e|>6tbL>J`Z5CgHg~KUKS2Me%}1Lg-3(CHov;y`HF$YstzxJcnU*CM9p&2Kqfja{QW;06h5lc6T!iGn+sY>lQOfb#k zq%JQkC9#sIe5-r|1)PL>dxA7&WnryYYo98Q08#;B5XT9|^+_Yy(%q$;BuIR-%KZ;N z;i>k6OvaW}rmG}YOV3OL=s=Mx|7z#iDRa6O$=hCn<131p33lxD*sye-4YD}P0BN4!OHbo34$T`*JitURZSe5Q+=bD6X}mp%rdVY$xW4C(6Lzh|D{ryHB>pMnk@SJkgaRBl$s zcYhDdGu?h)XvQ*ppLSof(V@HVS<+S~z*hLZ?ffR=ws>Il2w89C>@R)H5lhko$Q^32Tya_!)uqCc~=mt=Lgs&xIdZj>#iUtXY!G7SV;>=t@1{g z4ue-S+2M*u=4(H}naGcq82x-5dKoN;Jh0FipNr#noF(ky8G(7@-TSn-W12t**0}@% zI{6js9;CsYqZSp4`rTx-o-)eMRT_VoX7$Bxmw^;k`>7wOw*RiU(Y;HsVSNmbD6^F7 zok=;E$oErP&9Ab0#9V@*;}_3Tc8mQ6uI1tZf!0zh|r+4C)3<-g&^Ao7af4j0@FJ< z0qvvZe_QI{jOYsz3`dNRs^e4UmNo0X0k6->yO+JU{-Jx^dCg{NNJZQUAb>4oXPZ3^ z1pp376+9@hpS;&}3-l#3Do$7mN@AC;R(O3M0hQGoy}}A-2!ETmb zP}W+aMd>+TUs&}v%~O&ysZih+hQ9~oWHNz-mnQ2I-=E}9mPD2>H=82jSoGS+B;t?m zy3^eG_vd{3l`Q2HU_kfT@NkcS^d$i1081)tpu8YN&@s)}+n}{Z(?&wVh28?xjQMe} zGZZi;?1m^SfsE+0*uAda*N@`kj7|Ez-aPwrJk30El(;xM4DMU8-Jm!FI(Gg71@5h zdlBYXaaP zint03QAQH`Db4S6Gsyc7zbHPie1l>5&}$}lzv~waqW2uAi@bjYh!6vRf%_ExKDq8! zk@e|`J^E4NGyo0Z>&Ud=bH^;U2qPdg+f7rP;;j$?NMa%~cEPR3%V~dVgv(Z93EDKQ zY%RIERT6Sy40LRO&pr+SRK^|m|Ct6H$7g&T0VeH~af%K8LIld{^LAg|MgwEgq>%6h zY=LB^ZpqWU64GJuh8u%JcCH;B-gB68EKyS?D&Q@|2OU&(b_iJ?Z+Wzd^*pzmEYPzJL#v-gBFeesBGi&Yglw8#G z#TgBGsY>5-y~+My(gk$6dKtfh!K) zp^|uBpNFV#e%e}!Dxe%qGPT~uC2}C}WW=^L0o~-l&1bA9_g&-qMEm8Q3F4~9$+rlV zZ3W9oUwz7<2gIYn&7J4R_ggdW*3tUw9Lw(mLcJ$*hWwSWa_5rv@$#RnDg3c?#)og7 z|6ja`jBt;&ojN;aNHAUGS;*AkG`Giwv{mcHog10wDeMMa?IMqq*Gl)02tOqyO~He| zH7A0u&Ij~GxJmyA4PAIId4THeLi)^cN0C;pJ7Vs+x$HioD4_Q)4 zGH#X036qU0%7V+}BvYny3v;b>E!Q`;NpSI!)S{JOza+xZ(LLY)3P_2>uU%-WMI>$4 z8q(L*YcziX#5!N4ra5>ipSWYV0OHeYuD0W#U~^CYbn6nHf`-YZO=|TlLv942mCYzqrvW+jwV90M?FlyjIa0Hcz#P z);=t+Nw9+~xK)M7&w_$Pg!dx*I1zX$7q8MB3{nZP3YK5o%T}LFNp@|PohtI>3{&B( zlnnp8n@~%)G+kUY=Q-Yxpo&Ses`>bZ2~l+g(tPVJ=@~2d!T$vsakAEM&>SWo_vS6w%wDwG_;7dV#WRq}KHXX3MpoK^JN#CANrgrRe$b1BhJ0a$8 zxChD+7`{B71lBM9AHLdR<9^$P7WZA!VR4!BVUvb3Q3gxfIk=%L# z3?r>Fz(wNnHca5kb+$Gs#xaefmRwSbx_F?_WQzc&i?v-38~?b2QGx{Ai{L{d)%tsV_kxt&xrNovbUt~wf3Ez8FdrNk%9Z`AY0pR3V~Vj`mv0bv3y&;XXgZY~U=K_E z4Su#C#7$cLfEFT9DFMw7wMI8|C{+{|-Xx;0JoE_vp)epALd4F0<)3u~^!`7~SizNU z&n%#O=3`X*Nt1h9vw36rMKI4rZg3?8PXkz)5Oe6A0l;vlN)1>S(eIDCf5Sw#P%<`cKB4qT2+W$ z=XWI2j_TC2bif~(=6MheNu<~Sp5u>i+ zYs0C>q&?i6<&fhydQf1`22f5L>ARqMYxw==dSv5@b}1Pt!4Bd^lOW3UnvmC#f>AhD z!19s@nXrW0Xp5rG#|hBB9o~}sqy?un4lm_XZRn@}V8UCA_aFIwc#Ia)9{~Nf32ql*jl-T)@7YFntODYZS;*GWN~NEoWolLjFlJzO zIt5AU%FF=Gx>V!^E6i|MtMzahP4~ROfwB1D|iRotWEddiDVsFR;{nY{N>FHIk(OIg6o{2%YzW7#e~bV zHS~T(K!RZX?1?n>E#!O=jW2L_9@T0R8gkzaG<$w^aPIpbmTmCv-^fCVU z>TJ>1^$_!w|ho#Q>bmjUXQ76yH)^% zw3G51LvFW#wYhMo&w7&Nz1`BaDoF>MN6S z%Be?Hl+~mK#UE+n&vDmZJrXk50B$^*dKUb&`B!|*7s;hEC1vuPK-?dr?bTXerNlJd zrQPQO(uh?sh+lf@@AUq$(p(~tZ5_1#{7aD8J5oc>8%+$duF*;uCtI!rf5HWer@Mfz zwa(m|28TZu#==(O#Bu0+*wO9iw|S*Cr{W_=Q)St-dHrA?(q57c(qZmGIfBt&zd+zX zYR|ssu+tVL6Hjpo4~VFX@Krt&`7$7~#{{O8s}vm;xtZiWB<7_pugJ~Fs3{3-`R?{X zR7E6gq_kxM6aSdWB0$(`mC1AipW@>HTXldy{DdM24v{&@iqYc2b5K#_z*tZ^6Mf9e zcc*7j?fW9Ua)!oP+`{G7U^1Luy3F9tyxft-hsJsz!EVeM#B90`aIi-L-WKb-Ivi@7 znq=1p%_a0JwICf4-DxFYTV!x-xyc7}T^&6l<+7hb_(Z;)j7Pi{nM|6-@5U-?JzCx9 z@yp*VZbK!YFQ)32+^_%00;DD7`&tLvFNC5-6Cz4vs{Z|-G-I9X=*I4MEjS3 zjgD$Z;(83vy48?#V(u@A|t!ZgeFu2$lTJtR9(Hf2gl=*D+ZKpneu9!34bX7i8 z2de?RcXEa54@16={Ry=vZGZOXUg?`B!h$Etw==|V{l416{;NT-%joXuOk&1#o?|t)VPS3O6 z<4oR9-gK&j8Pmb<(&zHtKM29Eg#L9Rbq2|bi=#>5TIR-jkiBFmxb@C;0eSX9c1+Qd z)W$`K-J@gBxGf&HPn8v(RWn+b!yMHZ+(Bg|r3L@)Gm8!*<9zAelBpHF?tXl~1yOYXiOB&+9gJ%e6%a4p^B=_Acp~&6e@WQTg2UX5y3@euf6r7eyxaeN7;u zLLnDX&F8aL;M-GgH_eBiJn}ytkDSNGe}KSf_^+S{a$g zgv^FN1VO^jkF_NUY>0ei=D@Pk)2~xw*WtU6{yt$DaU~fwB^4#Djvi>w(06=6o;3M+ z7O)pv0>kNjJt&AV2#1VMP-3r8rxQ8)?Y?(|R{~`<>Jdol;7!&vDB|e>bvBgS)=+iM zk|j&O1#Gq1VUv~8ZW8EcZtzmq$CTYJwt!oF!D~9Gf#O)pK=1YFBko|}Qfwx$%ga60 zZqFAt$ik2tIXssFL+mLC@wBfQn|9CT1lq+QU72l2jw)BgM=peeneExp+xgFvRnKi5RBfd!K56De@26hG<6 zM-M|PO>TFAEK*#%IA7@&l@ekrEpq?HIF!nr3fFQZfLR=qkl8EXky&@Z998^a=F6;& z^PXUH64oGZDrt`vn^n}sjGs8CK5?_VoH$LQFtx?2D(!(jk+qO`PstE`tDVBq%b+!% zH8!q%k^AiFE(72&UC%HZp@>SC{xASwA|_T_W?lvgo0l0*-!16xL{(yAs0QjxvCPW- z93bKpnD4*KWQ|*^1Morm97k#!zxv5fz=;lcSrA3=Hcf4+kOwIUt1JT9h z1AeZ??YT$(QbX!;n_Pad2bt0sw^1S>&A|XKoC`;a2Cf1!fvU3ZOwuJIv^?4MhbknNR&#k^dwNKYb%VQ0jd)-$aytD+(zO`Fj2@KJJG z(Z|m-0fL6Nw$z~)Cbh{4vo%pc&~|?tPM3E@(Z-)Ba=jBvcxi`A@*J3AHYC z6{hp_u?4$KPv%;|;0?PS5J)Q7iu$}iol9hFpb0%YRgEAVvRkJi7lm9zD?O;J5Q!AMcT11xhPUj?PtEp}?(+59)J%?vXx^ z)KFkN{ir+n`$(AI;j_VU!>mK%SrTIsHgxozSJToUr&`iS$lca!cp4dXUm88dRjHxN zteP&`jRb=h&uLui&2jIE`SgcVN~vJG_C=^MG@jyN2)-Z`t(;Bw`HIMXdoM@r;ZD3t zkC`d0$xCn1UA0-|#-%3#k`j!?1v{kAU1gZf-U9#206oOH6GR6}O{K|}J1L;`k_@&y zm_MG-y1TJ@hy)zC>1>jSD(tZD%SHTQ^L2ZgLh7NQ`WKob8JWoG)3e-Cuxat@qe(TZ zgS$I3HM8~9At?J|68_)7`bJY&VgPSmIEND}%Fc}F(+gSoGs}GeYin4n#ggS*dRFEk z9!Z+k(z`w2IMjiV>wijk94MkJ%-2bN=19@?d3JxU_9{ln^9+%Ox)DRW1rGkaQ0w+& z&T6t-c%~!qO*&%(-_H(nVVS*``~i6QNOvoEro)6zaxYxvV0Qmcm;J9zh(HhVEb$2$ zEp`J%haDR>bB%Q9OVhLSiVGe4dq%nz+Yp+@wysi=pCk{%M}h)XfV-i(=xB|hw5b!E zx^2!w-p$l)_Y9}9!)_tFi>OXU&$~*1ZHl4!qT1VsCs7>>3XRR&e#{Z53~_dWNCg?f zOMPrORX=D;vgy!&Q1H%B(yWn_`ETg`fEkRhUKb-_MVKC4Wly;l^#Fn4{ms4c)~3vUAFg6K^D0VS1BV5CeWa!7wqJ`n!xXq&w$LES-y7fsp_wo?$nVpa-wAZZ zF_PT1wl*CXotR(leUdyAe_|u`QqQdRUthhP&7o_(0&q(qC5XD^%Kp!<);hjdckQON zm_HnK7}J={@wx&&{ACTJvygbsH!|f0*2RYvi^0Esv}~y z7eqUpNeXT0`|?5ya@%`|YJPOw8ncO7oUS&@EUvb-QW{JAw>_N2LN0+<1rS12C1!BH z5wCPMw$J^$j zf{H?|Eul{B2me@y4X_SDlFaxF;pVPIUe3GxH%=QHXD`FW@vwlf*c}F=wlcAofNS_$ zn{FqQtZt66OYe{|Q<~R<-DIeDRRQ{^BhYU%s!l0nYG!z52ZJErPdD01-Pjpy|~ z_&eebFviUpZR>q@KRodD%!KieFTYGXsH?%6klV@N0!skHFEw(@_UKpav$R{isi6=&a_p^b(R!}@ zN64gt{4Xttp)`S|qx8_p7~X@1yOu5nsYIScC5A7g-`K6T#hj|3C({&+dF!hB-auOa zFGkvc9+H$0;ZvKMUW5d~YO7=#4YK}Nn&`@*JeP9vIutQlZwo8azz4zq@_y14!sAO( zLtC$)=8(YDAq67Z&cwcvD@7&UcHP&_Wv#r_jB~W~GsP{)yPglo@h`PF-cHiN>+&(^ zO9&Qgr_rZaOyU6!1O4aZxR;SnJ?ID4Q0I4QOXjLpR)vv?YlC*wx%xr(2$@|?Mvm{k6=S7TQ>AsSZM$<4Dj|IeOjJ$Yxn;l)U%d2KJh92!b(_RE~1UAZ+QY>u2ky@C}xr!() zu}eD@_s{b8^I$-mZ&G(2`)x;7EY`)hWum@!8+?MW_*F9=Z_Bk3~6FDFp?V z?QcswZ`kF>B0PTg+cf`y1%Rx2KmL>`Ol6AnTSbWd?2xs6s%14pL+!E9Gs#RtizgD* z)iiz&wAf;F=%40MvUxzFIpNhtM;hfOm}Yrn2y;^Nektecc^)XDI1{kxye>D8u~?Ed zz=mxx*w0x)5*B3h#!ykW=qOKR_$3=$$m<_pLI+tAWKKQ{?bP3#TR0wLuCB|^$Z_l+ z8R@#S6y8;sES^O!KhPxn>W13OT%W=pWKZ?==BB z5uKnyJ~HMwh54xzdoa*!mKbW2V((e1YT390OnIEAnDP97zr6&fHW)_e-)peXuM$%| zdEhjp-eS8~1dV_h0bA7-g*yeV4}CmKJG4{5KhQgK8Pwf(7cLerVQDDf$6EkXrgGk$ z<^rOhi=%v)Oak|R9>E04=h%B`Z73G8M9;rn2>b+%H$6Zlx1#yd)fT;e;xNAW$Fk2u z>O8zuMn(t$K;Cw}Zm1~miVbb}&RkdKtJi)b)1LN~2d zIzQGnp#v10{BP>&J;4d2v&Ag5V{gQ4o*?Z+bbLPLX?eXl5{ zjZHl8rU#^wEEYL(dm!R1+$0Lb>VK=lLPMz6XqMTvh;6|xXsoh2c+hcw4stW^LhXV+ zTo#bnqH~!)a%heZd^k>P(^pXHD!(~NN%7Ol8u{pYo3ZPIV%bR4)>prgLCc8$u}0et zK2V#FvPenN7M@~;FjbXDDSnk5pM=>}A3Wc=IGZ9yDx4wm2Cp~CIw&-8W69uFal1vxwh ziOHoBhp@7Vkf~GwJsz+zhpQl<5 z$kTZjAejFX#7)Mak{yDce3LqoR|P+_(e8mbD(tL}p9S;{&|7Zj?UUgk7cc=!GQm^u zbf7>N>mhqu-oqcJ((aT`1un<;Bc7OG-npl zBxn#J!3rbeGXS^&#HXZQLHUa-?0t5O#7m^dpI>73mKM0GsmXRx{)yhZ(q;+{_8Cbv z#7TW6czUitKiduSH0SZcMl3!@rm^#z!Nb&1&ZQ!-tG=6YnUJ{NE4o*%ZJ&RaOaCdd zynzR%Uu7FviQjWKyWrjN>r&ERlRw3jAW7!$cn3!WiVp4rt;g#JpSCWTe;;6xZ&48r zVwwWz%@~lQcn^4ZRF#V8ac|v&F%So54phu0=pSqAv&qm?B9+v)jLeGdH)||~#Fl$L z@Wd&+JN5eU@gH{s-eb8vq+<;}IdocKI>)QInOzDDR4s?wK6N>U0I|0D@3c3mti1|M8;EfK;5|l2O^(K}b~3;&S@y z!z7u<7`~cJ|85ciD`Q2?Q~=s9uiHt=sAzst>llId4R-8$>dVTQI1FpU9t&+|a(>=$|&dltnpRqTw7^~RmuTx{chu%3E##qtq;OO=Gx7;jX?mhWmuLiDIP zSJigDtn&N+--{YRwHqgzy^pViEbjz4qZL|b8Z=Zjdnc&g_{uK|w7o*oWBm3XGmc>s z=<*Mk9F(<7!{T@}!qJej!j>f$cYQb~w~jUcijPCUgwFDx^a4Dfk>cdyvuB)THE1}K zOl;+jtuOK8q7`J+Mt!Bf=mF6r9PdI3Frkf#KmZ2D(DtbjIV1P{ z8H2^HDKX)0h9rYi(r-{`D>82|iRu`Tp=nI&(D1|Y#;~Il18_~+=%dZ|Qt#rv5HqSO zc7}Rxvq=U2CkwMoj0|=#1v)7V-wDp1HyF2jodLE#Px$)aUw;n{PHb8EIlB{6znc-1 zY_0UJXFGW{WJ&WA^l%2tZl}>Dm81HJ9kW|u)ZC7Vh;ceg}qtF|Hsx_M`gKn-NVwI zD%}Vev~)@f2qK_@bfX~MDL1KrfJ%2rD&1WY(k0#9DN@3>IOloa=QrN*@y8kCsK9;g zz4lsj&NbJ*YAfFn*;jrK$wA@{zJF9g%J`FLZSRh?sp*bSp#{7_>%zg5R%EW1SoO)O z@{oWco{8NXzc%xYtxk^bh4xN@wr8c^5NVN#o^Do`sKF&i+xpj^;V?~V)rO_&CYA0i zZo#^EHerEBfSS;cJI`cGgeMnNKTjtl^5o0Y3OhLjmVIRyv-Nf^?)StyOhb|FUMy3x z4UEyQ?(fqLxr=eXPsM+wySG>L5xn**nyeBb@xg3`X3umrDrw%NYkh zDHgNUwV0Tn8ylCY^gG>K#eDt{Qe@pYz1>H+Z%s43t*TvZZ^z9?4Rlmde=iy!Dvw$@ z0D|OLR!}MMM%qs^`qKr5+b6v=@<6V>h}`k@-5uz0DVdjF3sK;NsNz&v*hdRyS~0&US7VjvGFor zdw+l5hl!O0M~4jFG)H9MH5G*R@B!fFGxtvx_oV=L{&vX7*A-;AS2PQH3JA6$;mnr2 z?$3NsvLftp?CP5SCQ=Ot2VVr74e6)$<1kZP%h;$Am!a$HuleGY7$T^ssGcY(;o;%c z)z)%zbHCEkk_a?2HTBbZ1Ro1k(+`#wl8w#$f~5FU0#UrO;FOk?%wjC}ZuMuM1Z+LB z%2$~5tXn32s%S`bCq;M(vAWIw|B;LT=Rs*C(+7lvh11j0O3TXNDH9VDjSLNQ^YQ`% z18u3;u9u!^UJq!s@Nn|0=QLDn)^A)k;{qmRo-ZGk|55+}t4h-uK=|Es%@XZ>S|jXG zmjP&jU?S*RV+L>Dy!re0Z+MQVsHm)`$$VT~oj-qW?Cc~ZCf;^hzm5^(91$1J_T_N$ zqhAqC&BrS-Q>=YA#BWl6e_+L4~ zqoz)@7|nNeb8~WV=wEm6P^Ey)aJ~1=nujK=-I!ZWR(4`?(#~EL8AbcIgK=Ndxch!H zl3?sm{Y=2fGJU!fd2)F^qnPRj#IaI;_YVN^=1VK5pcXtF5gqD6n>P99er@qkqg~kQbHx-vy>eM@P4_vl9^! z`SRsUNN6YuGV;N}ft#C~IS<9Z(GkR5Qc|MLUh(}q8zW;&PmhwOCiyLm7cYLbwzhV4 zJrEPC&&bHAtMfEOi2R_DVf5k#25_y36H0fxauR&*M5XTS=|Q9ZH8k`&D$2>x@vWt0 zhRR)mMNT-%3~`v~_3sMqOQhRqYHB(-lm-U}fBH07WYo^CT}j8n!avKdEh;2*wx(oH zu(D>}3R2pCj!lpt?D^2pP+3{o%*+f42}yNzwUw0>eZ`HpFZ(h&kXnX7nYRZU}8R2R%T~o+g^iO6cZB{=XS)*v)~W(=-(hQ z3{G(*E4_a5`}Y;(shUmFNe2<>K>BkS5 z=g)s%oE}1Es&m?oi;dOP)}FdR8N4Z8j`V+jcx75z^S}U+^jL2%yNF0_aWQfGm+Q1D z9R&|nTPtF1ZTZO?@H^Jxed{Xh`uf0u<`zXrBz zad8o<9c0KiZ{Dn|tVBdaz;{#O%Z+`#e${ArpvcZW+)tAe6R(~>N1NE3pHI!p!(nHo zr?)-c(tP-^WNb|11Uo(01u5}&i?q+3VOotCX;e!(fi1c}OlyE%|?s;h-;<|``& z2nY!J4d8OII`==ib#5d5{hW91pw@TD%F22*EB6PH{%@QI-BwdmGv*e2_;9GBqho4{ zDno#S!y3+}ogMLiem+iMOR8!PFE4LVQ4u~qJ{$@tn}W_e32A9*v9aURHO`Rm=PYoZ zRApsh{PHkFUH=LT!}-6_{)Dg;|IhE=w@FCg^hiP{s52)m&CtQY!PHdt-*x{*1u?sa z#v>>wC?>`pqf(iXaR=gtj;^t-O;%I$v^(~pSzl6QcsM5~CnhegU$W}mFUiJDSLIqf z3up!pgJlD`cLFu2MGBXHer+jwc1+DyRH(9sb~E&!LK1|9_%#pd%hS^no;CYb_~VSC zA};(u-|zpVoQ;Q~qCJL16B85M46aIoHNG6w; zm-m2$Wp!t|CO0>iot-^0GBQ0qU4@e9p9%&kY_6{a;gkO0{{7;TlHJ*c-Hi=wA&>0| zUMwtlWs8Z42~-aogK(3=xyU3u!cZ3j)2ijU1|TX*jzn*JxV{X0146}G@#KFWxb}!M zwi`k#CWefOiAhSTB`659-yl0&fAc!E6#smOv%0#9frh5}>ecf?7#Ki9LxYkr*WA+5(wC%m;`)eDH%3rb@G+NJag1^&Xl9@UlPi<|Lqg$gHgMWG zxKtt_#$nGoJ3HYKA<6DptEt^gRBqRd3NJ%XIHbZ4e8T+a_!z2RDPXUP3TH=0DD9yi zKNgQ$8juo7v|=}95A0F%@bRIOQhVI=S^e}l1CAR6GHe<=hRwWD`^V0X4h;@) zq@=za4JYCwX+%a**ZQIapz8aP6A-{OH2L}Y_`gFT3kL+CQ-q?IeTnqK#FLPw$Tlj` z_y$M5xw*Nq@ew~iKfqr|UfHoyq9TlpD76}6CenmOlALdNJTOd5P0!BHTb#oa5~c>y z<@%Dv2{>@^@N~4b;k#j95gIIT;y= zGCf%S_I8X7%99M9;$QD>CN=3F{rMyHU06))@_2g^iVOq=ESG|Ug3W8FUT_3{w6(o> z`H}z+&$de21A#0N6|5ift)1F${tfIF8;_+ykVf zx~4|{j;f1GB|yHkv;}`0QhZu5kIM^J7d&iSU4Xp_pP+N4JvBT$JT&x>kFU*`TO#n~ zUoEVEyFLI=YK~3kxZdUVqPi4`n^| z#n*cE3d)%qRB{&=0YSmo_;`!guXU;&*0;t>AgTb@tGrB(jcwXQlSo2me^ALY7aSm& zDq@At4s{BEg!k1Yq^tQe)t4_D?3S@BIkjz}s28@*&Wb|-NXN*g!&)XxAT-xA6@II(kaJm4N|LxrL!2F$G0jObjNejD!Tzd+GbE ztbV~v!otE3ym#+*G&M;;t%BXli1}eSKV^)0z=PN?M#sQVR8(YSVA$H;ey*;roG9dY zabmkSyE$60xwh5_aoPwVVqswc(i1!&pgf6S&f1r#m%se}yTcTyJq9X$aJbM(>m4^q zhOZ2;T#%|ci_zz81n6oZb-`BhTTSg99_HobytcHo^!$*SnF&D$g(7=W>c5w=QTL>bob()85S@$PIvdiqTWp7?m2q{+d-gHocF=74~J=4MIQcBuG3 zSmCE=+}&b)L`W}{J^-*82OArb6@=luD#XGdWLg4RF;*s~uV25SMdNC-rZght{pNGw zNyw?GO*qLI_8g8%Aght}8$e5_N{oA<-cc1{uVs(xD1z}{(ik574$>K{dG=mSO$}g- z$?dj{LC68q=q=v#L7yECj|8$TU(R3dx=8j(4>D!?Lew09e>>LDIH zJw=BPN%;*`Rv;YYFT(mAvPvv zcw~g_M-YSoH5FB3P=RjU2icGyTAT^Qg9i^JtRHf7H`@QbxX{+o>FMs~;pH_kHf{_8 zeZy^MO3>BSwGy#2Q-||X&eoPoW3TIK^#wprg8>|jb5)TkN3n~&y6wsOy*jfo6-xa7 zQtP0{LxY3Jw{K@(6ATGY^xPw3Zu0gHneeJAL2UoDtgJu#?X;9+WVdeL9vL3KXwS-o zB?eFjna$C`A?1K$%lA?E?Eu+yU?xz_q4thXOyuU|_#6US{CmFJAnti~)DzD?|EZ{= z0 zyOZ9!1?2LY=}V(Ae_r3&@mlMr@1K14?nd^Ec$fdY>KjYTI}wi|*Mby52c`i!{AMv^ zR878rs7!Q|J}@09%kZIjfB~wjHE$sHv$T;p*wlo}9Qe-Mpowqy$L;SWe2IgOKN&Hyd9!C~8?@ z_5Mo>2ob*wu>Dnmzz`7`7#kbEeT(Oq1a+vhQ~sY-42GlupB&&LC-UppuN4)$!o$NW zD=WLZpM?7l4i3Tzw?Qgg0Z0On0>A{PA*fjZUv01n-x$y$AuccxFZ7u|W0|ctHr_C| zgs63O6-*ehv0`CnZm#f6PELl@^8NdFz}BE~=!dK=wudE)dtcgWael+v-PqjJa?cX_ ze+dDRWWSKMni|S)DhM%%rR+{XQW7JW8;_gWsS!aWaKiOV#zEww!=yvgM-3#PMW6TY z!f>F2gal;vpGt(}g`Ih${>HC_xH#<5TVd_)r^1R13-42IR{}6CExpF!fW3Qrl_627 zs@l!gdkQ=6OqH1R0sn+@^vDZB8Kd>1r72!Zp0s0(sadRW@&}H^T zFfjPdg(cfqCqtl6P!N|Qzf@PhMM7d~V$y^~PD8V^yXy^=3z7=3Rd^1-yDD?`hmAOZ zwKcrXkKYQ!&VP6Z_4GKuu6)kS=U+0jV#2*ZPVu%lGaxFGHzMK5`>^(JZ-{T^kdv3z z){@_UKE{HK2zofz0Pt6(jKp~-9~TdqF%0+fiDO8hZtR>-?b_L39(e{ z{T|f=oL-q6sHnaRw^xVZlrH>FzcBh|QQU#e8#9VVvb zrKLxKuu*8~Qmac#Um_zRpJGuU3~&JCLoO>XXP!hPqx~CbanYSY6{J(Z*XFYbP^6GW}d0Lhy%q8jRD6C`s{r%0&$htiI{6@er_EwWW24H)e znPtVsl8$%fRzjuCT4hKq^RpbMsTpAt?mBW zT6SR=nd`a_B_v+q_tMB$Xs5pq4v0fAJufd#X}wMix}w;$Dy*jA;N+-fC> zsiwv}iGpf-@w5HKCH|fabU~F!x3gwubhFVUJh2=Ecz7TfsqTw6vy&o%umRksq%;EZ zR8uOapU8fAXk4?ZEtG>QiA#r8K(^a zf&vK-5}@$&latDt8et)!=5e&FD9DG9_D*)86f_2N=+(2buw;RtXKj7u@-gFIRRwSp z?7ac)vLfDpW9oHP74Kxl=*|S%8`iDjZ-SL5DBlMMU9W!Y4R=2=h(?oW4ZXa)1QbF_ zN-8BK1?3Ndx!>R$KK(z{LPI0w%a>bZMTvE9?f* z>q_mNxj8xw8(Ujj$Qt_kDJi6drKLxpAb6e32P(z$y`8GuZ}dR{y(^{BMwgt7?A__v z>1orn7#t?$DoFjmKh$|5`P$iY`&k!>@so<7Qq?;b`w@CV4JQ)AWKTfWW(yh zlY%5YQ|AuYLY=AsUm{80)D)c^+stfLr^ac0V?$O>j`a3zsAE1aTHD%y)h3%Z%`pOy zg_=!w4F%`!*^ukjIN@cWm$Pp9%KF`SymoZN6W^0LU=HaRvOEwDIJx@uHUUs5msVE+ z8#N2sUtM|v4h9Vyh^&nP2q>U$z;A)vy*Jwx&5;Z#yV)P7u(i9p8#p}(lB}$(yu4-K zzI{tim*OPlbNb+V-QNFCnvOyRKv9dCGKhwa8_5KPGy4S~nMX>vkieF>=sJtr(V}%B)NE|_#!JlLpCpEd z(`_xnbKSlFxs!^V{I!)8d3G+cwghdye$K@T2$+ z@Lyw-dAq7x*k~I|AZ-9pRar#1-BOSJ2Mn`4QUz=SGzg$hx#jr6($X-1Jk^AVh}8W2 zdizyne*TJN(^f#W0G7{>w@ZqOIzfB8e;=8s-e$fT*t?XZB&fk*?Kh7H7$4jSVhL;k zQI#$OcI}!Y=E5pM#RK}MUobvCZX*QBv`-%}K5?sy+ecTtko`D0`+xm<0WqMWLU@E6 z1=|}PJvuT1C^4{xzgDInr!qAasa#x4?BgLa4(0!fq#d6gK^rmBU*YR7*rOj>dm7a0 zUsG}ecx_NM8;_1k^`EeD8iq#zBC#PS)UdYRWt95}zG*FHW@ho8AbUGIC`5l|+;?^A z+bw>4e!2Z+<$G~JJ8F*jqhn8ZY;&z%6DV4p$26%wNG8*OPp@q4MG^B3fz z)xKoX(hIMHP8L0{(`88U1XKbxAd(7j0R{&6I7hM#taWpfl7=P;WPleh(6ay?$w9aR zI)ei`RR_|^WB%YD$fRxezRTSBzt4tzUlEE6a4!HNuy1W`%nS^MAWOp8qD_+uN3*G# zg4!QU$^mJO1wSiGRZ_mCYQ8?Ogs1BH`JQm-hYyI7 zAG5QwU0pb=VNO4yPHx}6NTR6^5})Db z{gI`58X9_a-_>2%+bOEyjkmA#_0A)H7(zXKbXyS=38;fCEM~^Wel7DUfUAcfGihpR z73ek4ut$}amO^}koDJFNGt1NK4A^Jg+Hl%qE%x_FO(hk`CuDNq)s>tE;2WC;HH8Rb z83&0vKn-f7AAG|)Js zkClOSOMWcbM*!uI6g2JhIooKE?!UUiY?`XCs;b(vPyqO%pzz`2M|`N~Al_nQAAsN) zFW0{UZ8>aq+y(&vn{b=}X7=mu8G<|y@r$7D>gX^xH*d^gAiDz1h?RkXft~%MGy^1o zmd^g6Az!t|U{YYw4|(Mo!i;~k3+Yz7JeE22c=O5Psa*4|&v(G3BHKC?6c})llXFqy ze43f*Au7snaNs9HBk)LC5>b$QW>ZzhJKG+pr_qr$^m3KX3#$J`3|W0F`PGzQ{Wn%U zz2xMGrd7MsyklpD>+>&_E|AyG%=-K`nUQ7z2vSJomt_U+6|? ze?U(9_WgTLUtjd+&+g|i1#sSQb$%Lp0uv$2@z(XHJ^Zs8T3WzU09PO=^y)n{A)~(_ zJT{~2ZTw4k=N4-v6eI^48{JV?ZEbB_T-><|I4qv?&Hgu8lrQ#L2*A4kJCN3^(rUW; z_vYyCRMp{<2oQm&$jIBJry#e13<#1Q!8bu>X7rs>85tRyX3RKGG*2%OmZ0=@8gu(g zx{4e;e8<*chyhsS3Ha~HWWFm6fP-ND-VS&uc#wbYdyW1pi)`CWIY zy6w7}yg`Z*dS&P?M4Y`u)q4l)U+HY0XCdpg<&v=AJ}*zu$@yVmpq@069$iXmT%3oN zme->j4dpK|(XK1lD$@NCl|ZPd#3H?~c2ZT@pn+v)Zl3Mv zC21xx$?owcVA6T~kxqgkw4^$oqWF>K8Z$C7s-$1j zoskj$YEkv=l$C(DPcaWzAw*vDP?!$@z?jc{9~#OO@fctP5b!G7MRZm!KE6vxPVo4% zE{mZc*15U3ysMX2RP;qOeZ?+-GCa4kf*yTernQ|s7Q>1gk*UQUD{^)#B@}vF+uPfF zNWa8nVD~|c_VV%q7eSjE&_jp?h#VloXuXT8t1M&{*s%w#xZlNTKBATNRf(0kzhAfzI%xr{f*&*yKyEeVOT* zx})ai5z9y%vTog%*R;cdv>?((0o82 z@N=9Ct*Y`n{1~!__Q%TwN%;33oh+7``Vu7tvC*67FT_MpU4%Ve^79hyBK|a!*x3ao zIyoO|vKpQvo0`2x@%hvkrf+hWuQtHQZzO8WhXRyXFA7B58(3B-2kIrMVpt<0*+wmY z39j+9oR1>PQhq}NZR-Z@)k$D#ssTVnBO}HOXd)E5|FHsO7@i63F3|=e5J4vA3{$*D z3-o5I>{%XbK6^&AwG05PP=uX5KPyXaEV+6y0Jc|=6Hi_n{_Qsp7T~CNW;~AF2Tsbx=8Hc7`*K)JYt@BfcE~M+0 z3Fc7HYNhtf9%oINV{z_>XR64lrerhaq%ClnQyJgI!uUqCl!2q5>oU0h3pv98s|x787~*-Xau7)yUs#h z-c8?E6%{vCaVy^R8=S1*V$LZl96VPKO0C1iJ;_oQ)z(w{OiR^WkaHTHjX0E)PfI&d zP`JP$J&_9|7Or#syf^!aIPE6SaP+)}LDtKHg9^)e>)GC`OZUs)o6>=XO?qgJzcx2c z{_O0V7ze>_=j$-GO)EU6E5A6|&7s1d9gQZ-pzvB+mceC3|B5gQ30`z|U|mPKMrO+l z=G4reJK=l*1G?stzkb~zh8l@`-{l{9j@@Sd9T)T#-@JbPcDi~5TH(;6fPQ6Rp$aHu z4!BY3&!790iow1EKA(FJT@o+~0QPdWv3abd=CCSz!jiv%UOiD6CS@eM!LdooB}8Dr;LM~Fd|Zj(^Oj*_Lm=+rLZuimFKlI zefaJQKn_=IH>qtiU58o|J;_WQMVfy_ z8p3>DNzwO7MyB!|rU)aWc1bC@zklf&>+4&Rk_i5ej>iW1N+tWt6ug%YE3yrXAX>Aj zNYc%!b_*=#&d|}Vf3A?*_Y?b$Ta~}g2O>xTi_d6bxV!Y_Cm5~7e7A>vg)_5GML426!bqLBK+Ev zm59o5&JrSJ?%v;e_B71=%70smmG$KK*zd5nhe)Yvmdy6-(ld>p z%f;#$QIW8sq9NKCQ7tJSvaQn!1{zVZ$U`YhzaD1%t9a`ZRn^uuGrVL=YJD?tj?TiLPyO`An#qRF$%iSfD^dZI);U;Y%V1;N(rXM!?t@1i}Zj zw8_w96BMjkrER{Tv0(fWpj1;7kCJCPv@L%#+&nR-@5f-F4!p+Xthr=)JjAN zt)Sgf&2Ihqs))(~D5_3fX_gbE>m_|+=TJj0p`r5EvD0I(31g3B><38c$6Mnl7e5$O=!I|%4``~UkkVtf`0e7#7{cw zlWJJKSS9CU+k#kfOJg1ZG7$<%dF23|ceZ`3-o2GyDfgRvTU$D3W-d0~7(O;D9Nn>! z{4lRmTc_W6Mku!xvsH`d-$)Z0KYNr2Z4m+?*X5s)Q0NiKB&4M6t*!4WeM}LvASN{Z z{+f|-bRmnofYpYljN$I%xxTih@#+=eb1=GLGymz-zO0x5i=MG@1`rgmvjBo_l5e=W zJO_2fa=Q9<$Vt2mT+d|-uW#gdWG(KEp3)WW~J-^N~oda&0K%HSQmG<>3scx-IkZ zJ$-w-8c6x$<0`~=ZyV>9eC8Jsk;)Qxxft93q*+ZwE3RCM@B0vebLb-7DB9$0Z~s0J zs3n#)H7!f|jm?g(!`rul(3ij5S|D0x3Dr>eu)8iV!0}oBXoQ-a{<6kXcz{a#g={T# z{Zniltk|;BrP=zPzFy{I%&3WRc}wyo(kPM3UZRk1%WIEINn46;(3L1DNvjBS%jT8Mbus$2gz>hAj#@qwR{3TRY?hT`2VgpZ$_dtV?ERND8_uQVAmht{Ed zI5|0`1Ol@2uglKM^OfA0D0{%gWm~mu#vKdA0tx^?aWKz;d^a}=+F7Bk&4qoi-F!0| zw8lWu6cCCu14-dVn&(P4d7-6`oUgg{OzkP;ACz@;#sFWp#ZZ2)Kk$AEw;>E;hbApe z15;vy%@2}INR+~s3*!dYGK}49@#_i+{haU6>36gkH4YFBn!Uwip0wLHgrqUFJ`~EL zJiI%rcY387^PYH}SFfhe&X5@c*c#D0ZEXn^ zB%7t(gtq*rr@FUco@%y_nhLd(DPV+x()USNSl^Q;-Tme%b<$)Zn#}fAZ{B=tp>JMB z;E3Pw*SbUrRODYcTs_Ut_sioZBVf7kr$z`OUaH=``t&OR-B38Cj?mFDt&Xhwk33@l zTxt)B8ulkki?)t zY9jSMjD#h2d9IZgGL9jC!;-aptMujO1-xXpQ2KeK%R+V4>3k}ir>qeWdrct~+JG}Y z^$awlY)P=*w1+HCfrh7D7lACOlwc%bB%2|>5Cs6s#DrE(d+XLx$z70p z=mvmJLW|S3??yQwm7UGa&7~#d^IQ6}anKvHi1NaQ;3Kpj$$Ccs+7);?ulCn8kby}j zZ^htF)q74(PM*(*gt0sZNnas}MOe57+K|xbn5qIJ3#69x^u_%#O=Ip@Fz^T@klIer zb=(APyPLHlq@A6dw%76-jf(bm$^IWT~Xlk`~0vm_v4(IOY6vpO$1jljU1=?DE}-W z^@qbltOwqftu`lco6D}pjV#C+3u_EQOXUogVB=87@`{_G~!GQ&~hr4WS zcsMvEg@rdrXKGy!s~tDtCJ2u;NA0#r{UO7TD#&cjT(CMA*HbMMg=9@`noafDk?!17KB^3| zYhk00d?D71`E@Q^lI|Q%>hie?v5uS+Ym@!?wtA4p1LxP;R*^z8c9;4?ops@DMzb$H zPvtwctchLEpPJCts_l0M@=o&cQwjFlEU7H+FMd~5rK{2r5<+G~7p6Hrpa}cGaJI*M z=gA$Gq2dxvJUlu%X><%%DJlKRp~JT|(j80W_kY_S?lin|snV99*>fR4Wfc7`)MwP1 z@;Nm;k9Tz3UBfrfc}Z&I|TrK{KKWG ze3*`s*?rNGkrF?ik1b1vM`Lj+6h00Y?ytBuNARjVgfxwZ7YZI870K`(c=hBM<72L% z3~)HW8HJK0EseTGy`QR4r&cJ zXFziSOH4r@3dhp&@;qtkF($y{lTb{G>%Uie@??%}PdCst0o>R+I-+0_udVg)@IXdJ zp0mHa8W$$m%g%qeD?aO0qsQmUS2GTF!cMRE4Xu1db@EijHZ_GZ9+ysM?m&keP;Gh%q>IMtk<)z z%6@ewxwmfBFf`oZn-Dm%q4Gh2g62X_4pzJr9brgFh`xPS&18@X26>S~NSHBZHE|k) z<#D1mbh!Nu~Cy^Oei-%Iq$b|4qe;f%2i<+VC-Cr@}94Wg>Qq%jANH-i1 zY^7K7G2YF-r3Sy&$z3-uRJJQJSeqw4hc`Bxhx|VOhK_!!d#Z$Dj;>CQ?zTtbPeGEO zW)`=ezDyQqk_k;SO#EP%UauRx97&?s^}@p9#JZw@?Nx(Z~0u$4ZQPDUL9{7)p z7?qXXWMg~Sb%?b-+a8qKVxx6;qw{mO+3%yVp@_LiPQ44)ja%_;3Qml&t{eqbW}Nhe zB(+TU-m}$u#P$f_bv{=!N^iRx7F}86OKZ{Uyi-`#m>v;RROFCSUgJFOpw;0M5<^FV zkjdh=0q_4Ui|$#-vP4{ps<2j$Ds>r|0tYDv3-rMp^mBTho;%~#H{DVfL@(w z$bChWLY1BO^lkBJ7^gd&ddv;`%7~85#GL@PmtVBYU$@=`u6T*}p`O3Drq=OzAZxj&y6aqUoSNQfj)a{fp;ExvTc^>QzxtI( zh&@hJT<47JAiOQRfq^Dj7x(Hc)H*d}Bn0JrqAO>47jipws*RPOvmLRmp2zK7yTx-d zuF~PYu%0X2tFn^#5_J#Jtc=3osMMD1!|@QZKuw3$r8|^3ZSGZ_#ro|pUTis;K71IZ zsx$2&i+d<)=QlDn#7LcucTc{TS4s8>Ar6Kzv#nQ5QW8E9A1^P+eM-v8ZLe!<4;g|Y zJOA)6Kz0ZGUw<^H7+x7^Rv(NaLQ#+V+MnX3I2|1@8MnQ$wTiV-=SPw5y<>V96ZAeP6l*-dgSeMaZ<)4 za)sorpk(t<6UN%mXN!0d%?FM1RJ*B`9H=#)1m{ilO6%xaGx?V&(kAPs;AbBc}HZGeF>UOV*RL)v2dxWn^4(^e&=E!Wn&FSNRHf4mfUV{Wd$IN*NF zIT;#i!Xf%AC_aANvu9<+($3QON6$Sr!>r{eV}}Q0zXwfBEa{7x7@33oW$6eX1wu@N z)MP6gI3$^>@;JQ(wdj!uDI-Wlf8uy8z$eDc!t&bM6TLF8rz$>Eu<|@p4!&sUXiQe- z(Bq(T8WeyGv}dlthD(}@V;gYQ9JGJiZK3r&I72s>5BPpAP@ z#=qcTGR#X9aaEO)LYXZs1dg%`9etSc+S;;o*#~FfTLnaj3s)$akcjpi|Cf2Lm<^%u zr9tn$oXJ0So6ko`f^mXm6F)mDV9!#GYZh53p036d$?P^nod2{g);lp-@xF9l>GS^3 zaW&)}?Nwa0Rl*i@pp*Q3XY#rIv3h!va(X>`+V6=GW#nFYAo>QlSFB>JC0P6_LCNU1r7Z5e zOk!qcx9WrYE6imyG^P)on}Rs>Oc#G>3>bxy{dlD{Zq6+-+OP5@v4^=yR(@YCR_r{a zM{j!Oa&KMHxD~aCaBd67>>cD3sC`g3KobITwLSI+6QOZK-=Of?umDb{i-YI}uqb%& zF)GW;3%VVxX<64TZ*5IM1MdB2=dKr|FdzZGLY2jTfe}ncX|QdbK=%?X574+cVdv%I zf^OZ5XU_!fSGu8Wf%|K|3)(%<*lD%%n6)c0h>wrgtFnVB+@HUGk<7LLznh}|nay_Z z-aWAPWM^jssRtuMUOHZ#5FKOGNRXK*0;6VkyFSYZ)x=bZ z_dX+hGel_|x>ogeVBKnX{@bKg)`*wX%>lP<)!?rb{LPb=`9l2ACZ5V}PrLkNxP7`f z(thhc!B)=H6Tw0C{F<+&4ky`WvCveMVfwEJliis{c@X8kx&s41~;_gy>q zy^V*n85~OeSb4<|&QWd7d(qPDIvt^jiOMXjblg@~BE!2ZW^l;p=zZLk_YI|8T=X1x zUWooZ8XESXWejj(zEfy+DQW5|vQpyXWB-Tf!GjWimZu+T>&CP9hbU}yY4S*pVYH%T zw8lAh@9eZl{JFYD;;csts`gQ3Y?**FK8{iJTT053uBrj{AVJHCo={D`sKCJB{^yH} z*W3GUZmG7W<{SmOf&M<=N#=+r|@ z-2zSyA0OZ8>8V3l3xoX?5>TlH`Kl_)SeOv4JS~N;W~G724*LPHcdH!^mwYgcfT}~^ z9B$Zg5UuA0+pBE(6Qr0+C~e@(h`#QhhEnqHjF-sC%da0ScLB$rnSmbo07ydF3NuP9 zBuLzbnxQVa{F)l%xM(y>HFz0Ql1Heo%5-bS4D*(%x_`i` ze}#9il%iClRO6LXb&d0E{WK-j6cAlzn}B5**5VLV0YMl?Y=0jG$N=og%HO+w{~#}b~A&6s$20;@Zf-Pn%|9F$^&Qt?KKR1Do$Qrpi)wa2Ug_!(t9StA|g}Z9Rg4d z(-JBw;ZacmeK)qqCP&A|$$KrpODIvl$G^8<>99^5)($MKJpg8;xnNSUw6wLN6kNbC zdq#B%xnO>N9<&?a_9vw&EARy&z~w5!^2H@ToJf2oXm{fEj@DswPPEsu_uglb?*)|K z)L(UT@a%mY$)V1DE~Mh_MY|BsIN4PWqU?!|bZ1mWFn_(~$*)~|z0u%%V;?T<)k$_j?uK^?uOi&bH& znw{ux=DR$^YF=nw)S~U=8wjut-!6Aw#*ViD$u=|X$B!+RnNLw|-);^}_n1x<7a3IS zH>U>%&?w6Ud@Gvj3yZb0c%U}DZ@V&}fv*`5AeGd~w{4*4VP`3*?#OY}ZIcufy+BjucX}0;?+&REf7q#;s$t2J+xq0=(n1`{)CcUQcId zQCXR&^A6Rqp1b>baWS`RMMw+*r1L+li&`&5GP^}LH7{aJtzOw_*n{UhxsLz`$Cnl0 zwp3_U>Jpn)c`aP0DGt~1j(*cTT#2`~0_qOEBJfjz0O)9I3wBqKTbku$8g-K8SdBV@ zXsugwoZ_4;bZssJ8^SKLXutklYF`)s8-3(`9_?^(z!BuVfVf(u-S<8Ud#!yzxbIs^ zdyzcseR5uPa(o2>t&yK#@{)N*Wwoj6JcI{9T%s4cDk2u zn<%|m$B#xo_3Y9shzV!#eTjyzI0Zcl)}mC{t$J zlMl(gLGdA>T5m0drl;JHQO4Jfo8^N2WiBVmm}tEOFikuaQj(2~EEUX9MUINn`TJ!t zxAyj?F1i=gUhRkUGcwxq<1DglNcd|6B~NLo;5NCkOW#JzNUFpA(PpQP(A)b|X?k%l zKNjbrbD7Tc%^R!Gg=dRZ)Lv1yTkL8RYb+_nBM71%_u_oKZGfdK!_;v~zQfFNy~|Bl z8qb~$02Hn?z)Vm8tK;DBLDZrYeNvcwf*E^1qP*hJa1wrWiczQ^}zk&gr!pI`cqIHnkFD@?TY5_FB zpI!U&WX5^ob zqE<=9TiDiMcv)!00%n1O6Abpmc3lo?8X7O? zgy2!~U0j=tntU-pT!wj|yPBCGBQP*5Kz0QShnk8?P*(b+f=^8{+HBjDIXC|o)_N)O z;;Eq_H6WGh>ZpC7Z!I~O5v(mb8ZbHJIoF7E3w{P5#UL4EZXAi7?d`W#R{7t)J^9Ch zi;Ic52PMkJrm(Q^-PLuBfoFkIdS&0`$vXL&(Gu|TKhI6X{E$n7W_wifPZu(9Fnt}ZVpv5t0Lync>!30V-An}}?Yb&Mn1=w(9Hzlx795&q0KK88f(b^!)e0IR-~#;c z;U}n%S-H7xf6pAz(ELHl5*846+$#{Ow`bMvie287wt&8-xZ%=&HtXfuF1yMCDMaVcX+YfE$yz5RNOaa`rIXhZ^sq2c?e6SWW#7SLS zZM!Jz?(Tje$jM2!`+``}U(T#zC9@n%2yM?&fPrvv5v^E&B_E`}l$5>sK-$Z`tBXEs znmw>CU8B-MQ<$cN;a1SdAX$NMQ=REn1k?hbd%@K=Bqkh-+Yr$>F3|f?NJz-07}}z6 z-$Ae%b%OrTP#~6}ZR5uPYECdC$m0Hf_g=)U&H=98I96F>6CqU~rlA3B1I`$5r3#^- z_=0^khdk^0LX6To&1IZmaAv$3+~>(s2Qtp$C$3!V#Y6&012FIfmN&9_{T{?8|#OA^CHYjf=d!!aBd zT@8)LPidKhWQ^S0s$os&=x($Xy`AI(O2yKX^A()5>w`?@m=~nNIljIvmw(Se>wq}> zYMKzB*W&*)K_C@;w9j+$^P`*}ykGWlL3OpWQ?)~_f+3%(D)QvKloUFs=8z#Fx~|JP z%n||J9?XM*BA6b6u@!>kr(_P`A22at>S-^#0fH3<`F<@#bq6Xrmjo^W0f@QtmfD+0 z;GR1=GC*iN(Z_>E-e|s#FHwsD*u`jtv!YT{=OI19bZ}aFI{do8fB=NAZ&ida+-Fl* z$eDA%X%5-6*6s9Q8G%4{t@xzTW)n>;5egj}xX|Fl!wY0zv1}+ha6BN61)R(QU|3iL z?~3sON-ZyUva>t*{aePM77ZgVDvHFz3WjdhkTcBuLA&V)TE*iwlw|G*!a_C^0DT|4 zZ*8%-y}EF_kZrys3Q#QbkgzcLNRSTT&o(zUn(b+M7od>BwD{FLfp=k9*$*)oTfr7> zYK9K_{Ra=kg%%xPI`+|{cOXB_e9g|rT)bXhldvV}UkgM_P;;SO1tBptH3i`bH}?F0 zR9yvBRqNJO2@&a#l#rJ0ZV5#i36<{dE&+iVDs&7ub6AjxfY)_fME%`PU3Ao6_7!KdP^+mh|jnDl1wx}AV>Qk zWazCI?j;kjSZ83$5rv1%fZV1pC{_dkqUH8`m~UvbgNzAi_n4Q$&kBL`TDssm1_=Pp`}_BAFkk>-Ex`5*t({Nk=V5jP=u^mVu(1c;L2l@uV~`jz3;=%> zh>6h5?7E<;(4gM`E=J7Q6%AvzI$*7?ZEm`NKET|3ac%9(#02|R1CGU5Shl;FnVhC3 z;j2%}JD*2JAS=+porb(x4XPP~QxhCj2n9_|f1q?gGAX9PJF4+@ALQ*w21ai4@#+f* zB|u@+A{YOVV(7fE7c~gwiYG{mbaZs!3W0-}?>uqB(9m#! zasb#}z_~mc`g|}p9|cd|p(60R?%9&%#=TTRYN{-a+g>jA@vREAY#)Ry#Hsji)mZJV z&KQ`y77wnQ?2EVHFO*j+-Ol#?9I_qp2X)IolnBRSXF)^nDCiFyvs)_+#HMCv)!*3@ zqn08_|3EsrcW(?l;BDO=zqzbR?GEWR$Q)F%aG_xU3m(<7Gx0{=o-*z6vW?%t~ z#*ZAK)9O~k9zj-S{cl5)erA2PnF-|RHopv-PYr}JfDF=kjHf=j&QAk}i2i&BT*6Jy z-vbK-Q~>bR0Tlqyd#DD6!`7$KxcI&w!Rf~$#@JjBPSM_XsTxA`f#L zn^&Nc;Nc;VsfVd07(u9=IQ`8h^zzzYY>N&(|2+@SE-OLUpvC@JA7~K|YuqljzqH93 z=<0f8M=Rll{^FOogq!XX?JoVns6krpY`d$dT+T&XM09i>fWH7xdNv_X)Y14p07AMNlC4SM zJgPuD4<;xOKj?$D!$32&5*{A2$3bnblZO-EY*7_%}nGXu{EU{sJI3ePfVD&O7FLzY3&iDQBM_VZ^$@NW?f zZXm|h788!Fe8yzt1>zjYTPg)x5kPhX4Jk_kr2`OT)sM;mih&Eal6BvrhN>81lxDWX z0kBpG+L>*$c-YyucXnF-gn-eBUUF*c`y*#&oXOgA(VF@v5VOJF4;%6PCb$P+l>N7uxh!GdcwN2Ux6HoksMO;1<( zqDK0dmWrOf8M=RPpMg0D#NQiCOhv1s0zyKk`y-k#|6~{d*65zkUM&!iAS{D)3CP*-Wps6^ZnZRaT%h;+ zc^xt|^f(~cQ@?X(iS>2Ij>cRqFOe0BOp_eYOnIVt3oENzr~8XgMcPAD&4$+-me6T-xCVph-qDzPU^NN}rs0ATXQ0_=>H7sv!$^MO| zJ$GhCtaX91PK*8Lw{Jjqfa8Y?1>J+R&yC)sgW|j^R@b@~=u@V0)YI;nDn`jd>7+xX;;Pw(L*3M7aZ<0hAR`{piP16JbWwSD}kcP!yt2x8&s) z(OM?W(325i$8o3W5BPy;V7U|$@&`oAN37QV#izjxOd%Fh&t2~SvFC!y8!qDWLZ~;3 zQQ#Bf->5iO=!IkCmWy|^6pyR3*j2dmr z&EXDsbx@T-mWON!KmT3tE+dl_>NCG|j-X8PGNrA4;zv657Ute}2 z43eRaM2oi|g^P)9{`{HZtBi@9YMJx{B9V;^Yy1%q+(8AGOgjdZybwSCB)Az2tia`H z-lMyGbO3q7*?FV;85PHBoHuIEe1aN8c?IE>Ng-22d0yU@}sOsdQ`-0k_)4 z1uQl4fr5K3+I);3k^?eZcrgIf%=~=N>(=!gl00jqkzz21ct*~LFQYRq>*TA)J|E}X z{`b`3#%eKpi}2|IE(|$2i|$jR!Db2*CejH8syv*WdxwY7#BD*K6%-3B2b>?So0^*L zy?X#r_<}mo&4RbLgoo_K3-^-QDw4fv%668x8>h^mi_xKQniS2q8YfkLD`i+wOaH zL}MFWm)b^tuH`Mf;RGuMkTBNfPWbDpmHSQwb!#OHq%$85gTh{lEzYV+KQhpR4D5Nbh~?fFGH{PcoG z<~Epgy?(vEv0?m1w+bHrKYbYy>J9eVH1vSbkU>2Ru*V=+>s4C$YcMMiaVG8TxI@+Y z^93|J@Q1^}S`&5+4*Gg|Nd^8w=d7Y47L5gK^bu3r{wCUh=m98^yZ1FRGI;TjS~upK zLxHXfJYJ6$k1OhXRsyn@bV&~!{=R9PWYN# zLHWN92aXd5GaPPkmNrxXhDJtcAiJw6h2RG!@(mS?#NNLT{!#vMyu$Pe=`PwVDCiSd zhoJf8kSYL;Z13y@8zeYUICjYHKoW*>b`JDR5WHi5NVzS10%ghxBmn#6js&Qr|9)Pa z$X2+kAXNj40I+-f84toQbgO3E0e?JXuWjp}>QDoMVje<`+VX`v%3Rm2P=Kox z!x#nXe%cw}$b)bk;t{$4%qEj3B5b)Lu2E|muwI0&oX^=?VC`00?&%5}G<;R>-+M#* z5Zi6S1~Cqh(s;_TKS!OiX=TSMvM0mMe||JWDOC@z_OD0uar4w|3j!3qw6O3U{N28D z{%d0frn5-P=&&$(Kn|Rp%jFp4s5a?)J?>fl`#g)Fkp-P8s3e!VptLxK%m`)gu=a@n zGlB&L03DQtfD*u9ua5=(U1e2O>n=E_eB;AAeEkM)%*NK%lbDz=EpSM?GX^4#d!V$= zbj)O6UR-?zh#!;>cfr(&0?>`P=y-s#;95c`L3>qZXZN4w-U-pU`|r~trhVlula-X@ z2H+KhD8NzB-94KU(UZ$;sqfx_?_=j>ljO59QkM4j-5&K)xUw5JuO)W=Y9r}RV9;lT zo(YCwa6_TS`hBZPRlq~xuJo)O1Q4)d6M261(Dw-gqAMISRD)&_u& z{;~!zD2S0_ViVon>%dcldj+K=pr3HZU^oL~7s!5>!pz)@%b5RxsTdIVIw5}m(>ig1 zg6H8xW1uex`F(#pL+AF+3*?a)HdcsB7)nh|1(LqE{`?_il6shu+}hx0hY(-(rT+2h z!n>|fyT*JO|!N2=O3+jE9?ClGF`3!ddYx7O0$hJ+4*<1*WDIx(keUyDH>SY#3aV{zX8=>2@JloA;wfaV z|G$F2*6Zm$zNh4_?0J_&i2lTNl!c$j(;6 z#=i03!D`g@5)!#pQeGI*Eqqh^p0&3^(i)q%(aTq?9`5F;hX>tW`3HMgISA#0eZCzP zY7Gr8De1{j?4TeZwUlk>>laKIiX`Fln(*WqkBpR^J31K7`}kCaigk$%X%eXs`SB1G zLQw++Ih;70JM_}&yry8LxVGabHVRec z*=GsagoJ_;cGh9~5cayDjEvP&xjIp25_|iYT_DhO$DN15^+@L8B%Pc7E}lKE*w1ftW@!p^oc>e1R|{TDBK-!?_b&o^>X)1D^o z?h0F!X|P)rwtaaUgNHxK4i;;OLGUF(_SWWi+o@?KeLL}9J(`*-=<2F1txuOpnx8Y# z4v_fWj9I+r>^v`x(j@9dKs5)E77{5ykKoY)Qw6AC=$@d>U!cMJ`n7#+Py0gWSFD=E z%zsdta0Y#12nUdU02~HM65P^tF?tq6QNl}NQ1aU>_6*wk-w}?k z*EYDh$i~8ux=|>49J^M(I>q@`zv{Uj%R}kp)cC~M?>{DGX$feFIM^#0x1zA0uC&e5 zsV@(kko(qKu`Z3@cGhx#0C)^Ik#MoIyFnTbI@$)uAGDVfx(gp4hxr8(U^hEEM1A|w zv9Y@PzeDUL0Na2r0L~1+@d4EiHWrrf0&NOInh21*3<)%EE#}aP6noioyvU`hSYk50 zcR+|Dn^b5>>~VFX-o&96_5X}5(UWc2}P*+HVX zzU~jX4bnRxp0k&0>gs@}28Jn+Nu-N+EdCwf$mOElZ}D(&KwEJP{c>y>1~V>EUS9FN?+_tg}ZFJIW2QcZRHRxB~EkH@5~e<5O2xDigxXYA!x}?qtSL zPjLE7b0SpGPikCzVti(Z&*9V7gyBT^Luy0f01SIXZWxxPiiMq%!lkP+xo5Xnh@4A= z^ij@Q%rTmmL`bIw)YW*b$1#yz;D-xC6-+Fw*QKRfQ}2I(Et!Fq7Pu|N$Hgso#N~FL zwf{Rp--N;sYT~~QzFM`xxPdBMN{Nu4B~1z<*{RqwUYCidao_Aj8W0BRcb^|2E>kf! zPfhi)aC1H9t*;m4=y zPrV39iRY1v_uhJ>?C)AcjE;~0)HgLSNaLQtZ^iPZxo%x5C}3V1DYc8wKE;~V@TpwCKCa~M&ZX&vb**5dSo57;LcC#p-k6Kajle(= zY2o|P%JQ+|{L!nPX}HD8=>hD`Pezqiy?CM3zZ?_?#(bR!l=zu7u*kTrQk-b?&gC~_q8WqQaVWf6PG zd{RcHOwilg=%Q8J<{b?i=ZXqjohKayj7Kq|OCWllTKKJ+YO`}=1?!Lu%>V?8tkBSN zn0JCv5~TL;;CV_(IaBLd3_xLA{qf=?KT6}pC*S7JB8&V|VVgrk+NLa?i&=F?&9bMvKQpp#jbrk2 zE4JM5XYL2jsV%P@W^vSP)3_q${8g&GIUR+AXeHvKwq`k}J|wV2?77%+^|bYySADxZ z`e=M|f-mxMcY$%euV9>t0J{|5r+AVF7pEu`Hj7vnZ_mVEBm7l zOjN2R`HU|}P8Z~DUVkGkBbMEf)KMS|{YCX|YTGSM@Vg43Vv+XIr;EQrv5&aE%a3ed z6bno%YBAnT7;8CGzdHfU5fdfCLOxtP0s*6r51&MYMQl9!onMUyIh{Ba6(xFL0y1!~C95QrU8t`fGWO1|f0TvxF5Ob1gwynLJ>phnF<_j#g= z%YKkil=fb0O&m7#x=KdQ8~M00M_bPdpO@XN{E-0|a2=Y|p*n(|Hoqh;49xF4dRD)Y zNh7a}@l<3E>-Rv9MZ}i1_0My1L!f6=hO*}I-3)tFs8~5xNhD2JtSsu`Yis%7Q{J$Z z7}tkObBR`!<-^8yc~1xheVv3sRQCatmip0I$RLYw?=LZ=eTc0Y^Rq`~Rqrz16nfrZ zn(Tb!LdBSNiO9sx74S>A|8jDl0H_8|3_$bH_@H6e8#e$L$yxXNclPGYf?^FCG#ILb z6b_gP0Q!0`=7y;f4N~1^lJQG=t!wwK?a@fKWM@1j0akv*qQ^55PvwTt^O*%$n(@$? zh{vw%C9&tKoq5Yc633SBc?BgGee?}FM_tcO#F<>|&2Ox3@&GG@ibZsgToi>@i1J9e z#cILC!)4W0Ms(Ybg9}dtUw3&^KI)l+9bzu%8NP|E{gmxXV)Ax9GHS7A;==CA`;_#! zz!0(Hs8WjlG$ig8g8$<&_YF~ml{&tofey*Y11~0DHi7h;4dnf|;_|Wr535v6&9CIj z+M;lrsL4n}v)z>YW-AgL0s|*W^b+qb6ifP4{zyaK@REF7{W^x@<_8Wds_D128QdtE zVL=FwJ6<&(46)w4F$_34aZ)p{FT}phbZy>@r-@gR|EY6uH8GV%p`{}(rV}|)=*#Gt zCQlnd7%tZQjsx`$Sck_)9DpPPyu$#31t#+L=ZOhQf*FCqdL<~E3KdU(r5S#CQFp$# zW*~dEB2CY`+*5TyV5u1k-QII%!KY$a38+1wGvKmlZqAtaW^jv`5EEIcO3i=k3eS~7 zG8OrYG&Yf(?&(`L*8HN6)jX8T@;;?dNwDUe9&0m2vB>W;448)YEAuU?&v3BaBBaI| zBp(#UmyaTo6hq8~=9b3=hP*u@mK~~Yi_WNO;TLC$8j=?`FC5YteU>{|^_Aq;jyc7J zHbjMK=u*Ro9ac3#$K~sP2KX(QF|^xb>4cZmUrc;OB|Y3ph>3_OBONNj+1E6p>Sg4L zH#X~A=I0iGw@*eqrR%LhTFDL}+GNf@2H0M7_lz5Rl2K}Q*)NGpUn5%ry6+B|cx4tW&GZlW zsollF9WPc>y}u+22R)Oo3$_^cPU!Pfm)1Ss)azdgHxk z-H0Mf3n53jq~x6M4i060ZOYP;ZH0v_J{Cf{|HT9?+AnQn=j1@o))969AqfmiIvL+% z6enXMgPxzSt0ggP-dW{sw$j0)Dl0LwXs6=W>z&LnKH-#!3mQfI_>r;S@;bjUER2vm z9^)Eo2%Wn%%heje_=&0eCshypZp6wrp_KdZF_~;Jd*UkgeLO91#5+C32w9BEp~vdM zE{Y6ntr{E4P?fooa;tvfz;M_$mp?aEXsQ22M*Ej>ftEE&D)Z%44UImY{9jt$lsB@T zs*z_ee-lf8Q^8Bq9_6hNLP%?NhOvW+6=Uj1P9a;rJ9LdXVs3laV!5`9mV5SHG=5&M z1!{8gXU-2Ml?mk*lAUGb5N#R71JcGYg2x09RX?ZIG12G~kal`J7aMUPFZfo#A{miN`GS_;fkwwJlF-(~u3^ick(%&my0L%hu5+L2ye+UKTxvs2=T5Ot2Ysm@= zi@5XSz0G@cyrm;z;YVfF-xG`96%~0~w%HJG>Yjc_PvKN!V1}SfOw5&W2TFD);_sKg z2AL?we{d7DFFb$BmpkYsz`qlt9DmQs8tFSZRTXAGAw(S);N&zxv}Zxhf0*ac5c%RR z-UEDYr4gbT1~Cr?4%RfTnY}o)8GCCh%!aLjWd<-i%rjI7@bJLp35Kbe&s|%+piKXJ za7snB&=wgext!moYiVT2euzp_Mh|q57R0!bVmT*AM<6}OlJLIiozu&6#p1O?Ixj2CH^|3zF1685N zJHwY>X9!S9D7niXx47gHLPjD#s^y|D+VO;A(kAd_H|q znCW5-cl<<~r3}+G(@p|oN?NOPH#q{k$oInaUxU^(MD|2JsCggE=w{(qaDe0I830lx zCG5bm0LvE!hDil#R6e+P>e?VkbM+1v!CU(oTcHP|j@su+he zq)F}3@W*4XMYvT9+D`1>sT^KfDyCstwXt7yNsas#6HSn>rls2b8?pFs={LfB{@}p# z1kXJu%POEgP?V^}86Ruu0^4H_}-FF`gtM8Te^FYazG>l7e>h^YB z0d!|kAEdew!#<-CtCpM##&%Acgg=5t;T9GwoLBU))sK} zU7>aYd=kj9%YopaNb~D)ryP1*j3)e{a94ne1;hyO-Vt*FGYmA5ES!KaRuit^F@rs- zr{}I`M+Y6YC=QO&$MzoV8?0=;65qQ0u!dQv zwjrqLgW@mkTA=ocj18Hk|Jgk*%XvzyPw24hGS#l&clc|gFRu2qXf;zgu=cXjB6nNc zUGMVpNiiqQmqM1jX!>Jf%#Ei$@0J(yN&{^)xXgV`<3l6V zKwgF=7Zq^NqE{@$X&*YFO7Le3@;<$sn9ucQMMsJcS6@;lB*a=+!+vu?BbTEK44w!# z*DcZnKab?#n?uMF+8;{%Z@C{zYq`D*+qDxDK`lpr!Lhh4ASnqmSpx=sN5C);@dO|OoXbQyU)y6dhLmGRsG9Lfq zVL6TVi@Fis4vvDQ;k53AeUXGcE~p_}Rd+*5QU`Bu)>K0!{cEHW4TnFCeo2`QAQttB zIB~A)UoO(owLI)DVE$b187(eQY_r5~k<$65yzF`D_jUdUni@6-nAla*35=;-wBu5Q zC76NSJ)f#T!)1d{kD6u-sI7G>yVn2loh8PIU0gZ0u4Q#3jaOO#9lsPsjJ(+}kE(Q4 zWW!}F3dwYB6S%?%9pQIQW8MFq!9x<0> z_{HAD6e9W@u*+O;HPsn?`Zg;b4z;u6+`}=Sb!KOzRIehotJs&1+iHiiA-+N98POcQ*`hbN+m|MYY zk8*A9PodpXy5#0|^=cY(Jh}ZR(#2LSRm{4Qf^cE0LzfTNYM93n_dY#E;<9t!$6r(u zfZT0*u`>~AZaRTvR%H-MAy+<2a;c^emg~s>$R6*2#9Zw)&Lkj>E?O!&`#t$h>N~XB z5zXJs4bNZeI+4*#Uw4%k`2O7~fS;RtyzeP-8XxuZ=Up?`W)lZcfh-(6Hq#Ujh!T`o zwgZGZr!rY0W?be&j$T@Z8~VWQMlW>$proWE=pxLj z>EiVq*kEIh9`A#B{|6-U_MJNct-&zV#(Pxz$t64@qo>7PO1jw^)zs7niVbUz{eDrx z;*!<}d9r*eCGP6|ZI}PFwlj2PrA0lKYEUP4z!Q(;Dh!z*4I-^jRuKdoXmPMkLPQF8 zuwC}5FIPq zGyUNrN*7sO_Pl^!8(a3cg(Fvt5N5&)#vE@lAsN@yaOyy~&8-^5& z4=_WzyUnM`&LVu|EuWHnul0_@H?br?JLAIF3zvP0?I6cs>oV|tbhK72`)TFMWelp= za~g)ZAwFNd@YDjj(-j#$qF;fBhPE<3BG6@ATVN;Tcw1VkcKi0u!2zIFu#yPW0Bf6E zF0QU@aQHpwxweH;7{*s%e`sqz1^PCC^ax9I-mICpjAK!IvD?AkybhQC@q^n~E2Vjl zpmg=tyzr2aw`F-jCi!Dr>pC?}2AN_=tx-91m~#Gy6f&P|?w$qBhU+Y~^NTOC#68|A zwEV2Z6{DEDgp8aFJ`<*~#K$ocMaJ@WMrJ8AIXD`b8}fOq?qvuRwiaXkiamfXfPyBZap zY8&s!viSaf(SO>vSeO-p1{iiG(9*-84TwZ}ZGt*%P0&0%qD_eBqY3{bXH!)0KD7~( zCix^@F@0MnP?F|$N`r9DMlV5zeT48|^ z^CP7Xb3LECB%>4)e{CxKq#F@Ke!=&d9xx*u9NvJNBRFAzt^kSLIr#Bm{q%XupPrau z3;)t_otX8VpUB1ilg!FM{$KXpJn9F;u+RHnWwZx)cy9m)*<2e~q0rNHcEWa*`*XL6 zQLzP8$;O2*QiRq8Fj!FnAxb7wCW;}4Gb7_Cot2}bPlU4-bA6Qf zjqq8)(%0QN7a~pb+H{zT;|QV2FT08Iy$0kVAe9(5IusRp-c~ zlP}uZ)@;h|<36d$&M;?!#jae6SFef)-m_h6Q_&*EMC!E2hXO;Ts7Rb!cwqWR)K_x+ zel?Z5@nqLGs&_pb*dmRfx7NH0AEsnAKG?y2GmL1 zxpcNMI!2H!Q~P@~W;SH*)q${iu=MSb<;haF%IEQZbALtI$+lVfhYub&nweFC$tm#i z(I%uAULy?hTo;o1Gcsz|E2gK{Sc5h#>2Yx3_c5=>sVV2>N4@391pZj{v zZZF@ym5||{Z2vNi`n(kWw8fs3sr{v2vAlfG%`ENMe}0)D*j7zV!JGhO0S#afoRmaV z7XhqL7))}$JG8yLHCR2D`!TBni272}#MO@zPd4Rgc z`#0$v8YpQPX96t{jtlTYpa%fS#_KX*P|%y}(^2pA-O>ov)CpF%dsv-a*q9dcwBYTp z9mJ4hKmJq2v)8-VknLCh7P&AWtnsRWF!csBT|iz#^Ur|Z0rVE&kbcdkK>t7>@a7YH z_6SPn%uZ6jNZ+syIX-Q{pf`Q5cN^hZ_8O1QNLZ7T^>5WdxM2r;<3P&+rUr;J0A_$a zd2NX*_IHe6>tncKqbkkLPph|X?2V<|iMdPP7j0mP`f9;`DaJ5xbqG8AnKM6;nNoo#J z3yJ0hb?@f--R%PbZEcCXV$Y?zgn&Cs{R87QTR8ezvHY?*?MIs*fVn+(9qWWZUvSVg@vYN+pMsi*O(_(?jH5B`pv6gT%Z2=6LJO+#hvd0C6=M732ul_z#p72srQ@yQe7utIG6cL zD&oIiTLyd>+CW7lB68bVQu@z#hH%~UQs(mMDD(3D_~7JKM=W*#+p^_Gz2xSV=+9rd z9S7O|_xSK_fd&Rn5Qqk#8v4(NMMNSMN35A(>+6f6pqTOT9v)e|9wDV1IW06E+52ET zNAqv78>T!L8#r3SVoK=lfoA8wG4&o6b^YftaIWOEBWfwXYpNqWE8jQSIh5JiyNBg^ zIOd7^2MOuU_52D}6w8_$^8pU>ej(w!w%F0_p;=Dhdo7$cn5Ti4(KvH&6zs{#*8)p> zSfzLj)Opy4QVR43C#Sn}{^+IRm`E=_AEq2K8}Dk=s#U<0Vd?9KVhcWMvH+OAJf60%F z=COjgj!rUkd;=H)0s<@l`I^-dwj5E*g&7B9`B&Tt^bJzR#+vFjJZr1BHCzqC8`?J} zE#dpLx#8=?YzarDl_VgO48+`sNDoaXd$f{_s5b(@OCV4g7<_?%4xVt)j~~O9zHUhl zxP2B+YeLWefbAy~*08W<3j^~~3rMT}5+@~78{+R-KaYvQpeam2}g!eqxYXg+9bRMRJ)_>$I`p9_@;~nzk z+mGAyn}f9U-8nf)-8#h?b2iJ|!L#dEpK6A>o^+Y5qU=7zkH@>*vMo>>MqYh7_=v&M zi``L&{YRe2okRkgMPq@n`P8}Td!y6Fv(qCtdpoa6b^)pT7uV#Wm&@S&8tLn)mgH4i z>#B6>hI!K0O?!{-!vblP!CS85Jer;N@w}WtMY0vNTIBbmg|uqpXBCLl=zr=?i~x}j zR1UBc04fv+29F9~{vGA6UC9~)`W!64g*8B|(hNYX0S-}J9ks2D!1yDK%LFVi1i5|n zLhc~%&6}-@S8R*nGzFEdOkl}Fc6KAtab6)93&V>PSfS{2<8%j(lpcW@pX;@VmK&a&l5rBWKYbvmMgL>|{%h`GB@dO9#Vm z>+LNqFOPht&}iL#*|Zm^B1bNr1}A$xj9^g-)lO-fh{AbqGPXQda1F;RD7%4t2E&Uj zVDmo_JsXUM8+`Bxcz6+HP#w8qLS08g7e|Mtr{i=x!8&suivj)vdr?Vn z*PpTE0#(YZa!2t0l+XeuVaGAhv$?bF8o(~mlJ1M=I zT`Nb^JAdwT$HUJ0SX%y&G*=GABS<%3SBCFf{YAnv;K|zoBS%LJ3W`9mgI>$gR7Hf^ z1l%%KZ{2=$ckh0op|STRDGBC@^IA3x*k7~fS$ID)nazqOO-Zys@Yyp3^!?R5ZCv=g zH1YPAkWq3=6ucj(<71$;Mp#uAE5@3`N-hk6&2>JRAYJaE9J*`QqGmsU^UoVjH5s6K z9o>J#2Q($_TQU&l;hH76P<0ONyvLJ{?pWeH^Z)wj&9-zJh>?4&e_jhWJOR<@f-Ynn zfTX-n_U&ou^VhHn++6xZGDzSM=j|%E?1@k$m!ma;o+GEh z5DRD~;(xJByZ(+p+AZDW163$n$sy?)k^v03I#`#&xP(6;+_B?yM}U17c=duWxi9#y zkLsia0io!rxQ05+bFbZ?&#G4Z2p^(Va~cWBeQoWqD6U&FeBpm9mf@X&sw4aOE)D0V z$wRM)4{tquX!r2pwj~pPm@#77Fjr{w@Tl}vJA}&F`4KX~mmhq*Ni(z&0bm2vWICS8w$x$2F%qaeY>8-h$rFJc2{uUDA}OHZT^8>T23cfp#oCH`kI@}*>uQ+36WaHFXz4v%FF0O%sf(atfrar7)o|)nLoijH% z8RPl}Yib0%h2pDVo7i`5H5nMnY~RXKD}MPB{+y%xKpu!%>+u^C@(l&y$i=45&F53F zd@m0VIHlW;`*;p%JMQ((pMnqy-=Xc=5iuSX4>!6|1+l>2y9i6?mmOpFb zACTIlkLi*$=IHIc!y`umwlUv>{1!(r>8R$4DPl;`Lm19xDkJuks*7CD7VdrI3rB_b0X(W=L3ZKlL$zRAk?3Y&%_p&3tsf)m$Ej6hY1~{^{Hy|@cJGPUOg2t;0 z5tEA9q+I!AVY$4h=si$92?+^LIhMN#(G`M4l8^;(bU@kRZ+nZ&sA+2?oi5>NSapLF zuPY%FcS7Ntp39_L;uhTk0Sf#LApuf>C9?0!IqKeVC#vP-H0^)PE9NaHg0yf7t2m&m z0TKcT7sRUK!SfcSW8>jLLjMyOn&5SKw2hXTa6R40HA9!8vEadwl(FWD(zTono{c#c zpOa{?y!^}gV3+UB8LO36(hb+tz}VB;*Y6@QxGZl}e9?>CKV-H1PY>VVvB2X+jDrav zGeik!2LuSdlA?5!*~vOkDDY=RI~jmO;_7P8U!}bQ0nG9Q_D&O?#|?~&sYsR!7B|&c zyd@*Cx@US_Lhxxlm-2l!Wx?Np$s}9i4ki*#HUT``lSS`2sQ*%m;(!AHLz)mo9T26# zR#0SRWerGjbakIK2%@X~l?zn-jDlCKQ2tpdw2fk}i?O|KJZ(k{A1lpbPZyAe4j0d==S3 z-8?`P1C0?1)NfF_f@~W6NwT`TBzd8TQXmKlWs0)#`1l;et?yM~YaA;P4m3a4j)^e# zBC!q+4?zavma#x_8WSmG+;M1`AOCk#_3pJyYrD}}!JF{Z_Q(sNaVMF4{#R#x|7kf$ ztSu~V2nwRTP+*D-HVO{^sWoeNz~Js`2MuE@yzK3M;KKu%44PA^E8q@s^X5(Xf8aC! z`{bnNyosmPkAM8qIoOH-roAk{!Oh*CYsmhaDHhR*)Kczi&tqU=8J-;0&^7p7^R(r4 zywI1Y@_$Hji~ecSW5PX?As0YC7=UUJ1WXMLe<_OOi9D9UozjAn3>P?3pxy@AAO*M( z0C5^*$*l6A0-!CY9T3Ht;AD1hyF!jh6Swm7>Q zvFIj>X3z`;*Fmcn`jWpzDD(b1dwW-La2`=FBlggqvy~-p_s`FLpOvrIzkZOcE@G`K z2tQ7jgZTglg(sV03;P-@eGcIj&&ed7zk$fUMpn z<>%%>vV*^m9&Tm@4g|Wg&ir1?3e0Xp#L1_+A~hRYiAouV9@^;O;Ko}whQ0r~_5+k<#Csp3V1ocyX$A!co7bPw@WZ&m2L!jjei2-~+9qvR zLQ%!cL?-~hF)*O0<~0x3(D}EpU|E;x-SX7qo_#A7V@KmqdF2_jjS6PIFMDbaXqJF& z0wyS-r#qb>Ca2CZs6)3jjn&7iU$~G z?1G`_2iN&OXNU99lq|GFr4_)ttjVS-BQBIW><7M!^K?71rhI`X;tBk{;BF49{}$S( ztRa6^z5_odAQOEXK*alXQ4%n1rm?>Nc+2*s$xNlopS6+sX1DQ&h8{-$@3(Fm`U!zs%_~=1;##6 zP^`m_=C(FPUGVvk^%)-C7=H zhLH}{Wd~avtt-5P#mlR?4qrq*H7gZPyyv*67cQagsma@HILK`+7XMsDDPw*!yR`W@ zU^gG*N1LKksZv;7TK$j9RPN1aoc8hD@Z4MoB#tYjtf0+ilaXlx(D)0;`{aovY$}!U z(EIA#e0`h2a!wX^x&)A&{PJ@ACe{rsy66`gz@h`|hn^x;DquN9tn3 zk3y6}ekH6qzm#}VK|XeonxEkDnul}e84`9Or0#u44s2m`3vGHSAVtPf;Y=X;^ezNS z+`Ymi6Gh%6M_SlY7%}o?B{w}idiPY_VQ#S0mUILfoPcY8MFrwJMO6g_HzXtiz=0BW z@1ZR3o`;&T!8htc>e7mUzz4b<;deG59I+(qJDeH|VRW2`p&>#MS$_@;BQMx~FRVzY zO(z3N2HXQshD69H+BCigsXWZv@L>~>s_McPlc^+*KZA1LbhxhK{roJr>LnjEA7rjB z>_Twkn*`8GW}J{MQU!GM1(dRwAMf+DcF|uh(9kO|egNJj_hHjud&aM)MtX^O?zKtI zU@aqiI+b#yFj#WAsZToi(Rq2OaGNcPZ|GIs&^MfDR|<_6+uhH5O~#XkWRznB`1;d2 zaExqEwbn37$%^A zhkq{TZpYxam?MvqhCOZ2E5c7HNfSj$R%y$IjK<@2KIwV`h2N775h03=(~D7jG05t9SQ+!4u6OCqB9?v(BpAg;!<9Y+J}k6$&!4Pb}Kxn4}VYwo9?`@sB@(dE5e1 z$qfUAAWZ37aaw9pIrf9^g^8FtupbL?a>o7Oy9qkkTh4Yk#ZgyV1MP>?R(s@<^6Ruh zHhg0%ge^=+>>;syn%uDmivco9U-N!3&uZBF8n2d6njd^!i^fX~7C3I~ww7E@xKR`z zkN5DRUgTrpg9Y3?zL$PA*cybXaPjJ=ET>--GBjj1nW-WxkE&AJdn(q{B?9~`t!jde zkece&S~{oV#aGi_hy=Y07)#e!<9_!!yB&W~k=wWHjXEv)Lf}d%udM%%{`5Jj!|#2( zGE-IdjGqi=_8bcUKQ`BI0>E{a+~!5J7>{}yy~@{iUY!zdDhL*H|LOHjGiw4X1f zu%bH)=T`MHmH0s1EHGJJU46B#6!}Vi-^{J17hE~=H2z@oY>L6pNz%vR#oVsr{h6l$ z>(XO7!YZZSww2&NG0}3e^8k;^?;JO8D!g}-OOb!mU?2)wF?O=uj8}fn@F@sI)9*Zr zp1Ks!vd&LdPf*Lz?eySwd9)1gNF~}r`(8#hT8 zTn#lJyhaZxuA^JGN{qcww|NiGeuQKl9`7GEKad&evzl~&!A;tsxpt;qe*3`1OxU3&;2(|d8N*o<0+@+hDj8+h)J2qPJLQk+W}=djq2pJ zg(l@X{`!poOn1i?UrJ4enh2=X&@T1>P}M9h-In|E7ZM%N0vUENJ<^tu5_T};zM@D~ z<9GN(XO{`HT>8zc4?ut$NwRe14NR7&d=thRnUMKuFu#DHJR`R_1z8;?ku{+^EYU}& zXnj=|(V%4seY+N=rd=1NNcrr!WRi@(Dr2FxUj zx(Q(>j;JIrGR4RsGscQ?$oqkAMna9>OGrPII-^QRZ7-h<4h(cqLC2_20!$cxmYP&1 z7C(1zlITGAOS4OTPB3KAO!MwYCqJf@s4<_*iZKm7?#|+6<2thGX{aTYJzYpJF!kU3 zsy!GVux^jKIw*SpW+BTlo%CmGvh>F*%O80Ium5z4(^icx+#Iuy^Q2xz@o(F?V$zpbTG8CCZj@XW<@40Ep ztr$AsBMG1_%!a^G!Y33dGI515a&Acjvo~Vo{l|}o{ul8(I!)<+9UP4LS?lPKe9_!U zPTDy+2^b|MBFdu*qlKmFPn{ecm#wiaP(dV4N36T@oZuUNRNX`|BeY`)yNL%h_9O%= zF58AZf%*0czl9Y4lHBO4jP2MbS2{76Wj=?zpj?Z4w~SFKyxj4WB=PH2?nT_Tedwh? zB;;o*s3CRZM!}$WN2m-2p9S;~)jKJT-33^=jlTy<2c>_b&-VCqPgCY#W&RwFk5I~O zF!y{vT5_vq`TSrPl=>HcuLTJ+3iO4Dkym`!#SL_v@S7~r)&$?Q(1zv2`9IAx+tc%Z zu7yjv{NxPuDNn@x=z9Ic#HkTazybqc3Ci__*G%H#$KYTAwLWAn&?m1dzVrHP4w_E^ zC0c1{=B+xoL{DxH2}v;=tn-e43iMb^)iS_gmHJp+t!G(58*}Rh5e~RV3N@Cv8CrRi zOYZsPBQu2)kGUR{e0cpjCY=gFTu3(>|Arwy=rz>&1!e!o)?Ws6wQgPG@U{h{L`eaW zZloIl1*98k>F#cokVZgSK)OM?LsA-~yQI4t{u9r+@AsVheLn6FTYhV;>zXmhxB$<+({76j3tr1>o*zqjaad_&>e!Mk;dZS7c#S+$M-nm2TiYHkE1*Jf85D@k zF$3JpF@}JZ=!IXWF#!zMxNV^UXg*J{3H>Y`#u! zM+p-u^6>|o&t>P541J^i?8`tg_5xW$|ASCh8_~kc0w^{>%EcWQpy6+!Bx|q9G9!EW z^V&V03k5d!eJNYBhGiL$RkGBGCD6EdxIdJTfkX)trzDbm@)4VFSaf8BFM`Pcbo~;+ zk835hy;hqi5xSZsDKvpue>t2fOmNj1VE!#vN+Wmg99Heu=6zLGT1SIP zYRhRny^}sc)QjUoEb*YINX#>es>c@fyT7@A`6AzC)YeWV4izyqGs}>SuQC~-bEh7$ z6S@I&2tEpfR)2b!hWR|vX9tr;W)LWpK{b^mdCXr3d<%f>v~0$yv2601m=q)>gO9jc z`d)FH7*&&Zd{0;pHk?Nge*N0;E1Hxc#7B6XnudRbB?4OJ8yf`%o1)$dBz%$B+7@|i z+=V6i+dbrD1ltPWWK9K8on|05xe`%HynV<>hwncJdB-qbm4grIA*06&77^kloeZcs zFWpcrX3jQq3V0oeXI%F*JtnH0WE_3XB;NGx1ZXJl>aj&lQAc|0hInwhraS^&ymmb? zJ_q}8Wlen7>NQJ5oWh^LUk+3|`9ofz+~f@+xG)?E%D_K6dJNA#KC6F=$!s+Zes-_( zE4SGz>QIq!m$`M6{RFkafvKsWro!<0WPn(p2@ekodmqoh-yLlXjnGvvgXo^IR*1_k6LSt_O z*UHeq_h74XIUgZ0u#l^ehjz>gdsuXM;W;rY8i28(NOiT2Wl&v=gU$)a&lp=+^p1EB z{tNJMzlFbk<>#KR(QJ0_7@hmxPaf~u24g@owW3@xDS1~v6>(ErKVpNLvNGwbyaVA&3Q9Mh|xLO!9Glv zosZ*{lDa5{d1#8oj}ag&bF=-rUK!aZ=ebVwn6euoEM@XS;e(j0lplQ$-`pa2EppnN zn$8Fehd%y25tbg{rVj1bbdg?X>f3Nji=n^Qq4}XtJe24(`eAF(Cj{3Ns#JZ^*zdL#F_>X$88&xxbeCA7SUK=d6r+&M) z0Uh%2#EuZuIn8jjn+3R;owwX&n(nu!X=CZ|U|tP6_Z1H>4@;Et`yN=!;^757Dnp)G4Oz-@8 zX_6sf)w^u>@nN`v6wk>TcC+fdbNhQS-e}EA|F9;V84}`f0jt&16 z7z5uwH?LWK())&>*3rocoWfrV3omFP$g;j7wzsnSsGpve#!v2qbD|?8w`k% z{w3>d^$9zJVF9uqows^&yT#bFn!h4sC|!^N2UVcn9uoZvPON-;}yrwy0KfgZ=DW~!KJWGL%210zD}c9yPP zMmi~^QoN@QX2e(9>%H3ysszr9?5P?f0@?fjdx*D^97Rq*Oc#vtKqm`Ya=X7H{Fk5R zQqt!>fPzHqmGUT#D- $(T2m6w(6l?Q4$S!%JzgXCDsSN%LKL;8}JpnN$X9B2%S zI+e1XfGla)tEtVr=hBsVitWC9G9LEAW% zCFz8#AA$+=?5^1R(s(cFRE&%$>2lL)zdffz5B^=^-9`EsVUKx3W`O&IM)j%QRR+E| zmMhQV={2_#T-6)bS*L^k2g|+jEAI`|D0cetw(QDU<^68=CXVgSJ+R=u*tt`GJrxf% z+V)N59HZ&FGFMh!(U6nFqxj!1B#vD2TQs-RUQayNZZy$jKihx3kfOOe8Cv$Z_zRwq zrz%aLqz#2FXkT5>F2JDV7nEYmyn8!4ebLX$WF8wMm@EwmxKuWsot_$XGziIfrU#~z z(1bZq?1z0Z9P-s#Z5lTMv|-th6J-$ z>K`gu)SmvXJ)XXY?|xZ&{hWutjM^6a-hUovKf_)|9{nzCD3PziqM#82Oh$;iqW;hF za?=QNF|*BgBgc0)t?V%A!KWagQfw;tR03V_Z0}05drb^9*8ppfUiI~Tc*Xh>h! zpm1IWk!#M@G4@k~F?aAa5td?SwVw<^0WvExwb$*N_CKn)sOV(=b!H^J2v3XO8aCi{#smcW5B?Qa_$o- zH8oD2*St0z70L}GcMuC-%kjK(84?{s<8nMTGVQjk06n8RzLhiMXB!halGKx(pNG)a z{rOB-Gxy%&Tf~;DOF=~{=u_Rl4WP&4pYesD9Oz)f+sSO6Rn_AQ{R0Eqj^SND&nHb% zfZ;gHSlrFUpnJ6LbsvyNLHF}6;_hWtpvypLmDcC&z|p%JdY2sMsyG+jMILnyo_N0|%&^wX zdDG*6q)bwRkl6BLqMq34v#W0N{h=*1E1gqvMWI(^Fgy40-qk`mT;w0k+HXD}4s%I8 z<=M+7&}-}S;P4~zg6iLIwhShSE+;!$;7S0?LVYv?H?RV&S3x2Yj@QqhvJar|5ohsW z!S0oDTk4$ODR-C~hX%DKATp%L$F%A&dDUu3Cz~kRQp(Ym5NBh?*9qrYOJ@TeOV8H) zeB(r8{RukZ90D4vzqljLHvwm7&h47}-sf*SLn%~WNb1u0K9fm3*P@w=h0B;!E*vX%Uh)ojE9bhY4JKJ+!G3aSx~mxPgnF`szLV)@+-IKoW4A`JWo#MN>iMT zCg0x>E|u} z1d%*V{qdn-X6Xp-k_84xw>5)US@Wr~37rm%+Ej#XfDux`KAM#U65jVwc%KPPDr6X= zXRd`sJPmDnrk+Nmkd@H*dZg@A!<aYz2w&0)}!EsM6ud#HrEMZ=Dyj*FYZ`WDMdsKTJ0U z1MP)S*fHBvp04OZA5A5Uar@&x5CM~62$8_R2rR1k!|#toUr;l5ufyEzbvMO_M@~3N z(!M^H?-K`JoBdL&CJ7`^49;dI4Snq1e3)BMAj}gR_KR@j7MGQ>H0qkLLabD%EQn10 zz%DGxC{`KzlJ%s;4$B9{h5}Kb>MnoSiD1qYWXWV{P9n2Z?I|X`M#Q#W472 z)6e`-Zr~eMFSNR?Mk&}APcr;M9C74Z42o;Ymd~n4LuC`gMw^gKMCU0kd>hsNI6Wv| zl1pvl!#`Q9efz!{e<=IxQ5r)T7oXRsd8}jxaplnO#vPlhFNg`oZn{+@-cDO9t6k6l z6bd0QGca&S;Y$MTR+GDQXj+FA)5Ymx6>BT~_u0yaqp{!e z-x>otXS10kuz$g{Kn_3yI#{=WeAK7(%a`m$-tq$}A52N-e)k~}t>sybZFNaVHO zz}8$#7ETKr87#?2m7f@WLZcSF+r#y?mpgoa%s?-WZA7zXG&Ca3(6G;L3x2y-4-Dq+ zBjUVl`Ti+zR2u$62=U7dtPhQjzQf)H$8gYdxvIXA}dsstLElgGE_sJn#7(ruR95j-5u}1Xl-dgOek*7 z;Jq~2n9xuw@GA$qR*;s5itq9wMs#RkDi7!km;t1xr`<$EfJbs9x+c0%DiCmwKE@;~$XB$tN7?tgVWu}Bz?YQ%uh06W zT^Dpm3HjV>A|e#v*aK#Nz3B2)^o?A2>i6&M6V=+=)5%Y%i^wI#T`mt(4H6|_g7A$} z&R;Pga`qo`0{u*Y&x1j*p*XKsmf_3-%_I!Suc$JNOu@Q#ZH1B0ar*rhamg+hy<1pXG#3 z$L07*qk%n8NMtZkY^~l-uRm0r{>E`q!oiMB8ga+bCI$|7A8<7O_i)4FWko|%SDIK9 zCe6E>l^}RUh<87!DlpYl#j|JwvGNGGSQ1W7Dp{A~$ zg58Sr)agEu>dL-Yz40zeSx{Vj1xNf5B>?oV`dx_4rR-_#N`Dop+D-l9trW7Y~%3lHnX8ypH=6dopUILZB0F~6Z%suWvMTi6fPq% z+dq5~Q1tDec+F?{e@DYj-fDDw;K+G>bqpS~IVB|}zztPZ1j$$_hjLM>O>?t|$Ox8- z$_VqZFcvL=j+OpTW5u1U7Ift$Phw-2T#uC3s0$iGkuYhqIjvJk8N>ed>M3uI(3|Zb z>}%*!!_Vbq`-o1A%uAaAPnRQ3##2Y2t$ttF95`N}JcRa{hu$baj=R&&J zSN>w#?ef{gv-Nkb?KH#2>78s+r}^&0-TKPj+x%~RLVD6bW5bMY_LA6e!G!{?>~f$aMa<-rDaoqF-ekkox>pzLoA~yk z^PgsOOauYf;T6{=Ny}To@*#K;7Qq~vE4t5&Scg_S+iD_%wC`^gONDLa?FXcIz8CtI zYTU6M>Th>BMf$Mu{m1M^5AdV8Q6L8XDglqPe3~rs(AxWpOYJOqB22Np{q>#%T8&bw z^(NGTX~&e6^X;4v!U6~T{A$ZvvEP{NjL)K9;^?#`zuH_Kz>kSxriQ&YuW5+RkG>Kp zNEyUu^M9w2>Z>(Vr>{Uyyq+govAozS$i5RI%H+l(L#UsqU(9WJS>3ZwaIAc4d{x=~ zLuq5XUXpP>4i(!<&tFt+kl3vM&>`yiL(h9*RFD0j?gyIr6_f(%6#(DFe(kJonGY^0 z5kd{g7X0ibBqSgw_j+}yn{<67%6weDOb-b)snDvj(y1kZXNZ**nU0P&G*sQ&n_ZDK z9N8%WK1XxI--OFFe_uiHV-dH^ahYB1tdOhLl3}-gH=YDg zV$252B1i6yUCfUfDF=H9`@1MK%ynTY!EA}_C;#h@eC%scn$aR^h z(m1eaHhW8#mXB#wtzYfFZ!vQ3I(UXDqiYJ0%cD@`jm8f(G?LCE;a@g)o_?a9I{nE; zB`$Pf!$904?bqp&dN3=D)-0VQPX)7}qm3~gW8*3iZ3d=~mKlKnT|~$F+HCzH7QN!e z#DnFh;FU*1OMSGJS5oFf3FQ;bcxAZVi@4}n&0)P73(cT-{M6Tie zx{9Ro+sm$rt}i03w|VAQZ0v~0_j=3)K8o_KFO4Ee>nIwSOS^z~>!PxW=%5#CUO9`P{T(3C-G28j0f;2Xxl;Z(u2 zvO2dfLrwZvS>Y*(lCBl+Q)k>({msUq#-$uzLTTS((Ab{!Gd~S0;kcleum%h?JVu`%U9 zjda%R=S-e)-@)N^kf-1x=ncU1TSsR&&QwpqY3F^Or(k%2g^Q?vO_j>fkaxDN9VVQk za-y3&hC?Lesy}{t6GK!lg(maIR@)SR{7{ax*F|uD^o|WBa;@-Bi)DEG(?#GpocR<3ZStjSf3xvq%9Maf?L(srWl z%48Z*jgPL;77^v`C>NXU`Q3s=`oy?hEHmOrz4L`kSvIkiAJ?(vyE3z94qqO>Fm5a9 zoT+!WKf8=t;z6&lH{Hsz3$rcA7oRC>7JJh}7OF4jS?-EmqUBn#+dSPUC&=o7X2ePA zeyo(1zod@CTboj0=ds&6 z&{#N`o>cS~J`Z;&2_X#opPg+*MgsOBWMP3__4_?4~kUZRvl<@$la@wXUf`j7$N-YpK6Me~e;D}sux_>z>)HG$34 zG55Z=X2d>`oV{+(>eLoJGMTzDZqb?rvfJgMmp2#MeNLg}6?PJ_UF%O+t1pRLr$*Q$X?q6V`o)$P&kLn5AYVfzwuxG|ql?J7>*+ z*gV*d#;(}6EE-B3neC?qsRSCbR;T~On)}&2cHZ(Yym+=)8ib9T;9zdEQYQ7jLjCjB!0HCU`fzA#TpSN%QUOfj=ouQFYX#e<2FM{V0 zqTuRuLka#x90Gfss6&j+Y!9~S6{)IKRk@0a*5bb*V$t_JWRs7$`ci+5df6AHDHLA>WEu z!g3Wzz{~W5(h=gjY5wXxDZv;|)|x1zYSCwIk`umTSBDEsW=ev5PVsCiAr!VJK?TjIdGp&D73cK4|X zIqewje)F-U=B31hFEtnzZO6DcEv}++LpbYsCC&t@*{2E5p8t5)uKD3<$ zz44?EpPk=XLcjO^{VY`B(7AdGXqiycX1`g%c4dM|D2$qd0s}SN4i&)jN!`HK%^Aqm zZf*vOm^2j~tvQ>`)!WT=q;;fv+U5EDEri7yhruL|6h ziUmKh)~GJk6_fU4DGhm66}j3x8*cnw8U*k7BX%c!O=Ji!)1d~G&X13}-f~=+jfavJ zav9vSaGtrGSeEp#NA2RgZX7;iaFI{m50DZvZLlN`1}Ps{wy?Jk_Vc5JB}5}5pv^aL zqSVCz1N1}%298oOjQ4sOs(Myh500>M6tdx7mYtle>9kq%U2|^+u~{2*p_$K2!%{Ca zK>Hjar!o|7rf%wqQxtDKaCxvE+zk)3F~G$2oJvii%*GOd9i z0s@dbmbbS(uyt5J`}TLj_4gXB3QbmjvTRwrtjoDN4@al>s?})o<#8YL)yloK-kO{+ zkT_){LAbm7Rd8gLSV+|HY@Aoy@vPLXxmJkV8}H>h@iZ6K)in8Duf<1{@>b1MnStgn zP_?g+Gt5IbJD>rh)ZOkuJ0Z`c4B`IK(Py}b?cFhqq?eoJV7pi_T8$<9h*)v=_`tq|SufI*HiC0y(q}yD62Mk@^ljW&kriVqVQUa|qv~PL_2J4(DKa*fR zCo-Z`NO&ZkPqWga{@3rYT6U-^^mGPRHm4F|sS0xBV2gu|4WLKW7cU^rQRU?UblKV6 zB{iId!E65;Car{DlGG*_if&IEmS7r%lGh zpcp}AONfReB=&8g8^_8m+HJf)?UqTKM)c`Togk*x?WDjk18qZrsq=PhWjg(L@sd;9 zwy}^i*JIJ~emyh;))Ctpxyq3Q>>T>DE|%`K!b^fJSNpR&NfW&J2gT-MHK}NK{Ze`( zs$x^b*Fs74wiKcDt<9ldy_ye4$78s8Be#jc$>?OK2^C;BV0FEI5t`3bMJb<6P^m`t zn8n%gtJzfSVLLg_LhDmHO${@XiO`rVQ;TgG3P=9Bu0j&N`suMs-Am^uVt|Wu?Jgii z(dO{jW%F>vbc;%ao5SYABLeO<;O`9{%4%xThl>0~S_7XEA3?d=?8czYwYfD|_Bu+I zt+PU1vx@Gdd?MK(9EA?;bi+c*sv6{cgKcQ6S%Vl8-K~1~YNA3UiCPDsFz*vatVhc~=NnP?x{O=#^DezyS#C#a1~} z;^s4+#*#QW0m@mLA*Hl2rE0Eab(p86stR?3fuv;lyGJaF?YjQ0tx!`f&CUXFM1}ec zO<6_5t#h>T6Ro}L+7n)ZTW{nrx_`bwyZh1-(!jD5h5MNt3IBnf7xr$9(J@Ew=g z!J9a#5%+agsPy1NqNuU4&bD2@QSG9zD_v2a8#!JI#P&g2=;5hND6o1~GB*Vkh8zmL z3If}^NH~{HK$LPeQHHiRjhEVB)`*>iXtoSaZ#=!=7p1vzC6Oj>kED};-#sM z)8%q6^K%lzg_Bu{?fu0FtBUP4wok+L7+Q>#vyFFte41^Lu4(J^inmD&cx!U|f-tffEg z0RJ(JN_dYLQ#jH4vooDrKV+N7N8K34I95sp=mrx7KZOaz zG(Ln!x@>NVAAUg^4SZ+#64H8~0^FN;&)+@QBM|vfnPOM!^}D=dP+bZfD@S~f1udM+ z3^V)sDH?74Z~7HpcfOh!y=%e2U?VJj-c+;Z8dsfWN)fBkBZM724T7O6*ZpnCf?gV~ zq}sJ=4t{~7KL8>)_yPrHM~5i5su_S1$j)4oY*xv{KlrW?PyO!tlp3X7qa ziG%oJu2EQPC)Fn zS4nOlt!{4h`an#4&>v{1pW@;n1qD(FY5UU9=Ahsk*IB2qjT?m|vk@|8ih!DfWc zi3s3!-rFCSqW6EB)=$Ue-09bb+F+M-Kzw4GDcB>*&06B>G!M{&d%+V-Qn_7R)ma_a z(l*~x(($m6S-iNuR;ng*_dc+L5Ao55tH=3n8A@fV46f&vh*beP^!NT-L-3S~c)7Ascd3X@tIM~>@7#k0T65pF~ zkK5g<9>XB}8W;2Pt6oGzpX#ty#?UDeSLDcWna~@Bt%)c;2lKT~`i#0gf0#nN#>DJS zN&R>bbOc9mrkvjwP-Q&{n@IRJxw5F>wh?UzQlgH9fIdyv+8Okg zwYD}&eC3n4Zd{%U^LuSdq$Ab4hCxnsv_V<^11&ZNAt>;NjNOT)XMmWhEB6NW8TYqk zS(h_rU8?nPDX-Sn7u3}Lq1gA3u*mq1)%yLPf~IBD=^_!J#vsDv@dn;Bi%eeqquXlu zcn7GUc&w%m5fJ+AgaiXb$-+m5Aae%L(C*h=FzRfKe(UAU;dcB%%J{gW>ntEbbo1ET zMV=}`jgFSuWN+USUGR;ZrVB0L^B1T4)TsEze!gEuMvi|i@)5E(!}P0}=j8ovwt_!8 z=Q&Q2;s_U4lkfgg*D4jwpdB65y;YupCrYoyzRAT@D+CTLqv8bbA)m?)70{ia7T` zk&tit&%!`LNDA=)v?)m1|dXY@20@AzD zWf*`nicxYE-%zR}hf1H1#M>V_pFgs%hkQfHg}J7{%m?)IlM@=vI#*z(-ppjBq=1#% z^jY-9N8A7yg|eA-#Pjk1^16>j^L`yYBb5Rd*ZGP6y8U@$Fqe(ZTo38`@S=Fax4roQ zob4L9izZY^UJkmtulyq(x0h~{&D;!7|GC*0e|R5fw;=coc1Hge9KG;Xd&H}yFaY9= zbhYG%DkHzElT&Ih^53)K6+8xQAndOWWHjCQm%@UvZG8XEt!0I>QoD%AGOy1g9Gr?O zs>KPKIy#|gdWVHN;29c!`{z)LZ>jX#v>m;-8X97ThPB}s!H<=d3zcB_(phGn2QUxV z1}^nUzvcg!Tv)iQNZ#;zh9#ot9hR2n-+ir=aoCr5 z^&da#e}}tC7BHp;%R}D%E+$Bp<@@EK)p@UEUr2jITFQ9*~=BESX?h zXZ=P+u@zJOtezUZSUJ}Pi_u(4tlIf|X(_~nq%6wdH^`6zhSV$iaPg-U)VfAY&muI$ z|DS(XX%;Ct}EPW1n8 zD(w8mz`y|58L(HD;JWt~SavHvWU~hCWUIh;m$V>jRYc0-;3)ql<5fo;o|;cljaL@K z=N-> zQHlTegEKQT!?y(jR0sjjcu$Yy$m$C59*hNdEc^4-AwTE_L$TA%_GPl{#8ITMs5U}W402OWht|Na{V7a*C*K_p*Kl3V0qw~WNgcGsL3Lzi!7022ya;S= zs)+1rtTfpy+>U#zzM;tfF?&Bi1fm0&n`&$CU7c?y@_A_7{Dh7kNh2pGRRIAA)Nu5Z zr>ed6^-U#LYhCc@)IW_c*M}r>55Mj=4}v(WxVhPin=}x7OD1WGT-xXEucHix2=4 z=Jk7>lU^VWFqnQ7B~@cjjoR7S+1s=Jzr2w?YH)#vA{z$T_22<{(*owD1@L!}U+Mpuxt-qm4@f{^84o6BpTtKCb$ znsQiX*0?zVE!k-5u$ETXr%&*W%O36>uHhIH=jY0klVl1Cf+DY5Q=2e8UQSQ1(#S}T z)-~}#kPU^U@Mm196&abe9ZNf-tg2e|OAiAyLTl&+n(hmI110XEfPw-G;4c4PBFoBC z@P>z*&Y%rj5T@&#@u9aIR2@y?Q*_#^>~6;2JVvss=@NaqZ{6L?-{pphyz|(lx8s48 zew7z5Zqm%V5(-G%vYIXu3^wV8$6I8Cgz_j3J|Bw91D!H9q#l)`XQXFuZVqudWRDam zSxo0n*IgQ$PNcIk$`bPR)UXo^2DOrgp^wSYguhJrd`QThIb96iOL_TudOWjeuC62z zD8l6II4`wsJf%TDhU*X(Ou`Zq3xE#h_MZfgvpaP`U>B%SsO=3Si}-kT6_wb0CS0P~ zM#>0=8Oe{|0qlgED{8WCjfBLTWINQKGT-nj^JPuNwej;B#?VY+TI5Bdk=y~N5xU{k z8aor1dOodo*!K?9d-~M0JtHyIQ3N1J?5AmEMcQ;1m&a?D=R;dtN=+?qHvgpZ+Kbnk zV4Y)4C@T{eWnlNHs^_5~$XHBfY7`4?Zug!Av}g}=5a48?Ajt{J?xv{mdT~HT@PT{y zUo4CyzS#-iwg}KI*cvTt8W|}E>h%at5clZBPkj6z<4{QXE9U-kJf50d9f0;d&eb(l zU~VWY^}$Ydc2TjMhB_?@BFq{(&-Xe34evbLX=+Rp1N_b0FVKsPvRRwiYdjkT-~W7F z^K*}{=chqD)=Z^5S$frUUWedSqL4{7JC)e+pZu3isB4RzL)40ywKaogW^3r>?siI8 z;WHopIqZm7YY7-L+zETU^eZbXcf|47oK^c-@P(L1@5zlL_y6;e3@t3Kf!U8L1g@ge z3JOpS3lW&!EfpYwYw)Y<$xU|QRH*de%Z<$AH8oY!F`0ObPDD%V-F_v&Q>%~cXC4sX zDKV13i;RW2IqBytI$VGi8!b=3-jH4Qp5KOf5=8KRDzyOzH8@uLleK|yPuZrf=PxMX0ySM^6X=&Da63oOz8#8$7PkfBGT{_S--tzOC*xGu=sou=C zetKr6g7x^u+i>mcy{NEKlc$0^Sb>_%+9zbTj11Cd#vK|Ipo;Gq#9}!{L$5?mp5y5` zl#r0CEB^#T{32{1u%PuG1*J?|OQCOwfp>V=pi=%1j_Mc0%Joc%ohnT6*sMEKUQPP? zMaLdVb5ZogIEB_WF3rdl8`fy~z*-2l1}bc|f^^ zl2k%&0<&K?k?p1jzq=?l zSwKsY#>YtEb&Ksr)z@zoCE)Es@!~Bn(@;0YX+_o(QaG6>#_;9XyErpBJl`&EXiXAy zJFl~#g(IN#AH1T%q<@I>v$I9P_81xYaBojkT>OdOYcsQh#0YG2*k}c|-uq@Lp2NXV zVqx3(;G}-w(SiSZWK?-eD=T2UgnV>RDw(b;0yP0TL*)GY_^~m6AD@Jed7hn1Q`vc& zUEOAWzJ^d;aXIAE67jR#wNXLt^Bow7*-!4;7|SJ$yffD9PEM}>-BQ)XrS$WI^W8sh z$rAeBRe%V}da^hB`8kuidaX*WE<(8CNog_DdS*)@g^@uU=cl={Uk|#6hKoX^-M2OL z`+|dWf0VMQzCg@-RZdM^u=I~ro#n>}FJ+xOFI;zDq^|$}D}#oQj}HtvG_bRr2j0)ok^SkH{C$435%6E<1aU#3 zi={XV&Q~J7L@Cv!r8$`oG1Y3EOWz-D06$8U&9ot8Gb?K^7FW;3B}8pHg)jgcx!E_= zNS|!r_fzV@?V6_MaKeWZb`A!?mHI)>>x$`3j)=j2GMZJ*`gREn9}g!Q&17=(BsP~? zZ5`L-hsguVq!C;>XoKu17A)m&=SYZZa|Z5#g9S@w2%ne-ym zC6klSWTD^8;6O{d+N{2u)B%T^ zJ@K8-Fv*Z8mxLb0T<(dHC840?GKdZjGI;XZ`Qz-)x8&|)si>%Ro!NwT)i{}2+VS67 zuYL2K>dyz!y7OR`HsRMMcrQuHOAgj7O;+q7x)`L|=AkeD`B9!UH-564Q!t7%cUoKP z_OO8IrpSN{_CK^y;Jwkld5#8>jX!-2dJ}?>)iZ3WzXJ*;B2~cQ#CRQNaW~Neh5QqK zz@6KiHa3fghkqHI$-+!BgFl!kh_9|(4j&Ny*llG;yn1-a%%)U-PRFE~^aX*D=IO1W z(sF~86o*ai_+MWX&6`a|vax8jRq!$GOZB}!;XlP{yQ1g=Holsvv%V_GIV@%uUKbgr&Q<>p|GP<)^e}G z^yVCY4n2Bv0mM0MiZ0)l>{i({io9xuPXg49Pw#2@f3h@P;lyzBpQq4MD9f%)7Uulw zQAYM~z6|p3=AZU(hItqYo}HboamG*FQ&5UZPD)}T&p7Rfs6xV`LdAa^8yk6XLVT6S zVU^55@>)^mXU#idS#C>WduwgM6s@n)VkFd<#R-ZS7>A>UYj*4J*r=I@hay@|_r>)y z#I>4Ii8^s`l!6>Doe#4WOrMvu+Q^`CKk4lmg=zEw|apL)8=DJ2wgn{)Er@W6B*F=0m>GY~D1VW|yNUOdq)CM#Z& zkh~sQoech!ouitPOm(!~8_$X?Q{iX@tPNUp^srC2-{_OA-z81gCq7*e>QXH%(OpO^#mLOn z73H#efhQ3k(IWI(&kA(``<72abZjnDsF0e4)qR5Le8Aj(uzVi-|``R%ZKt)Yv#%!YK@!$l&PE9`HF9ZZS-X~ zeokRxJ(HA={NvzImYHhCDJ4!XFg%^IB1^q!9I=(5LG-ZkpPl1l%~InCXbQk}zDS>$ zDv3B%Kr6i70~m8X28jsz-BdRfnd$^gYV*S$1KnBl1Xu@p8j*~R(2 z|6nl7^gSy#8)vLpLmi0zWE#2Sl*|w>rKHO+v1xAzUs`j>sU%6qe`zT4mhO%Iseg?4 z@V&(|V(Oa@%L&!ze0pfRF3`%iwzk5_r8Fw7NfY`Y-F$UsI3@!UB5e83z4W+p#V!O7 zFxFh3KFW?VRuL;ee^R29f@*6GN9dA5W!lF z+gr?8ewrI!0)%0*sgB_#|KZ{9L5ujgo#1$LWnuC`~tQT?G_ z@=5N)Z+p8!9u}5dYMippORR{1*W$l{|D(MEvj^X}bdX>tBhv?*5Vm)(z_gv1?-sKY>P()Bw*2q2o@G=5sd`wQ()035>nOq)q#60R$ zkL}pla;mDF9i!HyNp`}~1(lQv^ur#KFZK^MlbK1r)$&Z7%Sd!S_+&agbr%+`(#T*9PRJU=hi zns5ummRcA2$L0H+rh9v*+Rqz|kXLW`H~f>&KyB;x$61gnD>mqLhoxUl$2so^ zYNe{GD$sm7c(gz*e?tsIFzET_bbWcO)eL%w0>ADgq0ahb$Wt}X=O-r*M@Pe2$J#<0 zlLGNXRsw3Oh$U zeaY_?0T)-y=dG!n>59;ZpFZIjHlv;o#$?FIx`c9a3WAN7*3mrnz%?s)t z(n;$5_)*;DbYnnIFW1iXu7a>A1;XZ3nMAEMX)Ku;^whEY@Rb>YSjn!M4 zt#5L_4aI* zX?qwc91>Wnt|n@+0M0uAcu;~wh?2g&*EGol@WL0(H42RcCp2E z1hILVyKG<}+-_SygyYLf^K1Q|IZDN)K1sh-%NY%>k5to}I5={1V((0Nj{?kmVbH5D z@oHLzma$Eek59ku*R5-f%0}KdVWWN}sw(fUS+@Ozphi;n>Z)FjzIboxYIj|x%HC0*XiPtpn zPx$?za*4mqFXrfY*%F{29Q;s1yrayVcA_Y)eL|Im*`g})D}$=7o!))t)yFPMQJ>+=C8=*`B{~m^pQu-&3&>iF2gSn zQ`{>U*68WtLh z8FFnAFkMyVU@>N_M4e}@s8Ts8%2catl%=earR-mw?mLgTg)|?=mG6s}{Nnq3D^<>i z4T^vdz8l{gx)>gL?qAnEi%aMKDznpYa>>0shtpHD%u|0H&$Rrl_nU)}zF{-kANY2l zfE!ushd`8?PeD&lPe}>l2cRh+j76_O{OP`3 zQj+xp+mR%6jC~&=ao@L@Lu(fou1y5ZK0>+M63?DIu{~T<;B9%nbSqdlLNra90?_GQ zfs}svVYyCj0rR^kHK5;yy(>mvTVlN^TG>RD&QHvG$FRA%2L4Iy$6$is?(TjQufgLj z?ce`ujaHKntloReNRbHO5{=}mQ-i^WsAyx$3kC+XC_j*@JDMkPz<6d2lIjfe!Aib zi<+0#e?*SR$l$lnfx{9gml6vHgMjDq!RkO(R+iG5f!8wu^It6iSeKWVTFr!@!wL&Y zizuI?eQ>Y~Rq~pUK`K=n;UU@`r>Xz_Ly;mpzLyslH_uZ(?cAC9pistQ9+mf`VR#sG zzG1pKwGe(zQFwIp%G}&7;;o?^EEIu%|M=V?|Ily6Ma^MxCfor7wf_V~N3$_&3mCrz z2?@}3mEiHsIVK}uHbf&y&dl_!^?REFpG23Ol@+s%AkcBP;Uk#jec^hhjjR8@c_iO2 z^czv*yGP6Tbq?SE_4Pz(+k1MBAZ)RiD1u@o=tS_R5Ht_DU^x7LjJ;)8RcqHatRf+e zbPG#BLPAMNX+b4aKvEDTrAtz!79|}@NrSY~9g9@y6p$7KB$N^X-!a+l=f0oseSdtv z_OS)ln)A9wk8_-3b>vBF01-q*YqxIF2??68ii2-V6n^r8jD%Tg5|~xj?a&qp&&kN? z1O#l$bf3U_D?LhBwRii*jYx4;SvuAM28`860WJRnnGmYWOde~cIjPSQ0VmEYIr{t7k z=$#^~9~Mq#kk9!5NYT}WG7 z8&>YXQjkNB*%p5|3!q#shqb}5gNolD*!WcAd4WM^e(I`O&kQdwFi!LFsby*2)6(iT zAeObkr4xu`LG_MtzWq7z{8o19n9xGCqoRhgNIF<)Cg`n}h< zGolCo2@eU$ZzxpE(6~g=`CRcP9Va3mqPsAYOoTG5b$OzrlklHYlf|p<=(j9a*9D{7 z$giKV+bbesl1FmoH(7K$L0CfP%l!P+H`jfk2jsdoM#ji^88JQPn8zUOq_Um2s;bGz z2gVRVfUL4vj7qW2cDeyr{QhG&{77YO&itbp@D!WwJ1f|z-OWwq1)`@9=YP~VUx)Eo z{s&Eze8o{E{JdfI)m7#iosEBzH|N9OW?rl&xg?9nLPU(nF>?2CXmEPOD59g2gWa2lwB{fGdY> zU{^y$FI+gKlz|+^B|FEE)j^IQ8R0$N`^FetW;=_}597C!(`%fnMSU6$2H5_;PXcR8 z`aq6p?C;*a3v61*hp3yG>Tm5_zUE!mH~4;YS%WvsLCmFK8FNnIW~f$P%eQ1WSqpK9*%ClVyBNt>!U+G$k)k;U4r&DsiNzJ@ zFcGuOiUQM($Fc)ye1!PFCrE}UTEqdE?M_Bn6#G~BVJG}PsjRXWc!hDmV`yVlOV<$koU=*!?bUJyt?{^>Kk= zy*rFko<4mVKK-&@#UW&@`uh4X^bf0z8(?VTUcT0?uP*_X%XzYQ~uEKhp^+eJ?lEUFvX1;r;nb8lc zl>na#t3jop-|Z>|BgWoG2Vw9aAho_YMDDxeX4Brkp8)LlkbsOy%F``X$_ufw)sAKW zcAzPhO`Ew2w<{0}d#9wOrD?X{!C+CI@Ly@{L!YZ=8-0ro3DK)|cmywI^mH+nBh~XA z_&pFRH;4_8+%)@EBJ$PnzL-YPT=!p#@muSVjELCHGy$gq0F@j}FM~lP0%-&n@c?5` z<22sjRr^;ULFR@KKD5b%Pp^em3nAKAP74Gk&W1nvr|X7+x(pbe`1Gqt6F~t!Fp9JI z399@@Ov~j9wSd`YZMyLfcttnhfqO0dL>ChNKqSn0j)e=G@PMzxT#&B%A%|atBIx*E zDaBlDX=wo_NO3F42ra-^?2XZ@Wr5#LeGpFUK zy*Hb26NRisVExa|>S$nKV0>I$HzOasl*xZyiao90Tt!6%mKY(F`J+ZYN5K3gEI6mc z^fXf;gepTZ3<%oh89-MZ0!<%34hRS+(k-`adUpEv-UdV(|7yj=1!3Wlo}MD@VnfLL z%F@Uhw+B?g-RoC7EG~YCUwj!!DoZB`yNQ7%3qmfSX9vEv*#G`}4h|%Sy!!Z~d4IZp z8d;^)Xb;S3fo;+*(vK8Zl*O~y2EsK6WG8d0YHQ`fPE0A977lGeSe*+oexQG#Jiy8N z=NBYn$447JJ}Y@SpfR-&!2CVV9Y+wRM3?7O-K*AdiBW_|D7VMI0tBvavmxZt&`iVCj|I z(}xf-keIOs!YFvq>UnTB$S)7!BWm<%IA6OrRk{(P8sR6OoxXn_Zf<4)_Te=3PDbhz zzr&KL)rY=uxjF63Z*lL#Dq#JP(!_2M(yOqhm2}_!01Q=-ci&2pKo-vFaJuRfy?{`| z!_95~;J~oP>BhQm{3Ivvs{?l?H#aw|IhU3;N>fL~(f8y*@*s!EjGJMi+1&$Wg2i>e zh%^--Vm0(R+F45RD1smdw8CSnjT%`JIZ~+ifl=Fc22N8A@(Fk?cd&QWB!&)3`n4`Z zybQFo-jVu)b^vfPRI2)%xQ5boYvo2;6RpGpo?MLpweLF=$4AeZ{$a}oG z`TEI+ocIgB1OY)4P1Oe&gpmN~`Wj5TqRz|Ow1JgIQVPHqyTIm42j;qkmvCipA(+rK zvS>uz*dei^KhXs|frnh&+|jUm@$Kf$PQBY!`XpH-4nFv$vteV_|Na@cWk`xGDZhRD zR>D+`VkM#gXLgRRbX*2eU0F1(uU;~&)62gH<|BXD^8fK0Pw(8npLc{c`KyzW*y0U1 z=Nk}9;vl+=ND4UY^MWStA!0lcF~lwY=j-7&{?`+;`2GL>^XS@8h(+`6imm{$7%bb6 zJU&%iinF@KJJ89RaNP%N1TK2bSQ>H`+ETkMUfE^Giz&v1U4XQK>6JPw%qnh9g)woQMY`fMsIMo zuVM5R=3W77Gs%Kn;({R@)6Ex(*1~=0E`v8fOUum-K$Ry4+utBX0uHMLNe|&3CUAt3 zySQ#dd==&8j6#+}F`RdR{^40HOwn3jzXit}QHvyv{~U94tqg3tdszyNC~xpA5VGuS zZ9#e^<*{oGgBfegGeRS0&z@zF_MU8S&sGX&0@n*!A7tbXfojN={S5rCXS#6lqUrd% zM}s+P%%HwsKP5hd>pg$IXBrI*rEXim5gI^9d*xv}VUlr6YwIF$DtHSNPUSWJWYv56 z4W6`nr4CB+beDFXV6=5Arx{?TZcM#0+nP>J@3t3Bsc zF53*>zXI}LF#Fa<-OnDNlz&qRs}4j2Ol|}N?O<|JQhONvUKdBI=(TIzj8Y&FilJKh zx0IFbisyjPs456z=>eHMX%t{kC2GQgG}flL^^q>(*H4yi+?fu8?4^gt9@W0SeG@}N z1BZvJdTni-R6LiMC3JpI*iu$hyk7k9VYKj$DnaJ(mj->^r-xPe?1_mUUiq7Liv{;z z+s|`FG!_?MLA9P;#eAu+i|Ofkgm>d}|6JQ5Ifqs#9UGOE714|M5xHR!hD!v*T3;6u z9#1O0%zdyb7hpbGbkC?p9>q>{hEAZG03rY+T!M|7p z2cn3sf8LNVlqNn!@?KR{6)Z!#y^dDK$~q3MdLtuI=8w zB>jh{LbrxOljpAPXRZq}7RG7cCo0ch38~M_di5Z=Z^Chjf{aWhx2UYxpcXnGlyZTV zr5}^?#XR@j31Rji@yUGL7ZDC&t=YNs7x#S*zLh`yDX6GcNzeF?d0amOxO#K&R}d1v zWRj#if8ODP83xK?&{c)Szmu@f6k;Z=>Q)X&_t1H{xuUS!tB4B(*#eWvzS4_+|4v0M zS+m)aLv7?{g8J;5K8}clk6~m?COU*X*>biMj{f7TjPaU#0C0(@2u7=iGV1kbbd=}a z5xRYQ?zy!}@Um!95>JIc1)q+(l)Dr575!>WMoMQd?)@Ldjg}sJMfz1GhszqVUt+AV zws%2Ax3>ofs3`^-W`?esSt^G1ncQ!vleoCxPS{B$m6&V*UFmZ>&(gn7MS6JT!!-@oV znQ=p@WO7FgjKhQ377z0DD&wv@hXl*tvE*^H|E9?)=mJ`nd4m$p-P>Emg1ZY1G#X{4 zoYGFpf?;vOkyN7Jw&uBVxA&&Cb#=^-j*4xaITRuL4fxZNKCP-AasHP~O{u78ZrbL6 zJ16Zx;#tUSZkl5jcxQlm1F|LX9J=@Ki(R{>sG!i+(J`$aSSke@UqAybT;MKi*3<{?s{6sS+b0{Ivo58}?R)D5FJe)>O zTh0pBSX-8=Pc~Rhf8RiVPPLS}6pod%9?kAv-yb~+5**vb zoTJoab?j&AV;6>IBD{s|3{R!tU43QLU`!?So3Zq$-laqs9 z8DtzDnV^6lySgI9J;7N4oKql=ZO05l%@?=+#X$IBz~k7ZDRu z6c&U87v-1ri(B*X*+UtM_he4V$vwIX*ge6KPq)h5?8RJaEbskV z88+EoqvY<6=e;~#SqvfMs#ABZ+tc)A>6`9-4N-LsuA?IXXr#W5%P*9+{$G5J4^*QaFv z-YziMK^6dvm>{Z1*j;8Z`1NP6G&3Y8;Q8!{$JMb7!x_aZ0IO4|SJ_SgHO9%Z2XYMQ zCs9Bq8Pp}pGr^vgs0$KG*~?(${58rL04A0IdoUDS5h4E^k@qL!fE zpXR$B$XwPr(shGyJgiaqa8T`YxKvGm!Q>6Lp}!H(HCV;PI?-y2G`)jR2-PtL~n4#dUzoJxtTg}o7jDoPHv8kBlg9CL8 z63;*t+VaK`tpMgSM~PM8Ui>4Z=R&zb32as#jhMtw?%cFp8v0b#;wp zuh&2Cy!KaU0|!{^8qX-6-Ezj!&$dO4CE!jDK4Sp?%BQ_`dV85?4qxh4Gi+IClx?gF z5?Z?YH6$G}6WSnv==Y>sydnscz+9v$?;UCN$C|H82n1rUPN@Fgzoa3SdugHiQOKs( z5YsW}2$S$lamQ?&<_C@1MRZ#jJ`KpB#}1Xa_^=n zl{ugF3jKSx5M!l1dSxMRZy99D#)j)GiH5TikKDo9nx=)s%FF|{yJg)6LZrhV;{TXn zuyD-DSZ+?YE7m2x`eoK(d1{eaP+8n6&W&J4UER)W&1#4wlm4mh{d){xE4YLN=YXS5 z!y`91Upp-y|14M<#FArW>gZwf(hg*ZRNP^!>;NnQ)S5t0uu;b=`NaXmj0aXzTcA_h ztD_rGMJajzo`8txQ+Ib%Z58AcbkIc5R9zWHtG>;oxvee4{{Bqd(qh(&^(SK&4sGTz z!5SG{>}o~N*yS$%{HdVQg=PuwGp;MQe&rSy{AlW0|3{iXEkt|YxkExJS~*u!i@tcF z0-}75$`elG2h-8#_mQlHHdWa2`DXPbq>aDt7()Z;^Ld37!E-N*uX8#$97p|JpL%rZ z49`SQ(PY1d*M3R&;2j=%kzkfuU@|$_E1rC(V4$;4jZ!R^31oYJTb11Rwp^t#Mm640 zWKldXcm--VEW^#OW+89{9?;DZsQ#vkIkLZ9$0H!ngGG-#9*~}h{+!uWT%S7+C5^L4 zrkiJriig*cLajj>y`5~djr;mprWIjK-gwBe&mAD-4 z>4?IX)u^7UoB6OEGA-n%Xn4sQ0u`Xwm2lRJGkev;r-p0#P3gf9ATJSTd>2C z?_)Vs%2g%D-GX;LInvpXJijGpV5oE3ngbXA5^8@R;x0qeK_toK+b%jh9A-|DT1Al- z)B_z{UE}}zN?XyhZ%c%8xrYWO^kQQ!)^yY1^K^dT4hq*^n=U?Bq<)er6}wrxV5(qa zlV^&Nbk~1hF|szvNp~?Pn`@ikN8PMo?G+^Ax%B1>dbUyBAVKP;O9$~o)bW2I;=#k;a}I0yi6@g6jIy%xA(YHJR!v!f@B?( z(-=cqR!}gId&%F|*L_xY{uO$s>FjJHIs09i%azuECJzee3wU^|wmPVzSlyy^F+h+3 zrI^Ra*jAi+9FY01O!mliUk9ll^q=U&PM9D=B-IDl$5u=kcl772En<*qu7C=Rs{vNh6WSD z722zq%%(u%yqWy~MG21zoGit%5ApHy<+1m$GigS6B-y_-Hm-Frmv{c$n^xew@OdD5 zt5Z1(A~U;*RypkXxW`86AY623RI;v!h)~BJK*@++k%5ftxgPPQ?@;r_A!gYBz0o*r zNU#ERXegwiaFZ;du_yv4EvVKY(j{o|{vun)r) z6r}(C<4^9tzgOD(I{@|(53lJpxKma=DCQj^)zaE!#6k+5Sjb*jm8hCl_8~6lRlwtq zeUL`C@`BxKg^|h+F6%sc4f@-;{^yGf@?i`}#Vc$Bg9a*RVTXmC`=OE&cMq_$zikxz zy`l^Iu1{VrFt_j4_8jZcCB_BntY@j~<9EI;=e7r+6wRr5E=jxG^cVE^XB!TqF}}zV zZ!>MUJE*2RMED~pl)|8Ji#ie&*q^~2(fXzS(eJ&GMY!JLg?stk8ga|!Qcx5Vys-Vy zGK^8&1sHWVjUa7-fN6JQx)ExPFbf7?1hAf+W)NaRyZ-^;WxlViNk~XQl>{2NyX#Zp zmP5G^V2F!}bs0E;Yb2uk>l!1PhlVt(R-)Jzr4KJSm8-^E`QnBw<)D--0}1=R_YBz1 zj*Q>`$W!1tEG{s2JGscX^*L5KfA@{(WBtcHLo)PJla{~Ns)Q9opOFdI9mgBVU-v$~ zPf!m9#O~|982)~}irnZZ3T*7TE?Z|5Z=R)&_m51=1E)_hoRsg)tTL4r;`!p)FQR)! z!D*HfGQL&#s^h*_bhs(UC_&ww6sghejq!^JXoYAAL5@K+xzMow09X!SQ6)snkO}=p z2qN8Pp3k-hPFH~93(UbtBs6X%uK>*(Ciy1xf}A{{H3x`;=GQ`2u-FBlB9oLdcr2OE zp$>?|m-{RC1c>Y%-pvhh4nu(7_@~IQrp$Bd8dN4s4o%&d%lg~0*4D-wKk|fb16ua` zTKC=tpSYtUq=1Efyi$hGC6+$+H#KM%QDg|B9FNY}N;)Z1Qe^r$jIaYO4W;@Jqxg^x zspsRbL=`VKP-`Xpi*U(fLfz%=&cEK?TfD@`N_GpnboEQ3o<HV8kfh9hg~ zz(WbDBL#p-Xi4X}8xqogf&_P=WoJ`_d$s)?j#`~(_4b@Xvz8Q3?)>~Y0eC1V?MfYO4{94eUF=CELj{Te!>U@U6rh>g#g@PV zSEZgKBy@6iW`qKf60=ts6o~v~q5ZW`M2MIc0665a{ZoOLMf=s({ssaE<80Uwhgk)m z1IU|CsnX25_^*zD0ch3Kw6Is|_s8~joTqb|*i&&|+8BvqEb=}0UUuqaUe@M#Rw=H!wT#B`C5e!5GZd{uE{NML=TDqdZRN9 zDT}z^9Q&=;H!3+d zu3HblIe-H}S8W{PqlpRn4JL6HLT+T#8nXWjIMw;^CI5YmNH-{Y;w#v4h;m)(((vgsa2a$8Y7#jcvC_Vhn^uD@k1|<`_1xO9% z`QvI;5RDZ@H1yzUk-{DdRxgZYEL70XnF4zdgmkj4n0Zj+{`%T8Heduys z*iMXrP94Xs*W1I|M%QbAnyLYCTp*j)fNl93@o7U@5TG}qqF1gss8NFdfg>aTPp`=) z5hl+eQTq&tDR|BVeq&g?iuCefAI8=OI4A&n%$7KtV*q0UbI-)*&Xq#sGFmhRRRIzr z;M@3BWKatYZfF#Xu`<9{t<3y*u9w`$Wmn(X(-Vi3&;J!pK@*3GnY+(?LD$W|r~|M% zfS?kNAF9@OvTrtP__^9U4X2T`n%KCwuUfET z1R&@qy@mh2eL%-R=nD-xD9%W_tR=u^lOZ?QeF9)WQNK;zfuTY&Z7r?1*x1=i2Jp?` zpg}65V`JG|g%DL*o{7rLJ#(!9tO9W$VoCq)iVbl)TOoiIfTw^e|JyHeU+f7(fT@4> zJER|A0LTMJq2&QguWKv{aMrDd)n%x!I~v`QF(@1&`hHxR`M;a6sRv)wrb=cVrqG??qd5-5b03aDOJ_ZK{7I>+UZ~lnDo&I() zcjRGd4KfCo>Q6nb?#2ee*xL8+Q?|zJn}uKrp%6$&!~Xz`0bscNML!tuz}xyI zaQsK0R)Ut7mqFb=L9+!QmY}W;X=JTF5antY>O%0&r))1T@24?ui42pVc-25%VW})s z?;WT^{;#8JnVx1QCWuZJwP!7WmAg}DEG#T|p7v1MK~M-Xl;YY%B}tD}=0{jwUBy3( zFJ#(D3Oqvpud@NL<`&fP=DS~fz%Lld6)VGlaBBm^Ycbvksxu4lGbI(gcg8QE@%Plj zV`HooIC@F}L1ORV5LK&#+`a&U{QBD{9U=$Qweq=q6?x6~AYgVAD~fB&%c2eoodC{( zZCf6owM;^m6eBdWTcGzZfwQ90(BpeK(unzg99xpry_tnmf&QBJ0!K1I?4!qUOL-1`t-WCQe6eaDQE_5k7E2{~hQf$G9_?;uS z+Ye)wJ`NN40(cD}I(xceV6X=8CM5aQ;DG-&{X>)yA#}_Dd{KAz3V=@#_ZA5KdK@CU zA)rF1x~yycx$Fd;Kn8|q>0~`g9iT}YH(LlcCqYzJzGuPv!nV$t7SS*sK-v{*@#&Pz z82vdI1xU_jT;z3Fg9X;94iFh|HAEyNu+cZJ77Z6dN3L5~aY(YMyKVFiNn{6OOG}vg?{=+vjpCADE_rZ*Tb7BR*B* zoCt1lWjKG4_-$H=_mMkf?aTZy%;ta$pw9af_$}FPc0l(7&?9aJB?cX;AAK4g+^r1h)WA zN!odZf>_L8_^=H^Za-8wgV=yM#)1YmonED&Z;`}L5QZ~Z4|m8^0Ao3l zVq*8#(Rdbu;No#`aC#C&Hj-Vx{F)2lgYxouN=g94FT4zir~#|Ck_5pU;*bV1Z`h52 zGPRh6Z3{yy>2sL{U;Xv~&|y0`IAs1@fsGWjwq{{uuEafSXr~&q%5&%Q6LZ^<+)yZ!N zK#`hDGk1RhW%Nu^H8?9|<0CNx(U~)6h#9Y$K6*3^7g=sKDjO(7M^w?>+pDCa>;xhg zs+iP1E(-8_y)ZhV6?jF!0)$K|0CZx&9DxqeLs&LfJHNCfVuHb&^a8WGHg1**pxB?# zSK`&LdNXXv*@i))jT&sFA#m~&m9``vl5U$94oA(sjRD*2;o+gG`T>Av>l2k~KG)jr zR~8gl!%)emM3GcMivh4Wgt&R_R>}fBT>ws+?2hHOXZl)zcri-|q$4KY)YUO4o)X`O zu=V$HM!3{w6V|OnVK1;IfWD>xwpdNgmM@r-N4R!2?rp!hR6xPZg*fX5Z3O1 zEz>D^a5|^=0zmB`Z1hVA9`bbqyQoPr_vh*i+%bc=OF>8o!T)^kix+1^`9gQV1O(L6 z346rF2unzKf{7H3?|F3L2I2k@kPiH+D zKCvE4gob}YeNYhXDHKF)4&a00ZF;gDO$JqGDJ}2L0+PWZ9r*@9zgks0-?&^ z8c4zi5Ma7H1bY`n80hlfyg9YUCBk5TO-jlevKY`%nCnH*IjO1BQ+yW?00p4DNuxWv zy2QK=%3u^0+}FvRiYFL7xnQ`fc95#1rpP219su0l>({W}R1ZRALqlFy^-PVqjSXq5 z5gr=uveEv2GAS#;?2%$%EPm7-^XNkytW%xrL)%XSJuNkl&gS9IUQ{%6U%kvsX|^Dk zEBTJhE|~XSaCP0QHIhM059D<$j1C1B8d)jCl9B++TPa2CM}&xlyi-)4*fFu@iS6fm74;p zQURSO_+<)g(0^V(LYH;t!tUN)Wl4z}xQ{S*Qu-bC^}e)L&}}=VjxV5u>9`{F5L?g+ zS;heF3@)Of+0okC+SGI*l=douUYz*+8BoMinPEgd?O@ywAxe3G0ZTg+E*j>M05LnX zWkaEGR6c5`*XS*&`GXK(V+&uQaFWMnSzZH4Q#KPuu|6o(Z7vA>LtsDvL?yAvIFq~y zq(^r52na&pEx|{8>uAHr!xIH?9g;%>zV^hN+52eTVUL&uL(g~r-Pv!E00EgG!X3pY zCJwMi;GK}|0PvD7?5hpczw!p-GF@F;dwU{DzE$j~ICpYHk-;YHdzXp;#?8E3w_KM< z)eHVHtrUbh;8wOI1ej}U5L6%oA5j0I-@Pz`g=%L9U=dO!oBnfbCOGGG_wEpcBf4eg zrQqHGznk(LQkqEy`j_;FLBodpjvs>~^K%Umodw)A72eC zB>}P&K#DFP?Mt5$sR3;A>&Ig4ofGK-1RzT#rUX|&g8DO3(`z_BSOv5iz@>_zptFgX z)jtr2c;oCr2SgU4UnEJQ*`{ zqe)vZlA9(9e}_<%lasSj!gwx|D@+t2+=Yx)OjJ}S)fkYez$yVXpptk93%1$=0Gjvd z1UR1AB?Y+NlRZs$w*YVb2ZA6-;9=wiK~sa8A450^&`U4yOzJb>#pWKbL8R!<1Eluz z#J38yrhi1@LTE2g)%+~AMH8?!A$J}*Ih9>3fx<16pmhEK^9am{!$RZX#}!tW9G^b@ z1tC(c)3+CQwxCPA17^3a4KVQ*kRpj5eI6gb-nt?C4as<6ipX#BJakW;S=&DiLs1;y zex8skfHlFv#)dXUp-yQ!RQ>=sC+f6JdJHii2}r2-q3HS%0|NuBq63`~YoKCTV8VTj zPZp4cpn%$e7oGc@wX!lgCx@eeO3~WZ*68>1l1#FkKv?z(<0_CBEyHbwhj$ziF1SNb z0pbsLFJB)Ad57{t0Pl5P);Pfu!#;Hg=mE+Bg8)sEi47XlP=}dzUoC|Hz&p{}+yfvY z5Spc=ctgPl*q{?b6Css<+}jn+0RaTAYVuVx;&l|p^}Ht=ZC+CO$7*cYDbqBF_}n5%vJdo0z;J#kB+_rVv3Zl zKw9Ro8Fqc{&FoCrHWHy=F7B3^nurCd>=AkpBIN_jFR zBO^q}z|zTF2Odl10vKGcgYC$}J!zaeNR*&MP*z#l+ug0n70bQ|=nG1GButK!gB0ud zr}k$EGoW(-Ve-(OASBzwg$QCDnNIMVjDi`lJ2|(Xy1B`Okwx^ zK~J$zJ)NC+`1sc#GyEU4v-@H<<$ocj{U#CkFU;#8k7CmP?}H#SpUBq&WclPlPewE0 zS<$o^!?&X|ufSYW1AeYO#9sf`j{#^3FIW-` zvWo!YQLLGfP|ZWeYfe(|TcCr#n89Gfe8zu%qN!SRbe#=3t94o!HhF+S%0ys*CQC^* z_h6t1R;sOpjZIJgY4In34{(lcJf_lJ_joGX$;cAK-$O$Oui`hUDk?6HOdA3!8@N!T z#HnOgQXsq=8X9``>=}d`t;jTJRCM&upFdaasH^%s$GEv1{;2U ze$Z7Oy?0#owEZ%SD?ulHAorh(-DCgv*318aeNQGrArP6rJ!v%~A8!l&9=Mk=LiK!S zfB%|oCj+N4Ua|YynrEK&(}tNsad$w!p+NQ4@Z#4MLAqBag+gfN{(!(~>mYPrTSv%w zgLm-#^wXy`SIwNnU6u<9oErb|mfg;y2ryT^{gU^h zyz6p=&CkbEd3S2&OpqrLHPkn7h8CAKt(c~n6}QS+1^)>qvGhbqy-Lein+-#VnnXIu zwL;vVDHR(QzAvNr_Wr$dJa5pa(SrUk`keRg2N^}*sNSeV>O!T-Oq8zDP_hr4pz)xsDoCT_Eg_2%&aX3SSv19Q>4! zHc_vqt$yK7K{<|Mqf23tmj@I9YZ|NL?09zN=9!hR-c!_oYBn^9h4Om6;Qjx#yO$~ET!BAN?+A{XWNtNP`3TVyp#ubQni z{8Ajv2(;;8NY2SA`Q{M_JxC~mQ9*r>f&w;~FTPgx_LdT^gXwOAIvpJZ zZ4YbYIX!=#e!e}l|7bgUebabrfm(|ja1pS?K(<~(qw~`;i}>WzdBv%4X?(dHvP5^L zXC1Hx0=O|bUf)(x!58*x9v;5YMVfTV*k5!$D?3}IR#io%1~Q@Bw~6m+s9;43szk%M zXk?^uLbmXQ(wK9?jbZK)Z|5ND;vb*b_d1o;loJsf>wj}QOIcO5_4UE;^5vWl{dg)WSjU9r+E+|6aOJl}j+ zUz3#ypZKihl(57Z+HmHqP+l7&W!KT>V3V5(in^$%sHjp)aPC}CczB?% zoJ5u&DXc%64Tnl|?7)ooDT@m|{EMGAkOWCQI5@cFYqr*l2Ckk|>F~GDCPvDrzuo8O zcmENh`9>be4haaN9mE~K6254Dow%Tge)_B!>*XI+p9cdX@ev+py?ig}7rqr?uBj$d zo%mu%&JN%RxN4azbCldpR8%!mUKsL^UD3``QYNNc_2*yLlc6NL=@|+VuicYaIXZF` z&>4y4_PKHA?!^(GpJ5RummED0jY6v&&8C{3ryB^mP*d+M$+<98t7PGwqB{IuS<~$6 z+<3(PBaLj7DM`}~CiL;3|K=!!KtE-sXQG^)HLskFw?#jJamU+U1M7C|eid>OppaRD zRRYg0$T8K|)ny7o@8`KF2OHbs!orZZ5nw{W00W24*yNB(1QNSt(hz$@|9%>yY-v_x zyHm)AtwKRhA96Eu5~8=@t3LYr4Bww6NbX;oA)vpD-B1UF0#H7KdG2@;{T#dc_D7}e zKhppg%PUZIVb0RT=^IOCsSHpfTtor)X(-js2R_-=H`aYOq@`z{X||1;Vn}b4>&B<@ z1w;o2k!2_(i=pT)&Kni@oul)z(TPsvW|BeCZj%#KsHl=3>uA_Zmddi=l&IXKsJ?zV zEv&CAB4YJh>E-jQsZAq(d5WIjUl*0#4Hd7qODpnlH7-7VI{oqXMqF%==o4!UIfRx@ z$H#L9(7jSpOL(K#Xt>QM^;DCP`|@+aOINyUtzRwYNO;%TjPOK;D(ZUxc6y69&DRf_XF{=g7VB%J6Wv;A_?in}c$J@)y;eIVDZdXi_G3$D2YX2E*zDc2BH_bHdRp zGuMr$4=UfiR}j!B>y;vxd@(rK_G}_Rak4ORIV7x5opPe$s9NbRnPIDsh&Ac>?L{Ekad6L~JIXg30HXfmk#W__m$Eon#1){F zW%kFOX>o>zE%C#avqSqHi@^~}Yb~F3X#}>P4qb|L>tPVMtf8N@>>bkk>+oqm<>-Ls zXqvBEZtw#tJ}NO1MlSamR!Lb&$96Y#>&-!ND|I=W4;r@h|JS8_Ckj+h6+*tpWO*tU_IDcEpCLF z;(eG9#U-TK{CKsu?tj=SaOC%wQhfqMTO-AtmiYl>3uF%fJqn|yE2Vv4j_K>oylDJR zU4mx)CF9(;Cl(fAii8`9;@bQ3=?W&2=K}+R&xNE#OCM$G)!e;l?T6XClWTu7bc{gX z>qI@YB*LH|7Kv(eSH4!!#@kV`w!FEnOxj+7BLp)JR_~~WZ^^Y6MZmw zLD3V!`Z49QB8ME^ISPjUmPifhOE2mr!>Wi+P<~K!@b$pK#SNUK&@qLWTQaPGt(XkO ze7L%?!MF3Ij%`c=Dg#%q4%#tTPc{MF(gmixWO@v3iYkg7^UwTt6+ZfV6q_pKh=b5k z^{x2$+rwKj}Qe%^>?he=nwk@;x^JONMxKU5|3@1P0}NP!o(>`X5sOe2Y> z0~865KK4-c%85KV-}`jd9srDIyShx?v4GigXkkw40ua{m`+-mbX})7 zf9=WZ_5H2YTg6+WQw9ke&rY|<-MQ12q}0iBL5AiM1MQiYXDxS(fZ9*Rob&wrPqiCl z_P3L{QVxsmJJyT2-dbKl!Ni0-n4T89u(%u1@&snNMGcK5kjz3j$XDUuOleiJ8g-uR zJZo766-fch@xit`>iCB$n9sRAKQTvnBWn?nEhievGgF48vTlM7O#ybsbftMq&sP*f z$$KCfXKPb!;N%~Hs$`-5a0>%eruk=;AVRt$yoE)szzp5uQ;y^K^`=p7RXey(eV4Y z7-y4;p&HU$z#mshjiiZ_I_x1=2l%}fdP=qw>Q)!2~Gomg=nHxUc2F4aUrBQVEZQ1cSEWXr{S?~ej+J~q3Uhp zw9i?V%>lWznb*sdZFQ*X;)pH0i1Bdr?1x6KLHkSja`P+PB}EwgLTZK3C9s83+AT#w zMsJw$KiJy{4?%JKKtZ*plvaHTJ^Rexf9}^tf-_5wJde&%+kUc%h>f14m{Q(S7@z5`RuF|OM`9#U)Kjr$JYmShB+#sAS zG<0mrU}z#mQZ|W^QNd%aQ(43AF3;P}UNuwf57|f(k!ypo6Szdb&@zgjnN2=Y2Tk>OO2+uXGC z@$rET=zfJ8iJ_as%u;Lf^H|tT$x`j58G3J7w=O zGWb20#WIc;cRg+c3Jw3uHlHtk1ilvq`gvv_3a`MdEH!3<-5<|Rr)QNWCidOzLdWxv zsn9UltX1#sX47uHz#h#pej7A#6#}Y~fibd*qg}oJ&$Jbgmyg{}WLNRSf8L%hdLE3( zu)|@M8&}wYABBe-dgSY+sdR<8(;{J2EHnZRzISHay-M%_rv*I&ZE5>iCYp4Xa~Uz` zaq!EZ`^uoVE$H&dP!bCPT+WV;avw!KRG-dabKR#?r#{^pqVZGH(H@0T`NE%I3#Wbzl$_QP?j`Hd`<0DV-wx8pa*>+GFCh<<0kpwu<*sKS`IlQsqI zd%ZD@f?rB~A>dP%=c&+pT>jfZGeVwJv$L%VS2B*$FX)69Y>KH|E+TRbrYSk!!Q@iN zw+02xf>yfNP`5HWEx(HS#J zA?s*gSzEh#b*|d6IQ*6YdF2yK&D(R4d+WntjNB;{wiE0Ud&?SIcbZ6~(Ot2b8rf`b z=>_Hje_ay~NhQlxqh_2AcDG_5jP(zf?1;LAsmSD_@qgqO z>m;>9vo{1UQjCYPh>n_?s+)T<s z$DT@)ONok|=QC9O^(H}+-|aaG-U{w%!4>*Mu)(YkM%^ZXP;sqsT8B9;xGxx zky3a>W-FH1GB*`7J_UUrOa$fZNSzKH`!#aeI2Vi*1&|G@3+=8Igp|6C%OaU-ACz$`oKO&-?fcM>i?F?Wa zt1Oy{=xt7|Y*Jg$Z5h0Qgs1)M0$wr$zs&NNH`h%T%yNyKQ2_+0*Vt0B*e~Mk4FRQ~ z>_L$}8A&o5D&V2bm&16iLH_PO_1Vuv9q26YKEU_4_rin-H8F8|&ik-18r+*J$2=NS z=u#Yo-5tu_n9{GKMhbA4FQ=w5 znVt<{Q%0_eTV5y8kRB5TV8T-sx~kQ1i$ZkHe@^qYGqy7i)RX z{dMtl#>Ec<+j?%)I{`B+od>+L1AK&T1gTQLDW;(;E_?F~hhEa6-RlErK_EdZ0;KB$ zyeUwk`~U_!JE;W*z$rxF@U%sS|GrVzw>SKj+#KWj{BRswD!Gb+K zvcio=S_v8box1O61XLL5xhq}^$Q{!0yAdl~*mwHuf6(8QyQ*OT5RzdeK| zeSUrKfo1^8s<}?x58#+}+(Z*>L;=>OnDbFmDBJ}U(W+k*3?R};aVmc7BpS|d6qM=P ztda&Jr|Y;U1_*02ME%Lc&>rWIwn{5T*a%Ml!kJtlo?i&DHofloUpqo9mO*g+F)d-oUm zmSsuUCk>rUd3T0VJJX|R6X?km2p$UfP2wPU4lGZruf3_$fc?!$aqsR!BXmtnlI}eB z-(3_C&{(HAXTboF{WC(eTjf?Qrh|hDX0R8#U$Dm2HZAaAJbvbFUrm}^n~F6P#l_F` zava5mly}%aL0;qsbrcDe_U zD<&5ehnq#RgjY^cvUU{=U7&sAP(pAivjJOtg;bB_q8FVxBbWSnLr!K-hN}B7>Q@He ztZnLN_Dio9*kI7i{;^;0#C_$8`g$?y|B&_8VNr%}`Zt1r(hZUVA`Q|V($ZbhNH}!E zP$D&mlt@T-cXyXk(%s!4-S5qJcYnto@A{`T!}Hv6#d&@%FDwUHm%LI@FDzcMtoH2e zkfcbdoB8u#7a4lR?3r@kXB*xRPdK?-6%oTm>e z3&OXZrz6juo!h%OB2+R@j|R%%qgGa8Pw`G{k@4H0(AHKW*;y=7D^OFIKF*Bj`l4H= z+x08bNHA6lge#(CC3^HeqE}0gU0+OtF+g|S$NA<< z!>)+3*Yh90b_IggxPBlaA?=0{4H4nt1$+X$53g-3jpz2Awv}5Csm+&PB6j&tAEFmN zMK^umzO_xVu6f&-c(K`<_=&8yJh^&}T%g1#A*?)%%?Ns=k2eAsV<<0Q1~ACveT{rB z1~0+UEtOE9Qkr({J51^&ME=1aj*UZX_{d54MsMMEeoJtRPb>2_+3AQ6^j3a%Rk2wB zapIS@p3v#>Au?i(x-pjg{=U9<=7SAO65rAF+jM%GGYp6mdC?W8GFZ3io2lY!#yMi5 zI5QK0u=+}4IBM}ORAHTx(j;n|r7M^rRR;JHyns*(46#cu1-#Ius~(<*hoi>_P^Md| zFhhNWZ6xwX<^95;y6|hlWrOMJJGxRXf87JCuY>S?)jzo3UpssLbn7Z$vt3aT7no1pT$#qOq1nrf1;7Gf zwL)|fMX7N}^Jy|}cjHPD{*gdJIT4E7|m$mUYwZKurqHygQus7)$W? z+)@&pa@)7bqjcD~BKhw~cV}MjFkM2gV*&ui`xSSBE4ZjF^~5e?VCRWbRSV6PXQVrN zd4~(K7$Hf8BUj(PtVc%!?418iAnc=rSQpiZz6`4d1wQ@+KvIFL>&+xQom6svf@x&|HZEo4wwHM;Bo3n++ zi99+qUXuWZNT&FgbHsv$h_)7==omll*ai2P2vUB5b`nqozM7hp(j3XKC!v zm%h9$m&(N@;d`FcjK%h*FqO*oCu}E>)mNiTA-X8|Z1*J+HqaCOz%`nw3pixN-ivZ$ z!Hl@psy`Nl#jAcB=V3HY)1iq|KixofvA5JJ9PoD5>z_-;1J%>an$wkSm z>x*>>WA*81=Cn;(Yw{MAkBdi^P87Ju!cV?3lBqQs-buRM$=&_17D{NRz*cOr^lzId z4d;7zNFz)X&C8;yQP zQtAs4l9BjMp$iO6@XtJcBaBu`;UaadACB=zpe65IKq*b`(Of%u(!!*3T$E0%q@;q_ zCg&qzJF9!zz#Qy5< z?|TwzD0n`u25L~7;vY2ia6%4co))TqI`~HDujk_o>g-ocaKGxDeHTA0A%8=KfsT$C z3_3I`$vHpLvMs_UL*W~5&(N_E%m8CJ=xbOL*BcW@F*M`^O2`?z6k7J^V$NYTF%FwC zXYOcTUS1m*D<03Q2)h#g0IMser=<-Z=D&efZl^r4ae>V4e1GQD@bTQx_cU<{jg;3O zsG|4J-1LeKfLhAMn~i+yBtrB|R2HWF2KsKiLV}cx4Be?+7%IG;^Zdl4Dd+4pHrse7 zc^<{|$&csM_|Qp9w^U(jlTjIF1DN)3Ld*!-$c};eUk}oo@5PZR_K$k}tHuV%Xqr>f(|jY`aD7f4(PL==c z#wev%gE`Tua(MFlyy-0{S8Lu*71LwEpeVj8JQ+=TIL~OP% z1Y~3i`bfWjaQ-`LDPgmhZcJPL3Cw13qH>DPsa$)CA@M|_lBVgOhTxt0LQZ17<}82> zZXdWU8#Xo3j9YH7+wZUBAQu3HlRX0yVqL}RVqG?}cVS@c=uPRvZfOu2sl(2I3%x3Q zCFwU=kF^O`k^3E`sZv9r`y?Lmj>9UKIWwX&3L#?p`s_WrJ;}PeJngF>9nkSQw0>f*lUcHFlRX$WT?-@B0bhT{+GdFBXt^v~oJ|2|pKZ!;#nWAOaFk!EK z+r-70_)Nlph_C~1^b2k68A3;zpELim{OA`QUc8D%E2jeRZ{{rI z07;$Gvl7F8DmO}p1s3Kd2bBe1p^GTvXko{84O6bts$V6)jr?e;t_!P+k%iSMe1K`o z7ScVv3$ZTDcv1b}P95d6NxT|eAuYzquRqJnwST@^o~Ppq)lG&EfJKonbJ$DyV-7qS zIU`TAqcn8+dJ#Z@e7ljE=>|vAWWB!PyqM{@h z`bPrluyJwH8S{G+OK(IQgD4gV&oDS;6_;&!e>&BFt74>F)nxw9doiIe&Uk@cOaBsE z#HeB}*A*DFI^@Q&03**7jmU22`b_vK#VNa{3+r%tpM<|!-;pYSN2D!``2|!568bs$S+P0 z0YQ(9%8aFz6VQ(UHQN|ZLT{_qg`=30LV8bnVS7V`}q4i1g6p1{uh21sa zr)HE<%v{`tKAenrsqP;35>@9;7}4J&z9uxCL%~%yy6n!W5w_IWloqd3;YNw3wjVn|p3Ha&~t1G_*3wMnvoMrhtIweT1uIMj?0GB-9izw*rnF|?@)^BuiVU1pbI0NE4fTwf#3 zxg&p+`#^#u5jb8%U!l|b{75_a&F!+IQ?m^9`T7|OM;1i@^%Lqrtg`5dj zE0;#m)Pw{?R#a9RYv^vVy(=~wkPUm)zIUXA(GY-~FhJ9;@pA_!go_39-@cE>Upj9O zQa(qCIc3kxIOO_{bkAVNZ@13&4WHK~L@r8g&Yb?Gdi@KL=J`+L@U+KObtSQ>Fz8O| z+mjg{<1PVp!TZ+L7On0*JCgL_f1W>Bc}0hTu=BmtG~6uvd75b~g1R_k*861^3e7h7 ztDJ?^RHb+EV#9RZNcio9H+fQTE=Vjj_4LqYjm+KKf+8d?L*mQ)%<>R-N4Vz|tw@fR zHz}`Fw7PbBk7T=gcFrQoeI?ql?{Z=#sAL+RK}qqScp1IhFL+zNyoFZAs5Bp zP|oFD)Z&nW3kt^lXS%x~o4Y}==jV`CVOeH(Q3_EI!d=8D0vGl%@W; zT2&t^u{#pyaS?ck5v(!+Bu2vXuLT&sx}B+P%VT1ZL^JJNeh7Jf$7X%JsW>_S4fiLo3P13X}`~V3yn(9#W_5~^0#&2xRLna zTirp=OG!KH-=au-0QL4D!Y1aHLIY3f(?p$e7@kL0{>LnTwjaZ#3SrKn3H1N#utf&v zl%!jhC#{M0)s4$m4C9}e-_EEmB>2Jmu3HwV`GnDfpm$cEQ>5uKZldy9Pdl&10mI6F zG$VGR8LK>q&{j57I4C=U4KWjG!29+8Tn8*7WGc$T+ASNfx(d zcx?{TQJxD%TvM*hrM}w2)IbsUnZ2}rW}y@2;(|D;0XaEg!N_#biM#t)$>DuOHnZIS zy5gSEP@0U8?K}mW?~~)V=PRXOEz@$U+fayte_xMC55*a}4kd00y2z%NXnHqu@J!WvH}WTE z3VHI=Dyru;T_jWt^eOj~T0I+K)Z#aU{=R;=9Ww4r5)bAN#&l!(xGCta%pAuA(Rm5J zNQNeZ5TRj<-27?P@>zNY+)u3XpPDKGFa)sQGXzGPv4D2L>F;ZRI~b~WO17Hhbvx1w z=ugR(oA}e6U<}r@=>#_RHyi2i_Tl6QdQH>yR&f;p9`Dz#Pm}ZWchk2U_$9mUfB|HP zMPFTJ8V~{rg83c9gv^-#-^bg!oT1L@GS_uw(ZSLDca-$y2UhuZxHGE+T8Z%Kcc)1v zGyD671jN08SLanu+VM`O=3HOD+q)kmIJJNM7+VJNuifTlr>*g|Ni4tuEA-pUphE0U zfKhnLhjFRtJ62RMF*bJhXT-*UQ1A_;d6d=C>bKksX3hU^lY(M`t&8ww67e1SONX4S zJe{)T`6fXN^PC%eEU8rQO+nXzSENNLfd&og=%j>rbPvtY36FnS(7!h!w0MY4ECO8E zA`f*=ZE#yXVY@n3BlpoypNA6yZ|El7Mfk6TLW!%JqDtbhGU%YjgZ@^$_!a$I@5%c4 zz1|-R4pFfP#$l=WRs#tI7Wwn$kAhUqP}kGjXEPL=SJ_zhqR)>(*Kw-@vLjP#31 zzs&hPE803!lus*A!^zpYrFAd@77OCaBDxYQM}@3LF8E#rhLmsm-xjS<*5uh+5ubd* zOA(lm5j>>fseHW?$;UR76l=-vP;{(!7`Ly1_8~`Hg&;!#R-VLnlAXDAT7t{>el(+V zgn(Ga<@uT$26_^RCjR>{3xr+nJJi@6?a$9#w;&Myc|bz6p@z$LM}n872rN^mRFgl$!nPkk@CcragkNbRwTU}=fj(y|uchkD zaXP-ipDu@uTXCD4qA^+&xamNrP+BF+^`fXwhMq8%RK8;8Ept!DrfYR`<4!1L@BBc= zdgtar;=!qToII%(x1)Ra729r6m{sVqiSqaYc~hWA`*9>$4Groy+OSp)R%1KuH5i}K zGZ&$KO3+$=FP@hdlKjg@N%PoQS0=IKECR~4RKR83^fJ0S2z0q2Z zkRXCYtp)On`gS{RS13`<{-3sSAI5Fg$wogR;aFQ!k=WN0fnX%Xr#ljCtwWhO7WzIi zfeTw0FUMHDSG|d`Vk*BzvqICSkOX>SPDME4Bl0P02LC4n{By&hX0M$#Z4ZHV-lI(tfh`% zEAK;^WNJ*JPMMkb$n?kt!i|Q{d?Ct%OKlQYGoCV{ZmvAjN8Z{u=B@a=TzQdU9JDB- z5%D!PObI-NpC-Sn(#5AbeU-b8>F8NS>~5@`!8I8tDpaAawp;py9BiS;nk*zf!7e1D z@$A>oFP#e3E~G+Y>VCNMcJE2_LNX`wpYqA-+|+sUuaxKj>gdY83ej%MDRJNfSwB|+IM>L`*DqRB#Ovho7%Fa(aZw7bDYftJ95>PVq5}--9(Ab3h%FzZneQJMf^{>goksc zB!6rFO=#_2@zK_O+PlesHSfN+BqCrqnrnn~O#hqcC#4S_yeTsMoueT~7AYW|iyULC zV;F#}?K3nm%93ow?^5)OOz$hQ>8Dpr$pVF+){jx{1`>5DJoK>@_U6lDzsx8qaVGQ4 ztjjp)W_%uNpsMriDno&rch}U5yHB575ocJ0Xx)xS^LSns%~lR7TK7ax_o^vir*p%l z)+i;a{we+1Dc0r3^mKRq{-i42Txrgi3Y87J&}Bk#-`i{bo7$~pLUpqfO3<0!RD*--VWhFkVc-^qz8Y#!7oN3p7uX!hu z3(H@dT2$;?kd%WJ`Ub^ofeX9zLrtf?u^_YFzASR2wP&UQDj( z9Er{RkW=;CX~2h(P5zg5(40zVf2X*$I#l=)stH{QAH2v$4Q*dPNCcafN%xJ7LQNdT zU^#er&!v}|U?2L&_+!%1Ead3H=RDDFym_JC{0#Ol%<7xHZIiY5A*NV?ZL z`o%tok*KH>q&k%rh1kX~5;8x39=gAsh;(Rl{pQ=>-%2-a*ivMk+5*)G^uwhzF?=eI z{bwD6!t|1lR?aFM)3Qo6Uq)H(Ul{fkGMLbg>WiN&*tDYQ$~red=bTa{?pOCfOy@zQ4YO&f5w(p_g?Yj8_l=s z5J>l`$#i{wQrrGZHgjd5ZQVsWE9}Z$^rh6ww(3lvde^%4u{xUeCwOKRUJh*2DRC~L zFkF*C#yI}hs~^_>z}nq+KYqhdt zil;TY&Fh(8W3r8{hUk2@dTKu%r;FZ(4l%&O%P?MPpJ?9B>Ws-@2Izo$*P;tP64#XZ z)S~dxm-=G%3;^D6rBN$KQBLd+#|f! z;CZAe9YCksOa6DUygS_NC`BW>C+=0!oTXyk3*BHCTllxKuj|iqK6~FYAcqnEt;P8l zSfsD!iT{dvhzM+U6gPx%<3<~g8ARG}eDZKMgooE2ckj6hxi^-D87)f@)-23*SJLUY z94^6T`m4|V?-hmFZyD|la{^*!1reY<|AwOFSEgYO{_t_)IB~fx1p1cDha1EAI4Y+7@%x!dt2+x?_Ax2{d(<1Vi>R!;LfgS{Sd0bn(Y3r%K{S zMDCNc9$%8CVbtXJ#?#`T)VoR>+Oi1Gc&q0U>tB;333y8F9H)bSacjBKA~d=4KD)G8 z_tK|!x9?qH%_k8$V!`IKK_0xV9x2@fNOFnQTu+9p-6YQLVzMg?^9{1+GkKW%{I;V# zIaI%Te56%rV_t_QAbl877x}!DltWgi16}Zk!Ii^=WA7ic@WH*%SQhn4C#7G?1cKGh z!`zLb@)LrlY`4sevAm)?;IKbSn(HUT@66hf9_UHZ4``>{?H>Nt9j-GbOZ%Ofg1^r3 zAqj_wo2K2m%n6d=al|tBwVsAFyT{)cL_g!)7fIm`7b?-c87kvHy!x6v8bBT~mFDS;0K3ZT7o!DE{j7V!L>ms5JG)D2`s`)-Ho zB%y?b`3-5Gt?595D?lg1XIQ8F%Jc*Nmv>tgkH^O6SX@8R@hU6Dk=Mu>2=H(46|?lZ>El=@luOxhv` z|8T}Ok*ym1e_Zcco>_GbTr|z>>R9sfY_{3F#;Cc^lb&dMh?(QY-=WWpph@gQ!UJi+ z@0$t9zdZTWc3+HjGd`s6?d;9*%zS2dAKHQT6mP$C;0kP+r&n=cXnfCV$36g!vz~A&t zDfOota(Jd4vTJ7y+xh}v6dc)wHlQ* zVu*hWxyUNeG&^P|ynya&YZz$@6`-=u9iRk+X?>q5)17eajEaJcWWVAVSCzec9_-+F zQ?w>n=zIjqc=WLyem!fVx$AsT+>3Kb${JWk~Y>N z1o@oRR0RLdzI}cb#7~Rv&9-|%RII1(_8eB^Y7_JL9?}p+Jxf2Hg8+C>6Q4|holJ@A zV7kcskeFQtU5P|VddoatD}=I+XDQDH16w-qV{aG>g-DK9Co$J7D$ZLn)gvZW1Lc8X zSo0)^NfRdt+Nb=H)Wv$Q`5-abAkZzn%eFmkLz$)s_@v|xvpIvIB;4hSEbPx@LI!1f z7n8aFMIJ&S2?O6>X_WMQ>WwSbTZO$Sw>2>2bkqC*PIM&^Z(PnHSw=xO+3rerpA$8u zMX&vGXv5B$fkqb`Yw%%J^doI*(+BAyy89V(J?HRSTI+cy9`Rc(IV;k&+%R46?zilF}!Mc~+ zhLs)fjqI8Kk$ zCUcG3v{VFTLLsIwArZh0U$02b4C1XVk{3c89NFIf82jM^B%<>q&`duWs+%|)L8gWP zdg#IspSf{Rq8T*51!LquGdMCj+UZ|O*VZWDG@$}^^={_x)>Z#0+gdOHZGCHN4{39A zv%(uVm>oAt^PEBIq)$aeHUaERfN}ugP6XxRd;A!1LxWOUAgnzJMB^=YqhZhP8O}4> z4$az=aIR2gW#u^QaUDuiG>)3|Pr+%yksEioXwLJeMnQ6U4kVSLn!}j*joGB!;M!H~ z5HG6qm*aQI^FBT2|59@8z|Hg;@{jT~h)c4~DB@5(E;{j?&m`yfHOD>!qaabV0}_Jp)%4(U-Wfg>k&C_$ydyHfwz(QkOif9;+V@93L6 zn0`NR?)aX}KiM&|liK4HKShK=`NvHW5HB9X6iuTt>9=w$|_pp}; zdG)?ae|jlO0bvwALnJ1@54tjsqkUCxVdrXTC}1P|Sv`P@a`Hz)8c`~dOb09-U!Zmx zADg0#>7)AHNU#Qod7{P7jQTLDCDaFexK>9T zEjnwbr{&U?YrWC&L%FUiU*ngOtT6$%f`cnf<`XQEI0^HDowJZRv<*~jM-p5pN&=tk}oPzjfyT`lDJlFrf~>l{h#m5k-8C z)B&hK*#r1O+qd&fOiaKaEMY+00`wVQNg8l1fV!ac-DP9#1$t+y{$m+z1{A!)B;U&0WN;OgWO3K{e!-~Nd41q16FG{&& zLvjG3()TuLq$$P*3=n!MBs889l|mxiAnH|Wu=k{x^_8HN7ZyLmW>!TieY1*%bi+^qM zp-uVVXNXyZ@GdELoyif)N8JqKSp&|}tKy4lZQD6@=QoR9!bc4T?T}$tl5HWV1fNlh zTdo2wTk>3^1-{?NC$cug+7Ep|tdb1gqK}roKAF}Fk$W;&Un1B|B0zi!WZ-1{&X&L% zGM;BRWsP?AxRFrZC|4lZfvds&m^5fiwHYxG`YdFk=uxPDU{yNV9k#j_Rb2rb2_}RJy8kSJR6

*CyZKcay{9bKgqL?}7*Uud$$@piZUK(brlR&mD)# z_WgAzET53{3AFXMu9P5Z9gPuyOV^RoN|zui7UxmB_15{CUT|8Yk->L5+g78UGCPzZHO z9o9+qu6pMcVY66-V*=*=z;8EhoLW*YZVt2T+_<9e`_k=lOUN6gUG`K!?HWPbAsej`YaA{QMvcS+g{@YBAHg47H8mBjCLK6DY^hm<1{oLLWL_B{axO6zV zGo|xFn%;hAPUI~q`Z(3o3-g=oJ`K$uf4yq@dw0TA_1XJjOVO^%oH(DI!l0%-u&+e* z8FU**9e8!I%YDLc4p_L>q~fBrb>CC^S>q1mt!z9esOg`qkhlZ9CD5?@&FV{Ud9gnO z$U*?r^9V3VclW3$OhWr&0@uGT-mDXM9#vI0~; zA7AOS*H1ST7*swx>~nG2dfV7~Ta$Xm<9o`}Vi-a66LrpJO#JsdJ6p~7dRb;hkAJpO zn)xh65z$=MPgQi$@-Ph6isB3#o(=R+R1r7r8>nI=T0GB}b|oC3f4N}Re|MLxH*J5< z&>J7ManxLxaF#f)8sg@%|0@ z8NuDPHWjs=l>~H)WwY-maC`D-tHLIN^ZA)anm`e?Zv|i32BaL-jG-67x??yBJq;=f z*iV~qrel@Ru+Hz1k3;UlS__q%hJqbLzLb+9!Xr#nlSgEoSA$fmdR!LgB&Ac~0~z>So29jd(o897XyEq%*qFSc;%37}#y_1TDhoMW z2TMy!d3kv-=y7Co2h3*m;#`=b{pL+?h{GmhRXOuyYsZk5lKP6^39y)9VKmw1mGx$O zprfL8*L}j4@i=*fyS#eoCV^QoS-NyA@_2fDL~-5OXy^O)v{TrJ9`o@6dkMGvc2{mW zK4FfbyUN+v;ZZoI*;5mptmv&MlIQuV1avbGB=(^86-MH1g=2bo8TjmX5hrdHqMCp6 zRY-&?hs@r_ml@0!bn>*=!N4KjDQ{HF@|*bo9o-?&f))@mI*L$ zqTK0ogx{8CL zr@my{^YJ`X!N@i;)um9`r2EksBK*x<7T!N@vqjSN| zgxcWSFpJB)1S%74;d__|xWGk(TyWDc=4=EKvIwkY`9HlC@kiDad~m0hxZ5JMYr0h& zEXc+%MT7R53%nEXlIiX$H_PfaJ*T;l4$4orxUk5{=LwfaD|X+Btr0V-U*N$ z9v;?@E1zP#pYOZC+~hMrPfKJkEG-2zRtN~8K{DlY)k)!cFzW&+v3z`dEod4*ZHX4u zZt1+IFJ97ZQtx`83&6=Wa`UTT1n}=q>?bGP4}eIuC+RXXoc$v%&JEaAjmFF?Rj4EL zlv?dq;Df7>o9|d6F+^q$TqAfa&UK*PRGleGa{EFlLX(V)4qyrQkxyfJ>%=gkuw^*|y)30tLHJQzjK%&fUN%*2Hb<9DIAun+3 zcZvbG?rkr}`Dl{V5_Jy#dbC;|qMYghIm!7d%J6z_en>qm(#rqweNR0jGV5!YlGXsTFMN(upgr!OV4>&` zaV#2-KR-!5a-wowADyWt3n7L2D+EESG6RAiIE4X#ngyrQQcttv3^;{I2^%#KgP(%976{ zyOO%=zkp<79wW~6XfZi97Kz1A-Ca>$9u3%mUcQ_G5?3%Z5R;S_c%|VpPgZ*B|HcXn z(bI=S2zQEuzg0WQy$@(J*nF|HnW4d3E|TL1?wB1B63CZOz~S? zOW@Pv@~>(yRwjS{a1wFO+G4-PY^J=>`aU47>crI^l+W(dxi8uPzTXLV+V@C*!wa+} zi3zG1PG&P!#2H0LBGei8f8`rCQ5VUn2jHg!uKMT36a-gsBuaMi%RN;! zQR5#sNvca;TlGz^pO{7NoBHM*ElE$r#~NL{UR5Ns`b?O+UD?p0j{r}i=G2IL((l{i z2Y~qnHwY19?}BeHa+O-Z-sNIE9^{GZ)S@uU5%yM zDq=Dy@D&AJ1;Qv~{uAzPVwL;&y944Y$WN~}SbeW2N`1}&oZ#lX)K>@~dTqPwX)hfH zY&89(y1-=jc7(1^ugRaI3_3{q{RW9F9PyiON}sO*q#LK`CFA~0uipTK_u(t*Tw+XP zQA=VDvP5k1te3+bCcHd{g(okAa6>$;6JXDHlC0$5qIc``j$p9-5!+hBM%OU&Q5Id4 zHMM+!X&esEwog=)*0U}S(=d?}?LJDoj@nrbL;5CZH#uLs4YkRH>spX>O1GXL_UU_hX+! zHpvo0xl37R>n9YaEm{OUxpRy3cmCE>eI{S)C++4_c>9v$t9oPF5GauZ@Y_1`Jtrgl zJSeX=ENDe#yHw(Og~e4S?4-MMMxU+r_NT+2KiS>Ne7r>nPPD5A6dJ{P1rWn`wV$BM zuVxUA+gDhTDwGQK%(4?fYcmht&V4d4YcR>+&jaa{>iE?X1+;MNB|GINceD$S#((LS zs6-0*B=oejdNqjg@XnMT&y;{2$F22WOetLV(#>Qo;7IlyuxXV>nA%pN*i&)$2%&qV zQFw})Vnw_Ym18x3fd%G%Z?McpNEA_w2GOhxN{OGpAi-RIa}HlK+j&oIQaLlAI9no} zn)q!{hMh0>8v14NHn5$7%j5Oq{^xOKfqYIXs;{_5tADVo6@cMKwfHCO9E(zq!1pf> znQ_RXUC8GQBRIQ``sFu>@^asJ)KqcDGsnZANY#p@%<|tjIzxKZP|r_?50L=12>D&* zs5)FjYyc4l*0*0@1$Zn2+oRV889H+O-w<6|q@Va+WSKPo?A*MfbHVGHv|{8D5s?s! z_OncgNR^uU#=lm8Nb>DANw*=AR5i;fCdS-xxGj5li>hBG=YD75i0T) z)Ik43A^~PkPgn=+SLIT$?PWcCI1Cjwpk?d$2cB^>$NSwVED7HjP&EML-^b19LJ&(LApIg!vS zDk%k{&!iC?|KUY}gIC)hVIA#oo~J$K;O9>ehsx_XQN=X0UhjEQA*o#3_lTquSM^C( z*%HUzt!I*;Z0g|@26tSW)_Yx7_+S!aN&sncW-7$hHzFRb40#KHJ^-~b=Oq-rWDcj? z$1PqkD<`L8R;mXK?8_$(mXLJ$WFS&pjLw@785xavz#SIlbV{

(5P?9ke}KoxP57yqO4TJ6DM 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

, Vec) { // Read ELF params only if token_mint or chain_id is not set. @@ -118,26 +95,26 @@ pub(crate) async fn parse_emulation_params( fn process_result( result: &NeonApiResult, -) -> (StatusCode, Json) { +) -> (Json, StatusCode) { match result { Ok(value) => ( - StatusCode::OK, Json(json!({ "result": "success", "value": value, })), + StatusCode::OK, ), Err(e) => process_error(StatusCode::INTERNAL_SERVER_ERROR, &e.0), } } -fn process_error(status_code: StatusCode, e: &NeonError) -> (StatusCode, Json) { +fn process_error(status_code: StatusCode, e: &NeonError) -> (Json, StatusCode) { error!("NeonError: {e}"); ( - status_code, Json(json!({ "result": "error", "error": e.to_string(), })), + status_code, ) } diff --git a/evm_loader/api/src/api_server/handlers/trace.rs b/evm_loader/api/src/api_server/handlers/trace.rs index 43cbf8403..d53d552de 100644 --- a/evm_loader/api/src/api_server/handlers/trace.rs +++ b/evm_loader/api/src/api_server/handlers/trace.rs @@ -1,4 +1,5 @@ -use axum::{http::StatusCode, Json}; +use actix_request_identifier::RequestId; +use actix_web::{http::StatusCode, post, web::Json, Responder}; use std::convert::Into; use crate::api_server::handlers::process_error; @@ -9,11 +10,13 @@ use crate::{ use super::{parse_emulation_params, process_result}; -#[tracing::instrument(skip(state))] +#[tracing::instrument(skip(state, request_id), fields(id = request_id.as_str()))] +#[post("/trace")] pub async fn trace( - axum::extract::State(state): axum::extract::State, + state: NeonApiState, + request_id: RequestId, Json(trace_request): Json, -) -> (StatusCode, Json) { +) -> impl Responder { let tx = trace_request.emulate_request.tx_params.into(); let rpc_client = @@ -22,7 +25,7 @@ pub async fn trace( Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; - let context = Context::new(rpc_client, state.config.clone()); + let context = Context::new(&*rpc_client, &state.config); let (token, chain, steps, accounts, solana_accounts) = parse_emulation_params( &state.config, @@ -33,7 +36,7 @@ pub async fn trace( process_result( &trace_transaction( - context.rpc_client.as_ref(), + context.rpc_client, state.config.evm_loader, tx, token, diff --git a/evm_loader/api/src/api_server/mod.rs b/evm_loader/api/src/api_server/mod.rs index 9b94b34ed..53b4478d2 100644 --- a/evm_loader/api/src/api_server/mod.rs +++ b/evm_loader/api/src/api_server/mod.rs @@ -1,3 +1,2 @@ pub mod handlers; -pub mod routes; pub mod state; diff --git a/evm_loader/api/src/api_server/routes.rs b/evm_loader/api/src/api_server/routes.rs deleted file mode 100644 index 1b9a31457..000000000 --- a/evm_loader/api/src/api_server/routes.rs +++ /dev/null @@ -1,25 +0,0 @@ -use axum::{ - routing::{get, post}, - Router, -}; -use tower::ServiceBuilder; - -// use evm_loader::types::Address; -use crate::{ - api_server::handlers::{ - build_info::build_info, emulate::emulate, get_ether_account_data::get_ether_account_data, - get_storage_at::get_storage_at, trace::trace, - }, - NeonApiState, -}; - -pub fn register() -> Router { - ServiceBuilder::new().service::>( - Router::new() - .route("/emulate", post(emulate)) // Obsolete - .route("/get-storage-at", get(get_storage_at)) - .route("/get-ether-account-data", get(get_ether_account_data)) - .route("/trace", post(trace)) - .route("/build-info", get(build_info)), - ) -} diff --git a/evm_loader/api/src/api_server/state.rs b/evm_loader/api/src/api_server/state.rs index 1b49fe103..1205a9b00 100644 --- a/evm_loader/api/src/api_server/state.rs +++ b/evm_loader/api/src/api_server/state.rs @@ -3,11 +3,10 @@ use neon_lib::types::TracerDb; use solana_client::nonblocking::rpc_client::RpcClient; use std::sync::Arc; -#[derive(Clone)] pub struct State { pub tracer_db: TracerDb, pub rpc_client: Arc, - pub config: Arc, + pub config: Config, } impl State { @@ -19,7 +18,7 @@ impl State { config.json_rpc_url.clone(), config.commitment, )), - config: Arc::new(config), + config, } } } diff --git a/evm_loader/api/src/main.rs b/evm_loader/api/src/main.rs index d9091abc8..fd0fad5a4 100644 --- a/evm_loader/api/src/main.rs +++ b/evm_loader/api/src/main.rs @@ -1,4 +1,3 @@ -#![allow(dead_code)] #![deny(warnings)] #![deny(clippy::all, clippy::pedantic)] mod api_context; @@ -7,35 +6,35 @@ mod api_server; #[allow(clippy::module_name_repetitions)] mod build_info; +use actix_web::web; +use actix_web::App; +use actix_web::HttpServer; use api_server::handlers::NeonApiError; -use axum::Router; -pub use neon_lib::account_storage; pub use neon_lib::commands; pub use neon_lib::config; pub use neon_lib::context; pub use neon_lib::errors; -pub use neon_lib::rpc; -pub use neon_lib::syscall_stubs; pub use neon_lib::types; use tracing_appender::non_blocking::NonBlockingBuilder; -use std::sync::Arc; +use actix_request_identifier::RequestIdentifier; +use actix_web::web::Data; use std::{env, net::SocketAddr, str::FromStr}; +use crate::api_server::handlers::build_info::build_info_route; +use crate::api_server::handlers::emulate::emulate; +use crate::api_server::handlers::get_ether_account_data::get_ether_account_data; +use crate::api_server::handlers::get_storage_at::get_storage_at; +use crate::api_server::handlers::trace::trace; use crate::build_info::get_build_info; pub use config::Config; pub use context::Context; -use http::Request; -use hyper::Body; -use tokio::signal::{self}; -use tower_http::trace::TraceLayer; -use tower_request_id::{RequestId, RequestIdLayer}; -use tracing::{info, info_span}; +use tracing::info; type NeonApiResult = Result; -type NeonApiState = Arc; +type NeonApiState = Data; -#[tokio::main(flavor = "multi_thread", worker_threads = 512)] +#[actix_web::main] async fn main() -> NeonApiResult<()> { let options = api_options::parse(); @@ -44,10 +43,7 @@ async fn main() -> NeonApiResult<()> { .lossy(false) .finish(std::io::stdout()); - tracing_subscriber::fmt() - .with_thread_ids(true) - .with_writer(non_blocking) - .init(); + tracing_subscriber::fmt().with_writer(non_blocking).init(); info!("{}", get_build_info()); @@ -55,29 +51,7 @@ async fn main() -> NeonApiResult<()> { let config = config::create_from_api_config(&api_config)?; - let state: NeonApiState = Arc::new(api_server::state::State::new(config)); - - let app = Router::new() - .nest("/api", api_server::routes::register()) - .with_state(state) - .layer( - // Let's create a tracing span for each request - TraceLayer::new_for_http().make_span_with(|request: &Request| { - // We get the request id from the extensions - let request_id = request - .extensions() - .get::() - .map_or_else(|| "unknown".into(), ToString::to_string); - // And then we put it along with other information into the `request` span - info_span!( - "request", - id = %request_id, - ) - }), - ) - // This layer creates a new id for each request and puts it into the request extensions. - // Note that it should be added after the Trace layer. - .layer(RequestIdLayer); + let state: NeonApiState = Data::new(api_server::state::State::new(config)); let listener_addr = options .value_of("host") @@ -89,37 +63,23 @@ async fn main() -> NeonApiResult<()> { let addr = SocketAddr::from_str(listener_addr.as_str())?; tracing::info!("listening on {}", addr); - axum::Server::bind(&addr) - .serve(app.into_make_service()) - .with_graceful_shutdown(shutdown_signal()) - .await - .unwrap(); + HttpServer::new(move || { + App::new().service( + web::scope("/api") + .app_data(state.clone()) + .service(build_info_route) + .service(emulate) + .service(get_ether_account_data) + .service(get_storage_at) + .service(trace) + .wrap(RequestIdentifier::with_uuid()), + ) + }) + .bind(addr) + .unwrap() + .run() + .await + .unwrap(); Ok(()) } - -async fn shutdown_signal() { - let ctrl_c = async { - signal::ctrl_c() - .await - .expect("failed to install Ctrl+C handler"); - }; - - #[cfg(unix)] - let terminate = async { - signal::unix::signal(signal::unix::SignalKind::terminate()) - .expect("failed to install signal handler") - .recv() - .await; - }; - - #[cfg(not(unix))] - let terminate = std::future::pending::<()>(); - - tokio::select! { - _ = ctrl_c => {}, - _ = terminate => {}, - } - - println!("signal received, starting graceful shutdown"); -} diff --git a/evm_loader/cli/src/config.rs b/evm_loader/cli/src/config.rs index 6d3382ce9..5ed698eb0 100644 --- a/evm_loader/cli/src/config.rs +++ b/evm_loader/cli/src/config.rs @@ -6,7 +6,7 @@ use solana_clap_utils::{ keypair::keypair_from_path, }; use solana_sdk::commitment_config::CommitmentConfig; -use std::{str::FromStr, sync::Arc}; +use std::str::FromStr; /// # Panics /// # Errors @@ -43,8 +43,7 @@ pub fn create(options: &ArgMatches) -> Result { "fee_payer", true, ) - .ok() - .map(Arc::new); + .ok(); let db_config = options .value_of("db_config") diff --git a/evm_loader/cli/src/main.rs b/evm_loader/cli/src/main.rs index 2b7d4ee5c..615ce4419 100644 --- a/evm_loader/cli/src/main.rs +++ b/evm_loader/cli/src/main.rs @@ -13,7 +13,7 @@ use neon_lib::{ get_ether_account_data, get_neon_elf, get_neon_elf::CachedElfParams, get_storage_at, init_environment, trace, }, - errors, + errors, rpc, types::{self, AccessListItem}, Context, }; @@ -30,15 +30,18 @@ use solana_clap_utils::input_parsers::{pubkey_of, value_of, values_of}; use solana_client::nonblocking::rpc_client::RpcClient; use solana_sdk::pubkey::Pubkey; use std::str::FromStr; -use std::sync::Arc; use tokio::time::Instant; +pub use neon_lib::context::*; +use neon_lib::rpc::CallDbClient; + use crate::build_info::get_build_info; use crate::{ errors::NeonError, types::{TransactionParams, TxParams}, }; use evm_loader::types::Address; +use neon_lib::types::TracerDb; type NeonCliResult = Result; @@ -46,9 +49,27 @@ async fn run<'a>(options: &'a ArgMatches<'a>) -> NeonCliResult { let slot: Option = options .value_of("slot") .map(|slot_str| slot_str.parse().expect("slot parse error")); + + let config = config::create(options)?; + let (cmd, params) = options.subcommand(); - let config = Arc::new(config::create(options)?); - let context = Context::new_from_config(config.clone(), slot).await?; + + let rpc_client: Box = if let Some(slot) = slot { + Box::new( + CallDbClient::new( + TracerDb::new(config.db_config.as_ref().expect("db-config not found")), + slot, + ) + .await?, + ) + } else { + Box::new(RpcClient::new_with_commitment( + config.json_rpc_url.clone(), + config.commitment, + )) + }; + + let context = Context::new(&*rpc_client, &config); execute(cmd, params, &config, &context).await } @@ -75,7 +96,7 @@ fn print_result(result: &NeonCliResult) { println!("{}", serde_json::to_string_pretty(&result).unwrap()); } -#[tokio::main] +#[tokio::main(flavor = "current_thread")] async fn main() { let time_start = Instant::now(); @@ -104,7 +125,7 @@ async fn execute<'a>( cmd: &str, params: Option<&'a ArgMatches<'a>>, config: &'a Config, - context: &'a Context, + context: &'a Context<'_>, ) -> NeonCliResult { match (cmd, params) { ("emulate", Some(params)) => { @@ -112,7 +133,7 @@ async fn execute<'a>( let (token, chain, steps, accounts, solana_accounts) = parse_tx_params(config, context, params).await; emulate::execute( - context.rpc_client.as_ref(), + context.rpc_client, config.evm_loader, tx, token, @@ -132,7 +153,7 @@ async fn execute<'a>( let (token, chain, steps, accounts, solana_accounts) = parse_tx_params(config, context, params).await; trace::trace_transaction( - context.rpc_client.as_ref(), + context.rpc_client, config.evm_loader, tx, token, @@ -182,7 +203,7 @@ async fn execute<'a>( } ("get-ether-account-data", Some(params)) => { let ether = address_of(params, "ether").expect("ether parse error"); - get_ether_account_data::execute(context.rpc_client.as_ref(), &config.evm_loader, ðer) + get_ether_account_data::execute(context.rpc_client, &config.evm_loader, ðer) .await .map(|result| json!(result)) } @@ -190,7 +211,7 @@ async fn execute<'a>( let storage_account = pubkey_of(params, "storage_account").expect("storage_account parse error"); cancel_trx::execute( - context.rpc_client.as_ref(), + context.rpc_client, context.signer()?.as_ref(), config.evm_loader, &storage_account, @@ -219,14 +240,9 @@ async fn execute<'a>( ("get-storage-at", Some(params)) => { let contract_id = address_of(params, "contract_id").expect("contract_it parse error"); let index = u256_of(params, "index").expect("index parse error"); - get_storage_at::execute( - context.rpc_client.as_ref(), - &config.evm_loader, - contract_id, - &index, - ) - .await - .map(|hash| json!(hex::encode(hash.0))) + get_storage_at::execute(context.rpc_client, &config.evm_loader, contract_id, &index) + .await + .map(|hash| json!(hex::encode(hash.0))) } _ => unreachable!(), } @@ -268,7 +284,7 @@ fn parse_tx(params: &ArgMatches) -> (TxParams, TraceCallConfig) { pub async fn parse_tx_params<'a>( config: &Config, - context: &Context, + context: &Context<'_>, params: &'a ArgMatches<'a>, ) -> (Pubkey, u64, u64, Vec
, Vec) { // Read ELF params only if token_mint or chain_id is not set. diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index bc9cc62d2..c193af9cf 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" thiserror = "1.0" anyhow = "1.0" bincode = "1.3.1" -evm-loader = { path = "../program", default-features = false, features = ["log", "tracing"] } +evm-loader = { path = "../program", default-features = false, features = ["log", "async-trait", "serde_json"] } solana-sdk = "=1.16.14" solana-client = "=1.16.14" solana-clap-utils = "=1.16.14" @@ -28,11 +28,9 @@ ethnum = { version = "1.4", default-features = false, features = ["serde"] } goblin = { version = "0.6.0" } scroll = "0.11.0" tokio = { version = "1", features = ["full"] } -lazy_static = "1.4" clickhouse = "0.11.5" tracing = "0.1" -async-trait = "0.1.68" -axum = "0.6" +async-trait = "0.1.73" build-info = "0.0.31" [build-dependencies] diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index 8dcb3980a..9467cd9b9 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -1,5 +1,5 @@ +use async_trait::async_trait; use std::{cell::RefCell, collections::HashMap, convert::TryInto, rc::Rc}; -use tokio::sync::RwLock; use crate::{rpc::Rpc, NeonError}; use ethnum::U256; @@ -31,7 +31,7 @@ use solana_sdk::{ sysvar::{slot_hashes, Sysvar}, }; -use crate::types::{block, PubkeyBase58}; +use crate::types::PubkeyBase58; const FAKE_OPERATOR: Pubkey = pubkey!("neonoperator1111111111111111111111111111111"); @@ -109,8 +109,8 @@ pub struct SolanaAccount { #[allow(clippy::module_name_repetitions)] pub struct EmulatorAccountStorage<'a> { - pub accounts: RwLock>, - pub solana_accounts: RwLock>, + pub accounts: RefCell>, + pub solana_accounts: RefCell>, rpc_client: &'a dyn Rpc, evm_loader: Pubkey, block_number: u64, @@ -150,8 +150,8 @@ impl<'a> EmulatorAccountStorage<'a> { }; Ok(Self { - accounts: RwLock::new(HashMap::new()), - solana_accounts: RwLock::new(HashMap::new()), + accounts: RefCell::new(HashMap::new()), + solana_accounts: RefCell::new(HashMap::new()), rpc_client, evm_loader, block_number, @@ -208,16 +208,15 @@ impl<'a> EmulatorAccountStorage<'a> { .iter() .zip(accounts.iter().take(addresses.len())) .zip(pubkeys.iter().take(addresses.len())); - let mut accounts_storage = self.accounts.write().await; for ((&address, account), &pubkey) in entries { - accounts_storage.insert( + self.accounts.borrow_mut().insert( address, NeonAccount::new(address, pubkey, account.clone(), false), ); } let entries = accounts.iter().skip(addresses.len()).zip(solana_accounts); - let mut solana_accounts_storage = self.solana_accounts.write().await; + let mut solana_accounts_storage = self.solana_accounts.borrow_mut(); for (account, &pubkey) in entries { solana_accounts_storage.insert( pubkey, @@ -232,9 +231,7 @@ impl<'a> EmulatorAccountStorage<'a> { } pub async fn get_account(&self, pubkey: &Pubkey) -> client_error::Result> { - let mut accounts = self.solana_accounts.write().await; - - if let Some(account) = accounts.get(pubkey) { + if let Some(account) = self.solana_accounts.borrow().get(pubkey) { if let Some(ref data) = account.data { return Ok(Some(data.clone())); } @@ -245,7 +242,8 @@ impl<'a> EmulatorAccountStorage<'a> { .get_account_with_commitment(pubkey, self.commitment) .await?; - accounts + self.solana_accounts + .borrow_mut() .entry(*pubkey) .and_modify(|a| a.data = result.value.clone()) .or_insert(SolanaAccount { @@ -279,19 +277,17 @@ impl<'a> EmulatorAccountStorage<'a> { } async fn add_ethereum_account(&self, address: &Address, writable: bool) -> bool { - let mut accounts = self.accounts.write().await; - - if let Some(ref mut account) = accounts.get_mut(address) { + if let Some(ref mut account) = self.accounts.borrow_mut().get_mut(address) { account.writable |= writable; - true - } else { - let account = - NeonAccount::rpc_load(self.rpc_client, &self.evm_loader, *address, writable).await; - accounts.insert(*address, account); - - false + return true; } + + let account = + NeonAccount::rpc_load(self.rpc_client, &self.evm_loader, *address, writable).await; + self.accounts.borrow_mut().insert(*address, account); + + false } async fn add_solana_account(&self, pubkey: Pubkey, is_writable: bool) { @@ -303,7 +299,7 @@ impl<'a> EmulatorAccountStorage<'a> { return; } - let mut solana_accounts = self.solana_accounts.write().await; + let mut solana_accounts = self.solana_accounts.borrow_mut(); let account = SolanaAccount { pubkey: pubkey.into(), @@ -361,7 +357,7 @@ impl<'a> EmulatorAccountStorage<'a> { self.add_solana_account(*storage_account.pubkey(), true) .await; - if self.storage(address, index) == [0_u8; 32] { + if self.storage(address, index).await == [0_u8; 32] { let metadata_size = EthereumStorage::SIZE; let element_size = 1 + std::mem::size_of_val(value); @@ -414,7 +410,7 @@ impl<'a> EmulatorAccountStorage<'a> { let mut iterations = 0_usize; - let mut accounts = self.accounts.write().await; + let mut accounts = self.accounts.borrow_mut(); for (address, operation) in operations { let new_size = match operation { AccountOperation::Create { space } => space, @@ -443,7 +439,7 @@ impl<'a> EmulatorAccountStorage<'a> { { self.add_ethereum_account(address, false).await; - let mut accounts = self.accounts.write().await; + let mut accounts = self.accounts.borrow_mut(); let solana_account = accounts.get_mut(address).expect("get account error"); if let Some(account_data) = &mut solana_account.data { @@ -469,7 +465,7 @@ impl<'a> EmulatorAccountStorage<'a> { { self.add_ethereum_account(address, false).await; - let mut accounts = self.accounts.write().await; + let mut accounts = self.accounts.borrow_mut(); let solana_account = accounts.get_mut(address).expect("get account error"); if let Some(account_data) = &mut solana_account.data { @@ -485,6 +481,7 @@ impl<'a> EmulatorAccountStorage<'a> { } } +#[async_trait(?Send)] impl<'a> AccountStorage for EmulatorAccountStorage<'a> { fn neon_token_mint(&self) -> &Pubkey { info!("neon_token_mint"); @@ -511,12 +508,12 @@ impl<'a> AccountStorage for EmulatorAccountStorage<'a> { self.block_timestamp.try_into().unwrap() } - fn block_hash(&self, slot: u64) -> [u8; 32] { + async fn block_hash(&self, slot: u64) -> [u8; 32] { info!("block_hash {slot}"); - block(self.add_solana_account(slot_hashes::ID, false)); + self.add_solana_account(slot_hashes::ID, false).await; - if let Ok(Some(slot_hashes_account)) = block(self.get_account(&slot_hashes::ID)) { + if let Ok(Some(slot_hashes_account)) = self.get_account(&slot_hashes::ID).await { let slot_hashes_data = slot_hashes_account.data.as_slice(); find_slot_hash(slot, slot_hashes_data) } else { @@ -524,82 +521,87 @@ impl<'a> AccountStorage for EmulatorAccountStorage<'a> { } } - fn exists(&self, address: &Address) -> bool { + async fn exists(&self, address: &Address) -> bool { info!("exists {address}"); - block(self.add_ethereum_account(address, false)); + self.add_ethereum_account(address, false).await; - let accounts = block(self.accounts.read()); + let accounts = self.accounts.borrow(); accounts.contains_key(address) } - fn nonce(&self, address: &Address) -> u64 { + async fn nonce(&self, address: &Address) -> u64 { info!("nonce {address}"); - block(self.ethereum_account_map_or(address, 0_u64, |a| a.trx_count)) + self.ethereum_account_map_or(address, 0_u64, |a| a.trx_count) + .await } - fn balance(&self, address: &Address) -> U256 { + async fn balance(&self, address: &Address) -> U256 { info!("balance {address}"); - block(self.ethereum_account_map_or(address, U256::ZERO, |a| a.balance)) + self.ethereum_account_map_or(address, U256::ZERO, |a| a.balance) + .await } - fn code_size(&self, address: &Address) -> usize { + async fn code_size(&self, address: &Address) -> usize { info!("code_size {address}"); - block(self.ethereum_account_map_or(address, 0, |a| a.code_size as usize)) + self.ethereum_account_map_or(address, 0, |a| a.code_size as usize) + .await } - fn code_hash(&self, address: &Address) -> [u8; 32] { + async fn code_hash(&self, address: &Address) -> [u8; 32] { use solana_sdk::keccak::hash; info!("code_hash {address}"); // https://eips.ethereum.org/EIPS/eip-1052 // https://eips.ethereum.org/EIPS/eip-161 - let is_non_existent_account = block(self.ethereum_account_map_or(address, true, |a| { - a.trx_count == 0 && a.balance == 0 && a.code_size == 0 - })); + let is_non_existent_account = self + .ethereum_account_map_or(address, true, |a| { + a.trx_count == 0 && a.balance == 0 && a.code_size == 0 + }) + .await; if is_non_existent_account { return <[u8; 32]>::default(); } // return empty hash(&[]) as a default value, or code's hash if contract exists - block( - self.ethereum_contract_map_or(address, hash(&[]).to_bytes(), |c| { - hash(&c.code()).to_bytes() - }), - ) + self.ethereum_contract_map_or(address, hash(&[]).to_bytes(), |c| { + hash(&c.code()).to_bytes() + }) + .await } - fn code(&self, address: &Address) -> evm_loader::evm::Buffer { + async fn code(&self, address: &Address) -> evm_loader::evm::Buffer { use evm_loader::evm::Buffer; info!("code {address}"); - block( - self.ethereum_contract_map_or(address, Buffer::empty(), |c| { - self.state_overrides - .as_ref() - .and_then(|account_overrides| account_overrides.get(address)?.code.as_ref()) - .map_or_else( - || Buffer::from_slice(&c.code()), - |code| Buffer::from_slice(&code.0), - ) - }), - ) + self.ethereum_contract_map_or(address, Buffer::empty(), |c| { + self.state_overrides + .as_ref() + .and_then(|account_overrides| account_overrides.get(address)?.code.as_ref()) + .map_or_else( + || Buffer::from_slice(&c.code()), + |code| Buffer::from_slice(&code.0), + ) + }) + .await } - fn generation(&self, address: &Address) -> u32 { - let value = block(self.ethereum_account_map_or(address, 0_u32, |c| c.generation)); + async fn generation(&self, address: &Address) -> u32 { + let value = self + .ethereum_account_map_or(address, 0_u32, |c| c.generation) + .await; info!("account generation {address} - {value}"); value } - fn storage(&self, address: &Address, index: &U256) -> [u8; 32] { + async fn storage(&self, address: &Address, index: &U256) -> [u8; 32] { if let Some(account_overrides) = &self.state_overrides { if let Some(account_override) = account_overrides.get(address) { match (&account_override.state, &account_override.state_diff) { @@ -623,11 +625,10 @@ impl<'a> AccountStorage for EmulatorAccountStorage<'a> { } let value = if *index < U256::from(STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT) { let index: usize = index.as_usize() * 32; - block( - self.ethereum_contract_map_or(address, <[u8; 32]>::default(), |c| { - c.storage()[index..index + 32].try_into().unwrap() - }), - ) + self.ethereum_contract_map_or(address, <[u8; 32]>::default(), |c| { + c.storage()[index..index + 32].try_into().unwrap() + }) + .await } else { let subindex = (index & 0xFF).as_u8(); let index = index & !U256::new(0xFF); @@ -635,9 +636,12 @@ impl<'a> AccountStorage for EmulatorAccountStorage<'a> { let (base, _) = address.find_solana_address(self.program_id()); let storage_address = EthereumStorageAddress::new(self.program_id(), &base, &index); - block(self.add_solana_account(*storage_address.pubkey(), false)); + self.add_solana_account(*storage_address.pubkey(), false) + .await; - let rpc_response = block(self.get_account(storage_address.pubkey())) + let rpc_response = self + .get_account(storage_address.pubkey()) + .await .expect("Error querying account from Solana"); if let Some(mut account) = rpc_response { @@ -650,7 +654,7 @@ impl<'a> AccountStorage for EmulatorAccountStorage<'a> { .expect("EthereumAccount ctor error"); if (storage.address != *address) || (storage.index != index) - || (storage.generation != self.generation(address)) + || (storage.generation != self.generation(address).await) { debug!("storage collision"); <[u8; 32]>::default() @@ -669,8 +673,9 @@ impl<'a> AccountStorage for EmulatorAccountStorage<'a> { value } - fn solana_account_space(&self, address: &Address) -> Option { - block(self.ethereum_account_map_or(address, None, |account| Some(account.info.data_len()))) + async fn solana_account_space(&self, address: &Address) -> Option { + self.ethereum_account_map_or(address, None, |account| Some(account.info.data_len())) + .await } fn chain_id(&self) -> u64 { @@ -679,7 +684,7 @@ impl<'a> AccountStorage for EmulatorAccountStorage<'a> { self.chain_id } - fn clone_solana_account(&self, address: &Pubkey) -> OwnedAccountInfo { + async fn clone_solana_account(&self, address: &Pubkey) -> OwnedAccountInfo { info!("clone_solana_account {}", address); if address == &FAKE_OPERATOR { @@ -694,9 +699,11 @@ impl<'a> AccountStorage for EmulatorAccountStorage<'a> { rent_epoch: 0, } } else { - block(self.add_solana_account(*address, false)); + self.add_solana_account(*address, false).await; - let mut account = block(self.get_account(address)) + let mut account = self + .get_account(address) + .await .unwrap_or_default() .unwrap_or_default(); let info = account_info(address, &mut account); @@ -705,13 +712,15 @@ impl<'a> AccountStorage for EmulatorAccountStorage<'a> { } } - fn map_solana_account(&self, address: &Pubkey, action: F) -> R + async fn map_solana_account(&self, address: &Pubkey, action: F) -> R where F: FnOnce(&AccountInfo) -> R, { - block(self.add_solana_account(*address, false)); + self.add_solana_account(*address, false).await; - let mut account = block(self.get_account(address)) + let mut account = self + .get_account(address) + .await .unwrap_or_default() .unwrap_or_default(); let info = account_info(address, &mut account); diff --git a/evm_loader/lib/src/commands/collect_treasury.rs b/evm_loader/lib/src/commands/collect_treasury.rs index 7e2dcd0de..ad9130c0b 100644 --- a/evm_loader/lib/src/commands/collect_treasury.rs +++ b/evm_loader/lib/src/commands/collect_treasury.rs @@ -21,7 +21,7 @@ pub struct CollectTreasuryReturn { pub balance: u64, } -pub async fn execute(config: &Config, context: &Context) -> NeonResult { +pub async fn execute(config: &Config, context: &Context<'_>) -> NeonResult { let neon_params = read_elf_parameters_from_account(config, context).await?; let signer = context.signer()?; diff --git a/evm_loader/lib/src/commands/emulate.rs b/evm_loader/lib/src/commands/emulate.rs index 9a1a5b3a5..140f0c6bf 100644 --- a/evm_loader/lib/src/commands/emulate.rs +++ b/evm_loader/lib/src/commands/emulate.rs @@ -16,7 +16,7 @@ use evm_loader::{ types::{Address, Transaction}, }; -use crate::types::{block, TxParams}; +use crate::types::TxParams; use crate::{ account_storage::{EmulatorAccountStorage, NeonAccount, SolanaAccount}, errors::NeonError, @@ -138,11 +138,8 @@ pub async fn execute( None, ) .await?; - let accounts = block(storage.accounts.read()).values().cloned().collect(); - let solana_accounts = block(storage.solana_accounts.read()) - .values() - .cloned() - .collect(); + let accounts = storage.accounts.borrow().values().cloned().collect(); + let solana_accounts = storage.solana_accounts.borrow().values().cloned().collect(); Ok(EmulationResultWithAccounts { accounts, @@ -221,9 +218,10 @@ pub(crate) async fn emulate_trx<'a>( }) .collect(); evm_loader::types::TransactionPayload::AccessList(evm_loader::types::AccessListTx { - nonce: tx_params - .nonce - .unwrap_or_else(|| storage.nonce(&tx_params.from)), + nonce: match tx_params.nonce { + Some(nonce) => nonce, + None => storage.nonce(&tx_params.from).await, + }, gas_price: U256::ZERO, gas_limit: tx_params.gas_limit.unwrap_or(U256::MAX), target: tx_params.to, @@ -237,9 +235,10 @@ pub(crate) async fn emulate_trx<'a>( }) } else { evm_loader::types::TransactionPayload::Legacy(evm_loader::types::LegacyTx { - nonce: tx_params - .nonce - .unwrap_or_else(|| storage.nonce(&tx_params.from)), + nonce: match tx_params.nonce { + Some(nonce) => nonce, + None => storage.nonce(&tx_params.from).await, + }, gas_price: U256::ZERO, gas_limit: tx_params.gas_limit.unwrap_or(U256::MAX), target: tx_params.to, @@ -260,9 +259,9 @@ pub(crate) async fn emulate_trx<'a>( signed_hash: <[u8; 32]>::default(), }; - let mut evm = Machine::new(&mut trx, tx_params.from, &mut backend, tracer)?; + let mut evm = Machine::new(&mut trx, tx_params.from, &mut backend, tracer).await?; - let (result, steps_executed) = evm.execute(step_limit, &mut backend)?; + let (result, steps_executed) = evm.execute(step_limit, &mut backend).await?; if result == ExitStatus::StepLimit { return Err(NeonError::TooManySteps); } @@ -274,13 +273,13 @@ pub(crate) async fn emulate_trx<'a>( debug!("Execute done, result={exit_status:?}"); debug!("{steps_executed} steps executed"); - let accounts_operations = storage.calc_accounts_operations(&actions); + let accounts_operations = storage.calc_accounts_operations(&actions).await; let max_iterations = (steps_executed + (EVM_STEPS_MIN - 1)) / EVM_STEPS_MIN; let steps_gas = max_iterations * (LAMPORTS_PER_SIGNATURE + PAYMENT_TO_TREASURE); let begin_end_gas = 2 * LAMPORTS_PER_SIGNATURE; - let actions_gas = block(storage.apply_actions(&actions)); - let accounts_gas = block(storage.apply_accounts_operations(accounts_operations)); + let actions_gas = storage.apply_actions(&actions).await; + let accounts_gas = storage.apply_accounts_operations(accounts_operations).await; info!("Gas - steps: {steps_gas}, actions: {actions_gas}, accounts: {accounts_gas}"); Ok(evm_loader::evm::tracing::EmulationResult { diff --git a/evm_loader/lib/src/commands/get_neon_elf.rs b/evm_loader/lib/src/commands/get_neon_elf.rs index 7e5f039d1..882a96a98 100644 --- a/evm_loader/lib/src/commands/get_neon_elf.rs +++ b/evm_loader/lib/src/commands/get_neon_elf.rs @@ -16,7 +16,7 @@ pub struct CachedElfParams { } impl CachedElfParams { - pub async fn new(config: &Config, context: &Context) -> Self { + pub async fn new(config: &Config, context: &Context<'_>) -> Self { Self { elf_params: read_elf_parameters_from_account(config, context) .await @@ -143,7 +143,7 @@ pub fn get_elf_parameter(data: &[u8], elf_parameter: &str) -> Result { pub async fn read_elf_parameters_from_account( config: &Config, - context: &Context, + context: &Context<'_>, ) -> Result { let (_, program_data) = read_program_data_from_account(config, context, &config.evm_loader).await?; @@ -152,7 +152,7 @@ pub async fn read_elf_parameters_from_account( pub async fn read_program_data_from_account( config: &Config, - context: &Context, + context: &Context<'_>, evm_loader: &Pubkey, ) -> Result<(Option, Vec), NeonError> { let account = context @@ -226,14 +226,14 @@ fn read_program_params_from_file( async fn read_program_params_from_account( config: &Config, - context: &Context, + context: &Context<'_>, ) -> NeonResult { read_elf_parameters_from_account(config, context).await } pub async fn execute( config: &Config, - context: &Context, + context: &Context<'_>, program_location: Option<&str>, ) -> NeonResult { if let Some(program_location) = program_location { diff --git a/evm_loader/lib/src/commands/get_storage_at.rs b/evm_loader/lib/src/commands/get_storage_at.rs index 44261324d..bd8f02632 100644 --- a/evm_loader/lib/src/commands/get_storage_at.rs +++ b/evm_loader/lib/src/commands/get_storage_at.rs @@ -15,7 +15,6 @@ use evm_loader::{ use crate::{ account_storage::{account_info, EmulatorAccountStorage}, rpc::Rpc, - types::block, NeonResult, }; @@ -52,7 +51,7 @@ pub async fn execute( let address = EthereumStorageAddress::new(evm_loader, account_data.info.key, &index); - if let Ok(mut account) = block(rpc_client.get_account(address.pubkey())) { + if let Ok(mut account) = rpc_client.get_account(address.pubkey()).await { if solana_sdk::system_program::check_id(&account.owner) { Default::default() } else { diff --git a/evm_loader/lib/src/commands/init_environment.rs b/evm_loader/lib/src/commands/init_environment.rs index 1c45090b9..018b2443d 100644 --- a/evm_loader/lib/src/commands/init_environment.rs +++ b/evm_loader/lib/src/commands/init_environment.rs @@ -1,4 +1,4 @@ -use std::sync::Arc; +use std::rc::Rc; use serde::{Deserialize, Serialize}; @@ -103,7 +103,7 @@ fn read_keys_dir(keys_dir: &str) -> Result, NeonError> #[allow(clippy::too_many_lines)] pub async fn execute( config: &Config, - context: &Context, + context: &Context<'_>, send_trx: bool, force: bool, keys_dir: Option<&str>, @@ -116,13 +116,13 @@ pub async fn execute( send_trx, force ); - let second_signer: Arc = Arc::from(context.signer()?); - let fee_payer = config - .fee_payer - .as_ref() - .map_or_else(move || second_signer, |v| v.clone()); - let executor = Arc::new(TransactionExecutor::new( - context.rpc_client.clone(), + let second_signer: &dyn Signer = &*context.signer()?; + let fee_payer: &dyn Signer = match config.fee_payer.as_ref() { + Some(fee_payer) => fee_payer, + None => second_signer, + }; + let executor = Rc::new(TransactionExecutor::new( + context.rpc_client, fee_payer, send_trx, )); @@ -329,13 +329,14 @@ pub async fn execute( executor.checkpoint(context.rpc_client.commitment()).await?; - let stats = executor.stats.read().await; - info!("Stats: {:?}", stats); + { + let stats = executor.stats.borrow(); + info!("Stats: {:?}", stats); + } let signatures = executor .signatures - .read() - .await + .borrow() .iter() .map(|s| bs58::encode(s).into_string()) .collect::>(); @@ -344,6 +345,8 @@ pub async fn execute( transactions: signatures, }; + let stats = executor.stats.borrow(); + if stats.total_objects == stats.corrected_objects { Ok(result) } else if stats.invalid_objects == 0 { diff --git a/evm_loader/lib/src/commands/trace.rs b/evm_loader/lib/src/commands/trace.rs index 7a7061fc6..50a5979ad 100644 --- a/evm_loader/lib/src/commands/trace.rs +++ b/evm_loader/lib/src/commands/trace.rs @@ -1,5 +1,5 @@ use std::fmt::{Display, Formatter}; -use std::sync::Arc; +use std::rc::Rc; use serde::{Deserialize, Serialize}; use serde_json::Value; @@ -44,14 +44,13 @@ pub async fn trace_transaction( solana_accounts, &trace_call_config.block_overrides, trace_call_config.state_overrides, - Some(Arc::clone(&tracer)), + Some(Rc::clone(&tracer)), ) .await?; - Ok(Arc::try_unwrap(tracer) + Ok(Rc::try_unwrap(tracer) .expect("There is must be only one reference") .into_inner() - .expect("Poisoned RwLock") .into_traces(emulation_result)) } @@ -115,13 +114,12 @@ async fn trace_trx<'a>( storage, chain_id, steps, - Some(Arc::clone(&tracer)), + Some(Rc::clone(&tracer)), ) .await?; - Ok(Arc::try_unwrap(tracer) + Ok(Rc::try_unwrap(tracer) .expect("There is must be only one reference") .into_inner() - .expect("Poisoned RwLock") .into_traces(emulation_result)) } diff --git a/evm_loader/lib/src/commands/transaction_executor.rs b/evm_loader/lib/src/commands/transaction_executor.rs index f195f9f71..b57ec31e5 100644 --- a/evm_loader/lib/src/commands/transaction_executor.rs +++ b/evm_loader/lib/src/commands/transaction_executor.rs @@ -1,7 +1,7 @@ -use std::{future::Future, sync::Arc}; +use std::cell::RefCell; +use std::future::Future; use serde::{Deserialize, Serialize}; -use tokio::sync::RwLock; use { crate::{errors::NeonError, rpc}, @@ -45,21 +45,21 @@ impl Stats { self.created_objects += 1; } } -pub struct TransactionExecutor { - pub client: Arc, +pub struct TransactionExecutor<'a, 'b> { + pub client: &'a dyn rpc::Rpc, pub send_trx: bool, - pub signatures: RwLock>, - pub stats: RwLock, - pub fee_payer: Arc, + pub signatures: RefCell>, + pub stats: RefCell, + pub fee_payer: &'b dyn Signer, } -impl TransactionExecutor { - pub fn new(client: Arc, fee_payer: Arc, send_trx: bool) -> Self { +impl<'a, 'b> TransactionExecutor<'a, 'b> { + pub fn new(client: &'a dyn rpc::Rpc, fee_payer: &'b dyn Signer, send_trx: bool) -> Self { Self { client, send_trx, - signatures: RwLock::new(vec![]), - stats: RwLock::new(Stats::default()), + signatures: RefCell::new(vec![]), + stats: RefCell::new(Stats::default()), fee_payer, } } @@ -96,9 +96,10 @@ impl TransactionExecutor { } } + #[allow(clippy::await_holding_refcell_ref)] pub async fn checkpoint(&self, commitment: CommitmentConfig) -> Result<(), NeonError> { let recent_blockhash = self.client.get_latest_blockhash().await?; - for sig in self.signatures.read().await.iter() { + for sig in self.signatures.borrow().iter() { self.client .confirm_transaction_with_spinner(sig, &recent_blockhash, commitment) .await?; @@ -115,7 +116,7 @@ impl TransactionExecutor { Transaction::new_with_payer(instructions, Some(&self.fee_payer.pubkey())); let blockhash = self.client.get_latest_blockhash().await?; - transaction.try_partial_sign(&[self.fee_payer.as_ref()], blockhash)?; + transaction.try_partial_sign(&[self.fee_payer], blockhash)?; transaction.try_sign(signing_keypairs, blockhash)?; Ok(transaction) @@ -161,7 +162,7 @@ impl TransactionExecutor { match verify(data.clone()).await { Ok(None) => { info!("{}: correct", name); - self.stats.write().await.inc_corrected_objects(); + self.stats.borrow_mut().inc_corrected_objects(); } Ok(Some(transaction)) => { if self.send_trx { @@ -169,24 +170,24 @@ impl TransactionExecutor { match result { Ok(signature) => { warn!("{}: updated in trx {}", name, signature); - self.signatures.write().await.push(signature); - self.stats.write().await.inc_modified_objects(); + self.signatures.borrow_mut().push(signature); + self.stats.borrow_mut().inc_modified_objects(); return Ok(Some(signature)); } Err(error) => { error!("{}: failed update with {}", name, error); - self.stats.write().await.inc_invalid_objects(); + self.stats.borrow_mut().inc_invalid_objects(); return Err(error); } }; }; debug!("{}: {:?}", name, transaction); - self.stats.write().await.inc_invalid_objects(); + self.stats.borrow_mut().inc_invalid_objects(); warn!("{}: will be updated", name); } Err(error) => { error!("{}: wrong object {:?}", name, error); - self.stats.write().await.inc_invalid_objects(); + self.stats.borrow_mut().inc_invalid_objects(); if self.send_trx { return Err(error); } @@ -196,7 +197,7 @@ impl TransactionExecutor { match create().await { Ok(None) => { info!("{}: missed ok", name); - self.stats.write().await.inc_corrected_objects(); + self.stats.borrow_mut().inc_corrected_objects(); } Ok(Some(transaction)) => { if self.send_trx { @@ -204,24 +205,24 @@ impl TransactionExecutor { match result { Ok(signature) => { warn!("{}: created in trx {}", name, signature); - self.signatures.write().await.push(signature); - self.stats.write().await.inc_created_objects(); + self.signatures.borrow_mut().push(signature); + self.stats.borrow_mut().inc_created_objects(); return Ok(Some(signature)); } Err(error) => { error!("{}: failed create with {}", name, error); - self.stats.write().await.inc_invalid_objects(); + self.stats.borrow_mut().inc_invalid_objects(); return Err(error); } }; }; debug!("{}: {:?}", name, transaction); warn!("{}: will be created", name); - self.stats.write().await.inc_created_objects(); + self.stats.borrow_mut().inc_created_objects(); } Err(error) => { error!("{}: can't be created: {:?}", name, error); - self.stats.write().await.inc_invalid_objects(); + self.stats.borrow_mut().inc_invalid_objects(); if self.send_trx { return Err(error); } diff --git a/evm_loader/lib/src/config.rs b/evm_loader/lib/src/config.rs index f1293ff08..ab12bc955 100644 --- a/evm_loader/lib/src/config.rs +++ b/evm_loader/lib/src/config.rs @@ -1,4 +1,4 @@ -use std::{env, str::FromStr, sync::Arc}; +use std::{env, str::FromStr}; use crate::{types::ChDbConfig, NeonError}; use serde::{Deserialize, Serialize}; @@ -11,7 +11,7 @@ use solana_sdk::{commitment_config::CommitmentConfig, pubkey::Pubkey, signature: #[derive(Debug)] pub struct Config { pub evm_loader: Pubkey, - pub fee_payer: Option>, + pub fee_payer: Option, pub commitment: CommitmentConfig, pub solana_cli_config: solana_cli_config::Config, pub db_config: Option, @@ -53,8 +53,7 @@ pub fn create_from_api_config(api_config: &APIOptions) -> Result = Option::from(api_config.db_config.clone()); diff --git a/evm_loader/lib/src/context.rs b/evm_loader/lib/src/context.rs index 0d2b8c4b4..91793531e 100644 --- a/evm_loader/lib/src/context.rs +++ b/evm_loader/lib/src/context.rs @@ -1,11 +1,8 @@ -use std::sync::Arc; - use crate::{ rpc::{self}, Config, NeonError, }; use solana_clap_utils::keypair::signer_from_path; -use solana_client::nonblocking::rpc_client::RpcClient; use solana_sdk::signature::Signer; pub fn truncate_0x(in_str: &str) -> &str { @@ -16,44 +13,17 @@ pub fn truncate_0x(in_str: &str) -> &str { } } -pub struct Context { - pub rpc_client: Arc, - signer_config: Arc, +pub struct Context<'a> { + pub rpc_client: &'a dyn rpc::Rpc, + signer_config: &'a Config, } -impl Context { +impl<'a> Context<'a> { pub fn signer(&self) -> Result, NeonError> { - build_signer(&self.signer_config) - } - - pub async fn new_from_config( - config: Arc, - slot: Option, - ) -> Result { - let rpc_client: Arc = if let Some(slot) = slot { - Arc::new( - rpc::CallDbClient::new( - crate::types::TracerDb::new( - config.db_config.as_ref().expect("db-config not found"), - ), - slot, - ) - .await?, - ) - } else { - Arc::new(RpcClient::new_with_commitment( - config.json_rpc_url.clone(), - config.commitment, - )) - }; - - Ok(Self { - rpc_client, - signer_config: config.clone(), - }) + build_signer(self.signer_config) } - pub fn new(rpc_client: Arc, signer_config: Arc) -> Self { + pub fn new(rpc_client: &'a dyn rpc::Rpc, signer_config: &'a Config) -> Context<'a> { Self { rpc_client, signer_config, diff --git a/evm_loader/lib/src/errors.rs b/evm_loader/lib/src/errors.rs index 132e6e5b2..d8c20a32e 100644 --- a/evm_loader/lib/src/errors.rs +++ b/evm_loader/lib/src/errors.rs @@ -78,8 +78,6 @@ pub enum NeonError { TxParametersParsingError(String), #[error("AddrParseError. {0:?}")] AddrParseError(#[from] AddrParseError), - #[error("AxumError. {0:?}")] - AxumError(#[from] axum::Error), #[error("SolanaClientError. {0:?}")] SolanaClientError(solana_client::client_error::ClientError), /// Environment Error @@ -117,7 +115,6 @@ impl NeonError { NeonError::PubkeyError(_) => 116, NeonError::EvmError(_) => 117, NeonError::AddrParseError(_) => 118, - NeonError::AxumError(_) => 119, NeonError::SolanaClientError(_) => 120, NeonError::EvmLoaderNotSpecified => 201, NeonError::KeypairNotSpecified => 202, diff --git a/evm_loader/lib/src/rpc/db_call_client.rs b/evm_loader/lib/src/rpc/db_call_client.rs index a84aa7dce..29a972f41 100644 --- a/evm_loader/lib/src/rpc/db_call_client.rs +++ b/evm_loader/lib/src/rpc/db_call_client.rs @@ -41,7 +41,7 @@ impl CallDbClient { } } -#[async_trait] +#[async_trait(?Send)] impl Rpc for CallDbClient { fn commitment(&self) -> CommitmentConfig { CommitmentConfig::default() diff --git a/evm_loader/lib/src/rpc/mod.rs b/evm_loader/lib/src/rpc/mod.rs index d6fcc1f7c..30690ff19 100644 --- a/evm_loader/lib/src/rpc/mod.rs +++ b/evm_loader/lib/src/rpc/mod.rs @@ -28,8 +28,8 @@ use solana_transaction_status::{ }; use std::any::Any; -#[async_trait] -pub trait Rpc: Send + Sync { +#[async_trait(?Send)] +pub trait Rpc { fn commitment(&self) -> CommitmentConfig; async fn confirm_transaction_with_spinner( &self, diff --git a/evm_loader/lib/src/rpc/validator_client.rs b/evm_loader/lib/src/rpc/validator_client.rs index ab4cbab12..727698d83 100644 --- a/evm_loader/lib/src/rpc/validator_client.rs +++ b/evm_loader/lib/src/rpc/validator_client.rs @@ -20,7 +20,7 @@ use solana_transaction_status::{ }; use std::any::Any; -#[async_trait] +#[async_trait(?Send)] impl Rpc for RpcClient { fn commitment(&self) -> CommitmentConfig { self.commitment() diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index 69e8099ff..6cc2322b3 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -3,11 +3,8 @@ pub mod tracer_ch_common; mod tracer_ch_db; pub use evm_loader::types::Address; -use lazy_static::lazy_static; use solana_sdk::pubkey::Pubkey; use std::str::FromStr; -use tokio::runtime::Runtime; -use tokio::task::block_in_place; pub use tracer_ch_db::ClickHouseDb as TracerDb; use evm_loader::evm::tracing::TraceCallConfig; @@ -47,20 +44,6 @@ pub struct TransactionParams { pub trace_config: Option, } -lazy_static! { - pub static ref RT: Runtime = Runtime::new().unwrap(); -} - -pub fn block(f: Fu) -> Fu::Output -where - Fu: std::future::Future, -{ - match tokio::runtime::Handle::try_current() { - Ok(handle) => block_in_place(|| handle.block_on(f)), - Err(_) => RT.block_on(f), - } -} - #[derive(Debug, Default, Clone, Copy)] pub struct PubkeyBase58(pub Pubkey); diff --git a/evm_loader/lib/src/types/tracer_ch_db.rs b/evm_loader/lib/src/types/tracer_ch_db.rs index 0cc9bfbb6..f60cf9c2b 100644 --- a/evm_loader/lib/src/types/tracer_ch_db.rs +++ b/evm_loader/lib/src/types/tracer_ch_db.rs @@ -21,14 +21,12 @@ use std::{ Ord, Ordering::{Equal, Greater, Less}, }, - sync::Arc, time::Instant, }; -#[allow(dead_code)] #[derive(Clone)] pub struct ClickHouseDb { - pub client: Arc, + pub client: Client, } impl ClickHouseDb { @@ -45,9 +43,7 @@ impl ClickHouseDb { .with_password(password), }; - ClickHouseDb { - client: Arc::new(client), - } + ClickHouseDb { client } } // return value is not used for tracer methods diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 6c8e1c10f..f1fab8ba7 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -34,8 +34,6 @@ test-bpf = [] custom-heap = [] default = ["custom-heap"] -tracing = ["serde_json"] - [dependencies] linked_list_allocator = { version = "0.10", default-features = false } evm-loader-macro = { path = "../program-macro" } @@ -58,6 +56,12 @@ ethnum = { version = "1.4", default-features = false, features = ["serde"] } const_format = { version = "0.2.21" } cfg-if = { version = "1.0" } log = { version = "0.4", default-features = false, optional = true } +maybe-async = "0.2.7" +async-trait = { version = "0.1.73", optional = true } + +[target.'cfg(target_os = "solana")'.dependencies.maybe-async] +version = "0.2.7" +features = ["is_sync"] [lib] crate-type = ["cdylib", "lib"] diff --git a/evm_loader/program/src/account_storage/mod.rs b/evm_loader/program/src/account_storage/mod.rs index b2b47dbcf..27e8c3978 100644 --- a/evm_loader/program/src/account_storage/mod.rs +++ b/evm_loader/program/src/account_storage/mod.rs @@ -1,17 +1,25 @@ -use crate::account::{EthereumAccount, EthereumStorage}; +use crate::account::EthereumAccount; use crate::executor::{Action, OwnedAccountInfo}; use crate::types::Address; use ethnum::U256; +use maybe_async::maybe_async; use solana_program::account_info::AccountInfo; -use solana_program::clock::Clock; +#[cfg(target_os = "solana")] +use { + crate::account::EthereumStorage, solana_program::clock::Clock, std::cell::RefCell, + std::collections::HashSet, +}; + use solana_program::pubkey::Pubkey; use solana_program::slot_history::Slot; -use std::cell::RefCell; use std::cmp::Ordering; -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; +#[cfg(target_os = "solana")] mod apply; +#[cfg(target_os = "solana")] mod backend; +#[cfg(target_os = "solana")] mod base; #[derive(Debug)] @@ -29,6 +37,7 @@ pub enum AccountsReadiness { NeedMoreReallocations, } +#[cfg(target_os = "solana")] pub struct ProgramAccountStorage<'a> { program_id: &'a Pubkey, operator: &'a Pubkey, @@ -45,6 +54,7 @@ pub struct ProgramAccountStorage<'a> { /// Account storage /// Trait to access account info +#[maybe_async(?Send)] pub trait AccountStorage { /// Get `NEON` token mint fn neon_token_mint(&self) -> &Pubkey; @@ -60,34 +70,34 @@ pub trait AccountStorage { /// Get block timestamp fn block_timestamp(&self) -> U256; /// Get block hash - fn block_hash(&self, number: u64) -> [u8; 32]; + async fn block_hash(&self, number: u64) -> [u8; 32]; /// Get chain id fn chain_id(&self) -> u64; /// Check if ethereum account exists - fn exists(&self, address: &Address) -> bool; + async fn exists(&self, address: &Address) -> bool; /// Get account nonce - fn nonce(&self, address: &Address) -> u64; + async fn nonce(&self, address: &Address) -> u64; /// Get account balance - fn balance(&self, address: &Address) -> U256; + async fn balance(&self, address: &Address) -> U256; /// Get code size - fn code_size(&self, address: &Address) -> usize; + async fn code_size(&self, address: &Address) -> usize; /// Get code hash - fn code_hash(&self, address: &Address) -> [u8; 32]; + async fn code_hash(&self, address: &Address) -> [u8; 32]; /// Get code data - fn code(&self, address: &Address) -> crate::evm::Buffer; + async fn code(&self, address: &Address) -> crate::evm::Buffer; /// Get contract generation - fn generation(&self, address: &Address) -> u32; + async fn generation(&self, address: &Address) -> u32; /// Get data from storage - fn storage(&self, address: &Address, index: &U256) -> [u8; 32]; + async fn storage(&self, address: &Address, index: &U256) -> [u8; 32]; /// Clone existing solana account - fn clone_solana_account(&self, address: &Pubkey) -> OwnedAccountInfo; + async fn clone_solana_account(&self, address: &Pubkey) -> OwnedAccountInfo; /// Map existing solana account - fn map_solana_account(&self, address: &Pubkey, action: F) -> R + async fn map_solana_account(&self, address: &Pubkey, action: F) -> R where F: FnOnce(&AccountInfo) -> R; @@ -97,9 +107,9 @@ pub trait AccountStorage { } /// Solana account data len - fn solana_account_space(&self, address: &Address) -> Option; + async fn solana_account_space(&self, address: &Address) -> Option; - fn calc_accounts_operations(&self, actions: &[Action]) -> AccountsOperations { + async fn calc_accounts_operations(&self, actions: &[Action]) -> AccountsOperations { let mut accounts = HashMap::new(); for action in actions { let (address, code_size) = match action { @@ -117,27 +127,28 @@ pub trait AccountStorage { accounts.insert(address, space_needed); } - accounts - .into_iter() - .filter_map( - |(address, space_needed)| match self.solana_account_space(address) { - None => Some(( - *address, - AccountOperation::Create { - space: space_needed, - }, - )), - Some(space_current) if space_current < space_needed => Some(( - *address, - AccountOperation::Resize { - from: space_current, - to: space_needed, - }, - )), - _ => None, - }, - ) - .collect() + let mut result = AccountsOperations::new(); + + for (address, space_needed) in accounts { + match self.solana_account_space(address).await { + None => result.push(( + *address, + AccountOperation::Create { + space: space_needed, + }, + )), + Some(space_current) if space_current < space_needed => result.push(( + *address, + AccountOperation::Resize { + from: space_current, + to: space_needed, + }, + )), + _ => (), + } + } + + result } } diff --git a/evm_loader/program/src/evm/database.rs b/evm_loader/program/src/evm/database.rs index 11cc85f1a..56efcb7e9 100644 --- a/evm_loader/program/src/evm/database.rs +++ b/evm_loader/program/src/evm/database.rs @@ -1,31 +1,33 @@ use super::{Buffer, Context}; use crate::{error::Result, types::Address}; use ethnum::U256; +use maybe_async::maybe_async; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; +#[maybe_async(?Send)] pub trait Database { fn chain_id(&self) -> U256; - fn nonce(&self, address: &Address) -> Result; + async fn nonce(&self, address: &Address) -> Result; fn increment_nonce(&mut self, address: Address) -> Result<()>; - fn balance(&self, address: &Address) -> Result; - fn transfer(&mut self, source: Address, target: Address, value: U256) -> Result<()>; + async fn balance(&self, address: &Address) -> Result; + async fn transfer(&mut self, source: Address, target: Address, value: U256) -> Result<()>; - fn code_size(&self, address: &Address) -> Result; - fn code_hash(&self, address: &Address) -> Result<[u8; 32]>; - fn code(&self, address: &Address) -> Result; + async fn code_size(&self, address: &Address) -> Result; + async fn code_hash(&self, address: &Address) -> Result<[u8; 32]>; + async fn code(&self, address: &Address) -> Result; fn set_code(&mut self, address: Address, code: Buffer) -> Result<()>; fn selfdestruct(&mut self, address: Address) -> Result<()>; - fn storage(&self, address: &Address, index: &U256) -> Result<[u8; 32]>; + async fn storage(&self, address: &Address, index: &U256) -> Result<[u8; 32]>; fn set_storage(&mut self, address: Address, index: U256, value: [u8; 32]) -> Result<()>; - fn block_hash(&self, number: U256) -> Result<[u8; 32]>; + async fn block_hash(&self, number: U256) -> Result<[u8; 32]>; fn block_number(&self) -> Result; fn block_timestamp(&self) -> Result; - fn map_solana_account(&self, address: &Pubkey, action: F) -> R + async fn map_solana_account(&self, address: &Pubkey, action: F) -> R where F: FnOnce(&AccountInfo) -> R; @@ -33,7 +35,7 @@ pub trait Database { fn revert_snapshot(&mut self); fn commit_snapshot(&mut self); - fn precompile_extension( + async fn precompile_extension( &mut self, context: &Context, address: &Address, diff --git a/evm_loader/program/src/evm/memory.rs b/evm_loader/program/src/evm/memory.rs index ce9c40c6d..2ccb671fe 100644 --- a/evm_loader/program/src/evm/memory.rs +++ b/evm_loader/program/src/evm/memory.rs @@ -4,7 +4,7 @@ use std::ops::Range; use solana_program::program_memory::{sol_memcpy, sol_memset}; use crate::error::Error; -#[cfg(feature = "tracing")] +#[cfg(not(target_os = "solana"))] use crate::evm::tracing::TracerTypeOpt; use super::utils::checked_next_multiple_of_32; @@ -20,22 +20,22 @@ pub struct Memory { data: *mut u8, capacity: usize, size: usize, - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] tracer: TracerTypeOpt, } impl Memory { - pub fn new(#[cfg(feature = "tracing")] tracer: TracerTypeOpt) -> Self { + pub fn new(#[cfg(not(target_os = "solana"))] tracer: TracerTypeOpt) -> Self { Self::with_capacity( MEMORY_CAPACITY, - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] tracer, ) } pub fn with_capacity( capacity: usize, - #[cfg(feature = "tracing")] tracer: TracerTypeOpt, + #[cfg(not(target_os = "solana"))] tracer: TracerTypeOpt, ) -> Self { unsafe { let layout = Layout::from_size_align_unchecked(capacity, MEMORY_ALIGN); @@ -48,7 +48,7 @@ impl Memory { data, capacity, size: 0, - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] tracer, } } @@ -70,13 +70,13 @@ impl Memory { data, capacity, size: v.len(), - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] tracer: None, } } } - #[allow(dead_code)] + #[cfg(not(target_os = "solana"))] pub fn to_vec(&self) -> Vec { let slice = unsafe { std::slice::from_raw_parts(self.data, self.size) }; slice.to_vec() diff --git a/evm_loader/program/src/evm/mod.rs b/evm_loader/program/src/evm/mod.rs index 09505121f..9e270e81b 100644 --- a/evm_loader/program/src/evm/mod.rs +++ b/evm_loader/program/src/evm/mod.rs @@ -5,12 +5,13 @@ use std::{marker::PhantomData, ops::Range}; use ethnum::U256; +use maybe_async::maybe_async; use serde::{Deserialize, Serialize}; use solana_program::log::sol_log_data; pub use buffer::Buffer; -#[cfg(feature = "tracing")] +#[cfg(not(target_os = "solana"))] use crate::evm::tracing::TracerTypeOpt; use crate::{ error::{build_revert_message, Error, Result}, @@ -27,22 +28,22 @@ mod opcode; mod opcode_table; mod precompile; mod stack; -#[cfg(feature = "tracing")] +#[cfg(not(target_os = "solana"))] pub mod tracing; mod utils; macro_rules! tracing_event { ($self:ident, $x:expr) => { - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] if let Some(tracer) = &$self.tracer { - tracer.write().expect("Poisoned RwLock").event($x); + tracer.borrow_mut().event($x); } }; ($self:ident, $condition:expr, $x:expr) => { - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] if let Some(tracer) = &$self.tracer { if $condition { - tracer.write().expect("Poisoned RwLock").event($x); + tracer.borrow_mut().event($x); } } }; @@ -50,11 +51,10 @@ macro_rules! tracing_event { macro_rules! trace_end_step { ($self:ident, $return_data:expr) => { - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] if let Some(tracer) = &$self.tracer { tracer - .write() - .expect("Poisoned RwLock") + .borrow_mut() .event(crate::evm::tracing::Event::EndStep { gas_used: 0_u64, return_data: $return_data, @@ -62,7 +62,7 @@ macro_rules! trace_end_step { } }; ($self:ident, $condition:expr; $return_data_getter:expr) => { - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] if $condition { trace_end_step!($self, $return_data_getter) } @@ -153,8 +153,8 @@ pub struct Machine { #[serde(skip)] phantom: PhantomData<*const B>, + #[cfg(not(target_os = "solana"))] #[serde(skip)] - #[cfg(feature = "tracing")] tracer: TracerTypeOpt, } @@ -167,6 +167,7 @@ impl Machine { cursor.position().try_into().map_err(Error::from) } + #[cfg(target_os = "solana")] pub fn deserialize_from(buffer: &[u8], backend: &B) -> Result { fn reinit_buffer(buffer: &mut Buffer, backend: &B) { if let Some((key, range)) = buffer.uninit_data() { @@ -175,13 +176,16 @@ impl Machine { } } - fn reinit_machine(machine: &mut Machine, backend: &B) { - reinit_buffer(&mut machine.call_data, backend); - reinit_buffer(&mut machine.execution_code, backend); - reinit_buffer(&mut machine.return_data, backend); + fn reinit_machine(mut machine: &mut Machine, backend: &B) { + loop { + reinit_buffer(&mut machine.call_data, backend); + reinit_buffer(&mut machine.execution_code, backend); + reinit_buffer(&mut machine.return_data, backend); - if let Some(parent) = &mut machine.parent { - reinit_machine(parent, backend); + match &mut machine.parent { + None => break, + Some(parent) => machine = parent, + } } } @@ -191,13 +195,14 @@ impl Machine { Ok(evm) } - pub fn new( + #[maybe_async] + pub async fn new( trx: &mut Transaction, origin: Address, backend: &mut B, - #[cfg(feature = "tracing")] tracer: TracerTypeOpt, + #[cfg(not(target_os = "solana"))] tracer: TracerTypeOpt, ) -> Result { - let origin_nonce = backend.nonce(&origin)?; + let origin_nonce = backend.nonce(&origin).await?; if origin_nonce == u64::MAX { return Err(Error::NonceOverflow(origin)); @@ -217,11 +222,11 @@ impl Machine { } } - if backend.balance(&origin)? < trx.value() { + if backend.balance(&origin).await? < trx.value() { return Err(Error::InsufficientBalance(origin, trx.value())); } - if backend.code_size(&origin)? != 0 { + if backend.code_size(&origin).await? != 0 { return Err(Error::SenderHasDeployedCode(origin)); } @@ -230,25 +235,28 @@ impl Machine { trx, origin, backend, - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] tracer, ) + .await } else { Self::new_create( trx, origin, backend, - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] tracer, ) + .await } } - fn new_call( + #[maybe_async] + async fn new_call( trx: &mut Transaction, origin: Address, backend: &mut B, - #[cfg(feature = "tracing")] tracer: TracerTypeOpt, + #[cfg(not(target_os = "solana"))] tracer: TracerTypeOpt, ) -> Result { assert!(trx.target().is_some()); @@ -258,9 +266,9 @@ impl Machine { backend.increment_nonce(origin)?; backend.snapshot(); - backend.transfer(origin, target, trx.value())?; + backend.transfer(origin, target, trx.value()).await?; - let execution_code = backend.code(&target)?; + let execution_code = backend.code(&target).await?; Ok(Self { origin, @@ -277,11 +285,11 @@ impl Machine { return_data: Buffer::empty(), return_range: 0..0, stack: Stack::new( - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] tracer.clone(), ), memory: Memory::new( - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] tracer.clone(), ), pc: 0_usize, @@ -289,23 +297,24 @@ impl Machine { reason: Reason::Call, parent: None, phantom: PhantomData, - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] tracer, }) } - fn new_create( + #[maybe_async] + async fn new_create( trx: &mut Transaction, origin: Address, backend: &mut B, - #[cfg(feature = "tracing")] tracer: TracerTypeOpt, + #[cfg(not(target_os = "solana"))] tracer: TracerTypeOpt, ) -> Result { assert!(trx.target().is_none()); let target = Address::from_create(&origin, trx.nonce()); sol_log_data(&[b"ENTER", b"CREATE", target.as_bytes()]); - if (backend.nonce(&target)? != 0) || (backend.code_size(&target)? != 0) { + if (backend.nonce(&target).await? != 0) || (backend.code_size(&target).await? != 0) { return Err(Error::DeployToExistingAccount(target, origin)); } @@ -313,7 +322,7 @@ impl Machine { backend.snapshot(); backend.increment_nonce(target)?; - backend.transfer(origin, target, trx.value())?; + backend.transfer(origin, target, trx.value()).await?; Ok(Self { origin, @@ -328,11 +337,11 @@ impl Machine { return_data: Buffer::empty(), return_range: 0..0, stack: Stack::new( - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] tracer.clone(), ), memory: Memory::new( - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] tracer.clone(), ), pc: 0_usize, @@ -342,12 +351,13 @@ impl Machine { call_data: Buffer::empty(), parent: None, phantom: PhantomData, - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] tracer, }) } - pub fn execute(&mut self, step_limit: u64, backend: &mut B) -> Result<(ExitStatus, u64)> { + #[maybe_async] + pub async fn execute(&mut self, step_limit: u64, backend: &mut B) -> Result<(ExitStatus, u64)> { assert!(self.execution_code.is_initialized()); assert!(self.call_data.is_initialized()); assert!(self.return_data.is_initialized()); @@ -386,14 +396,12 @@ impl Machine { } ); - // SAFETY: OPCODES.len() == 256, opcode <= 255 - let (_, opcode_fn) = unsafe { Self::OPCODES.get_unchecked(opcode as usize) }; - - let opcode_result = match opcode_fn(self, backend) { + let opcode_result = match self.execute_opcode(backend, opcode).await { Ok(result) => result, Err(e) => { let message = build_revert_message(&e.to_string()); - self.opcode_revert_impl(Buffer::from_slice(&message), backend)? + self.opcode_revert_impl(Buffer::from_slice(&message), backend) + .await? } }; @@ -442,11 +450,11 @@ impl Machine { return_data: Buffer::empty(), return_range: 0..0, stack: Stack::new( - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] self.tracer.clone(), ), memory: Memory::new( - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] self.tracer.clone(), ), pc: 0_usize, @@ -454,7 +462,7 @@ impl Machine { reason, parent: None, phantom: PhantomData, - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] tracer: self.tracer.clone(), }; diff --git a/evm_loader/program/src/evm/opcode.rs b/evm_loader/program/src/evm/opcode.rs index 928ad0349..f1f8c9b48 100644 --- a/evm_loader/program/src/evm/opcode.rs +++ b/evm_loader/program/src/evm/opcode.rs @@ -1,5 +1,6 @@ /// use ethnum::{I256, U256}; +use maybe_async::maybe_async; use solana_program::log::sol_log_data; use super::{database::Database, tracing_event, Context, Machine, Reason}; @@ -20,9 +21,11 @@ pub enum Action { Noop, } +#[allow(clippy::unused_async)] impl Machine { /// Unknown instruction - pub fn opcode_unknown(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_unknown(&mut self, _backend: &mut B) -> Result { Err(Error::UnknownOpcode( self.context.contract, self.execution_code[self.pc], @@ -30,7 +33,8 @@ impl Machine { } /// (u)int256 addition modulo 2**256 - pub fn opcode_add(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_add(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_u256()?; let b = self.stack.pop_u256()?; let c = a.wrapping_add(b); @@ -41,7 +45,8 @@ impl Machine { } /// (u)int256 multiplication modulo 2**256 - pub fn opcode_mul(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_mul(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_u256()?; let b = self.stack.pop_u256()?; let c = a.wrapping_mul(b); @@ -52,7 +57,8 @@ impl Machine { } /// (u)int256 subtraction modulo 2**256 - pub fn opcode_sub(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_sub(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_u256()?; let b = self.stack.pop_u256()?; let c = a.wrapping_sub(b); @@ -63,7 +69,8 @@ impl Machine { } /// uint256 division - pub fn opcode_div(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_div(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_u256()?; let b = self.stack.pop_u256()?; @@ -78,7 +85,8 @@ impl Machine { } /// int256 division - pub fn opcode_sdiv(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_sdiv(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_i256()?; let b = self.stack.pop_i256()?; @@ -94,7 +102,8 @@ impl Machine { } /// uint256 modulus - pub fn opcode_mod(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_mod(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_u256()?; let b = self.stack.pop_u256()?; @@ -109,7 +118,8 @@ impl Machine { } /// int256 modulus - pub fn opcode_smod(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_smod(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_i256()?; let b = self.stack.pop_i256()?; @@ -126,7 +136,8 @@ impl Machine { /// (u)int256 addition modulo M /// (a + b) % m /// - pub fn opcode_addmod(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_addmod(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_u256()?; let b = self.stack.pop_u256()?; let m = self.stack.pop_u256()?; @@ -157,7 +168,8 @@ impl Machine { /// (u)int256 multiplication modulo M /// (a * b) % m /// - pub fn opcode_mulmod(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_mulmod(&mut self, _backend: &mut B) -> Result { let mut a = self.stack.pop_u256()?; let mut b = self.stack.pop_u256()?; let m = self.stack.pop_u256()?; @@ -202,7 +214,8 @@ impl Machine { /// uint256 exponentiation modulo 2**256 /// a ** b - pub fn opcode_exp(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_exp(&mut self, _backend: &mut B) -> Result { let mut a = self.stack.pop_u256()?; let mut b = self.stack.pop_u256()?; @@ -231,7 +244,8 @@ impl Machine { } /// sign extends x from (b + 1) * 8 bits to 256 bits. - pub fn opcode_signextend(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_signextend(&mut self, _backend: &mut B) -> Result { let b = self.stack.pop_u256()?; let x = self.stack.pop_u256()?; @@ -256,7 +270,8 @@ impl Machine { /// uint256 comparison /// a < b - pub fn opcode_lt(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_lt(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_u256()?; let b = self.stack.pop_u256()?; @@ -267,7 +282,8 @@ impl Machine { /// uint256 comparison /// a > b - pub fn opcode_gt(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_gt(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_u256()?; let b = self.stack.pop_u256()?; @@ -278,7 +294,8 @@ impl Machine { /// int256 comparison /// a < b - pub fn opcode_slt(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_slt(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_i256()?; let b = self.stack.pop_i256()?; self.stack.push_bool(a < b)?; @@ -288,7 +305,8 @@ impl Machine { /// int256 comparison /// a > b - pub fn opcode_sgt(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_sgt(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_i256()?; let b = self.stack.pop_i256()?; self.stack.push_bool(a > b)?; @@ -298,7 +316,8 @@ impl Machine { /// (u)int256 equality /// a == b - pub fn opcode_eq(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_eq(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_u256()?; let b = self.stack.pop_u256()?; @@ -309,7 +328,8 @@ impl Machine { /// (u)int256 is zero /// a == 0 - pub fn opcode_iszero(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_iszero(&mut self, _backend: &mut B) -> Result { let result = { let a = self.stack.pop_array()?; a == &[0_u8; 32] @@ -321,7 +341,8 @@ impl Machine { } /// 256-bit bitwise and - pub fn opcode_and(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_and(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_u256()?; let b = self.stack.pop_u256()?; @@ -331,7 +352,8 @@ impl Machine { } /// 256-bit bitwise or - pub fn opcode_or(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_or(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_u256()?; let b = self.stack.pop_u256()?; @@ -341,7 +363,8 @@ impl Machine { } /// 256-bit bitwise xor - pub fn opcode_xor(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_xor(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_u256()?; let b = self.stack.pop_u256()?; @@ -351,7 +374,8 @@ impl Machine { } /// 256-bit bitwise not - pub fn opcode_not(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_not(&mut self, _backend: &mut B) -> Result { let a = self.stack.pop_u256()?; self.stack.push_u256(!a)?; @@ -359,7 +383,8 @@ impl Machine { } /// ith byte of (u)int256 x, counting from most significant byte - pub fn opcode_byte(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_byte(&mut self, _backend: &mut B) -> Result { let result = { let i = self.stack.pop_u256()?; let x = self.stack.pop_array()?; @@ -377,7 +402,8 @@ impl Machine { } /// 256-bit shift left - pub fn opcode_shl(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_shl(&mut self, _backend: &mut B) -> Result { let shift = self.stack.pop_u256()?; let value = self.stack.pop_u256()?; @@ -391,7 +417,8 @@ impl Machine { } /// 256-bit shift right - pub fn opcode_shr(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_shr(&mut self, _backend: &mut B) -> Result { let shift = self.stack.pop_u256()?; let value = self.stack.pop_u256()?; @@ -405,7 +432,8 @@ impl Machine { } /// arithmetic int256 shift right - pub fn opcode_sar(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_sar(&mut self, _backend: &mut B) -> Result { let (shift, value) = { let shift = self.stack.pop_u256()?; let value = self.stack.pop_i256()?; @@ -422,7 +450,8 @@ impl Machine { } /// hash = keccak256(memory[offset:offset+length]) - pub fn opcode_sha3(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_sha3(&mut self, _backend: &mut B) -> Result { use solana_program::keccak::{hash, Hash}; let offset = self.stack.pop_usize()?; @@ -437,17 +466,19 @@ impl Machine { } /// address of the executing contract - pub fn opcode_address(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_address(&mut self, _backend: &mut B) -> Result { self.stack.push_address(&self.context.contract)?; Ok(Action::Continue) } /// address balance in wei - pub fn opcode_balance(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_balance(&mut self, backend: &mut B) -> Result { let balance = { let address = self.stack.pop_address()?; - backend.balance(address)? + backend.balance(address).await? }; self.stack.push_u256(balance)?; @@ -457,7 +488,8 @@ impl Machine { /// transaction origin address /// tx.origin - pub fn opcode_origin(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_origin(&mut self, _backend: &mut B) -> Result { self.stack.push_address(&self.origin)?; Ok(Action::Continue) @@ -465,7 +497,8 @@ impl Machine { /// message caller address /// msg.caller - pub fn opcode_caller(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_caller(&mut self, _backend: &mut B) -> Result { self.stack.push_address(&self.context.caller)?; Ok(Action::Continue) @@ -473,7 +506,8 @@ impl Machine { /// message funds in wei /// msg.value - pub fn opcode_callvalue(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_callvalue(&mut self, _backend: &mut B) -> Result { self.stack.push_u256(self.context.value)?; Ok(Action::Continue) @@ -481,7 +515,8 @@ impl Machine { /// reads a (u)int256 from message data /// msg.data[i:i+32] - pub fn opcode_calldataload(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_calldataload(&mut self, _backend: &mut B) -> Result { let index = self.stack.pop_usize()?; if let Some(buffer) = self.call_data.get(index..index + 32) { @@ -502,14 +537,16 @@ impl Machine { /// message data length in bytes /// msg.data.size - pub fn opcode_calldatasize(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_calldatasize(&mut self, _backend: &mut B) -> Result { self.stack.push_usize(self.call_data.len())?; Ok(Action::Continue) } /// copy message data to memory - pub fn opcode_calldatacopy(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_calldatacopy(&mut self, _backend: &mut B) -> Result { let memory_offset = self.stack.pop_usize()?; let data_offset = self.stack.pop_usize()?; let length = self.stack.pop_usize()?; @@ -522,14 +559,16 @@ impl Machine { /// length of the executing contract's code in bytes /// address(this).code.size - pub fn opcode_codesize(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_codesize(&mut self, _backend: &mut B) -> Result { self.stack.push_usize(self.execution_code.len())?; Ok(Action::Continue) } /// copy executing contract's bytecode - pub fn opcode_codecopy(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_codecopy(&mut self, _backend: &mut B) -> Result { let memory_offset = self.stack.pop_usize()?; let data_offset = self.stack.pop_usize()?; let length = self.stack.pop_usize()?; @@ -542,7 +581,8 @@ impl Machine { /// gas price of the executing transaction, in wei per unit of gas /// tx.gasprice - pub fn opcode_gasprice(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_gasprice(&mut self, _backend: &mut B) -> Result { self.stack.push_u256(self.gas_price)?; Ok(Action::Continue) @@ -550,10 +590,11 @@ impl Machine { /// length of the contract bytecode at addr, in bytes /// address(addr).code.size - pub fn opcode_extcodesize(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_extcodesize(&mut self, backend: &mut B) -> Result { let code_size = { let address = self.stack.pop_address()?; - backend.code_size(address)? + backend.code_size(address).await? }; self.stack.push_usize(code_size)?; @@ -562,13 +603,14 @@ impl Machine { } /// copy contract's bytecode - pub fn opcode_extcodecopy(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_extcodecopy(&mut self, backend: &mut B) -> Result { let address = *self.stack.pop_address()?; let memory_offset = self.stack.pop_usize()?; let data_offset = self.stack.pop_usize()?; let length = self.stack.pop_usize()?; - let code = backend.code(&address)?; + let code = backend.code(&address).await?; self.memory .write_buffer(memory_offset, length, &code, data_offset)?; @@ -577,14 +619,16 @@ impl Machine { } /// Byzantium hardfork, EIP-211: the size of the returned data from the last external call, in bytes - pub fn opcode_returndatasize(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_returndatasize(&mut self, _backend: &mut B) -> Result { self.stack.push_usize(self.return_data.len())?; Ok(Action::Continue) } /// Byzantium hardfork, EIP-211: copy returned data - pub fn opcode_returndatacopy(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_returndatacopy(&mut self, _backend: &mut B) -> Result { let memory_offset = self.stack.pop_usize()?; let data_offset = self.stack.pop_usize()?; let length = self.stack.pop_usize()?; @@ -600,10 +644,11 @@ impl Machine { } /// Constantinople hardfork, EIP-1052: hash of the contract bytecode at addr - pub fn opcode_extcodehash(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_extcodehash(&mut self, backend: &mut B) -> Result { let code_hash = { let address = self.stack.pop_address()?; - backend.code_hash(address)? + backend.code_hash(address).await? }; self.stack.push_array(&code_hash)?; @@ -613,11 +658,12 @@ impl Machine { /// hash of the specific block, only valid for the 256 most recent blocks, excluding the current one /// Solana limits to 150 most recent blocks - pub fn opcode_blockhash(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_blockhash(&mut self, backend: &mut B) -> Result { let block_hash = { let block_number = self.stack.pop_u256()?; - backend.block_hash(block_number)? + backend.block_hash(block_number).await? }; self.stack.push_array(&block_hash)?; @@ -627,14 +673,16 @@ impl Machine { /// address of the current block's miner /// NOT SUPPORTED - pub fn opcode_coinbase(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_coinbase(&mut self, _backend: &mut B) -> Result { self.stack.push_zero()?; Ok(Action::Continue) } /// current block's Unix timestamp in seconds - pub fn opcode_timestamp(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_timestamp(&mut self, backend: &mut B) -> Result { let timestamp = backend.block_timestamp()?; self.stack.push_u256(timestamp)?; @@ -643,7 +691,8 @@ impl Machine { } /// current block's number - pub fn opcode_number(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_number(&mut self, backend: &mut B) -> Result { let block_number = backend.block_number()?; self.stack.push_u256(block_number)?; @@ -653,7 +702,8 @@ impl Machine { /// current block's difficulty /// NOT SUPPORTED - pub fn opcode_difficulty(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_difficulty(&mut self, _backend: &mut B) -> Result { self.stack.push_zero()?; Ok(Action::Continue) @@ -661,14 +711,16 @@ impl Machine { /// current block's gas limit /// NOT SUPPORTED - pub fn opcode_gaslimit(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_gaslimit(&mut self, _backend: &mut B) -> Result { self.stack.push_u256(U256::MAX)?; Ok(Action::Continue) } /// Istanbul hardfork, EIP-1344: current network's chain id - pub fn opcode_chainid(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_chainid(&mut self, backend: &mut B) -> Result { let chain_id = backend.chain_id(); self.stack.push_u256(chain_id)?; @@ -677,8 +729,9 @@ impl Machine { } /// Istanbul hardfork, EIP-1884: balance of the executing contract in wei - pub fn opcode_selfbalance(&mut self, backend: &mut B) -> Result { - let balance = backend.balance(&self.context.contract)?; + #[maybe_async] + pub async fn opcode_selfbalance(&mut self, backend: &mut B) -> Result { + let balance = backend.balance(&self.context.contract).await?; self.stack.push_u256(balance)?; @@ -687,21 +740,24 @@ impl Machine { /// London hardfork, EIP-3198: current block's base fee /// NOT SUPPORTED - pub fn opcode_basefee(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_basefee(&mut self, _backend: &mut B) -> Result { self.stack.push_zero()?; Ok(Action::Continue) } /// pops a (u)int256 off the stack and discards it - pub fn opcode_pop(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_pop(&mut self, _backend: &mut B) -> Result { self.stack.discard()?; Ok(Action::Continue) } /// reads a (u)int256 from memory - pub fn opcode_mload(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_mload(&mut self, _backend: &mut B) -> Result { let offset = self.stack.pop_usize()?; let value = self.memory.read_32(offset)?; @@ -711,7 +767,8 @@ impl Machine { } /// writes a (u)int256 to memory - pub fn opcode_mstore(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_mstore(&mut self, _backend: &mut B) -> Result { let offset = self.stack.pop_usize()?; let value = self.stack.pop_array()?; @@ -721,7 +778,8 @@ impl Machine { } /// writes a uint8 to memory - pub fn opcode_mstore8(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_mstore8(&mut self, _backend: &mut B) -> Result { let offset = self.stack.pop_usize()?; let value = self.stack.pop_array()?; @@ -731,9 +789,10 @@ impl Machine { } /// reads a (u)int256 from storage - pub fn opcode_sload(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_sload(&mut self, backend: &mut B) -> Result { let index = self.stack.pop_u256()?; - let value = backend.storage(&self.context.contract, &index)?; + let value = backend.storage(&self.context.contract, &index).await?; tracing_event!(self, super::tracing::Event::StorageAccess { index, value }); @@ -743,7 +802,8 @@ impl Machine { } /// writes a (u)int256 to storage - pub fn opcode_sstore(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_sstore(&mut self, backend: &mut B) -> Result { if self.is_static { return Err(Error::StaticModeViolation(self.context.contract)); } @@ -760,7 +820,8 @@ impl Machine { } /// unconditional jump - pub fn opcode_jump(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_jump(&mut self, _backend: &mut B) -> Result { const JUMPDEST: u8 = 0x5B; let value = self.stack.pop_usize()?; @@ -773,7 +834,8 @@ impl Machine { } /// conditional jump - pub fn opcode_jumpi(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_jumpi(&mut self, _backend: &mut B) -> Result { const JUMPDEST: u8 = 0x5B; let value = self.stack.pop_usize()?; @@ -791,33 +853,38 @@ impl Machine { } /// program counter - pub fn opcode_pc(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_pc(&mut self, _backend: &mut B) -> Result { self.stack.push_usize(self.pc)?; Ok(Action::Continue) } /// memory size - pub fn opcode_msize(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_msize(&mut self, _backend: &mut B) -> Result { self.stack.push_usize(self.memory.size())?; Ok(Action::Continue) } /// remaining gas - pub fn opcode_gas(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_gas(&mut self, _backend: &mut B) -> Result { self.stack.push_u256(self.gas_limit)?; Ok(Action::Continue) } /// metadata to annotate possible jump destinations - pub fn opcode_jumpdest(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_jumpdest(&mut self, _backend: &mut B) -> Result { Ok(Action::Continue) } /// Place zero on stack - pub fn opcode_push_0(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_push_0(&mut self, _backend: &mut B) -> Result { self.stack.push_zero()?; Ok(Action::Continue) @@ -825,7 +892,8 @@ impl Machine { /// Place 1 byte item on stack /// ~50% of contract bytecode are PUSH opcodes - pub fn opcode_push_1(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_push_1(&mut self, _backend: &mut B) -> Result { if self.execution_code.len() <= self.pc + 1 { return Err(Error::PushOutOfBounds(self.context.contract)); } @@ -838,7 +906,8 @@ impl Machine { } /// Place 2-31 byte item on stack. - pub fn opcode_push_2_31(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_push_2_31(&mut self, _backend: &mut B) -> Result { if self.execution_code.len() <= self.pc + 1 + N { return Err(Error::PushOutOfBounds(self.context.contract)); } @@ -854,7 +923,8 @@ impl Machine { } /// Place 32 byte item on stack - pub fn opcode_push_32(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_push_32(&mut self, _backend: &mut B) -> Result { if self.execution_code.len() <= self.pc + 1 + 32 { return Err(Error::PushOutOfBounds(self.context.contract)); } @@ -871,14 +941,16 @@ impl Machine { /// Duplicate Nth stack item /// ~25% of contract bytecode are DUP and SWAP opcodes - pub fn opcode_dup_1_16(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_dup_1_16(&mut self, _backend: &mut B) -> Result { self.stack.dup_1_16::()?; Ok(Action::Continue) } /// Exchange 1st and (N+1)th stack item - pub fn opcode_swap_1_16(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_swap_1_16(&mut self, _backend: &mut B) -> Result { self.stack.swap_1_16::()?; Ok(Action::Continue) @@ -886,7 +958,8 @@ impl Machine { /// Append log record with N topics #[rustfmt::skip] - pub fn opcode_log_0_4(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_log_0_4(&mut self, _backend: &mut B) -> Result { if self.is_static { return Err(Error::StaticModeViolation(self.context.contract)); } @@ -919,7 +992,8 @@ impl Machine { } /// Create a new account with associated code. - pub fn opcode_create(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_create(&mut self, backend: &mut B) -> Result { if self.is_static { return Err(Error::StaticModeViolation(self.context.contract)); } @@ -929,15 +1003,17 @@ impl Machine { let length = self.stack.pop_usize()?; let created_address = { - let nonce = backend.nonce(&self.context.contract)?; + let nonce = backend.nonce(&self.context.contract).await?; Address::from_create(&self.context.contract, nonce) }; self.opcode_create_impl(created_address, value, offset, length, backend) + .await } /// Constantinople harfork, EIP-1014: creates a create a new account with a deterministic address - pub fn opcode_create2(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_create2(&mut self, backend: &mut B) -> Result { if self.is_static { return Err(Error::StaticModeViolation(self.context.contract)); } @@ -953,9 +1029,11 @@ impl Machine { }; self.opcode_create_impl(created_address, value, offset, length, backend) + .await } - fn opcode_create_impl( + #[maybe_async] + async fn opcode_create_impl( &mut self, address: Address, value: U256, @@ -963,7 +1041,7 @@ impl Machine { length: usize, backend: &mut B, ) -> Result { - if backend.nonce(&self.context.contract)? == u64::MAX { + if backend.nonce(&self.context.contract).await? == u64::MAX { return Err(Error::NonceOverflow(self.context.contract)); } @@ -994,22 +1072,25 @@ impl Machine { sol_log_data(&[b"ENTER", b"CREATE", address.as_bytes()]); - if (backend.nonce(&address)? != 0) || (backend.code_size(&address)? != 0) { + if (backend.nonce(&address).await? != 0) || (backend.code_size(&address).await? != 0) { return Err(Error::DeployToExistingAccount(address, self.context.caller)); } - if backend.balance(&self.context.caller)? < value { + if backend.balance(&self.context.caller).await? < value { return Err(Error::InsufficientBalance(self.context.caller, value)); } backend.increment_nonce(address)?; - backend.transfer(self.context.caller, address, value)?; + backend + .transfer(self.context.caller, address, value) + .await?; Ok(Action::Noop) } /// Message-call into an account - pub fn opcode_call(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_call(&mut self, backend: &mut B) -> Result { let gas_limit = self.stack.pop_u256()?; let address = *self.stack.pop_address()?; let value = self.stack.pop_u256()?; @@ -1022,7 +1103,7 @@ impl Machine { self.return_range = return_offset..(return_offset + return_length); let call_data = self.memory.read_buffer(args_offset, args_length)?; - let code = backend.code(&address)?; + let code = backend.code(&address).await?; let context = Context { caller: self.context.contract, @@ -1048,17 +1129,20 @@ impl Machine { return Err(Error::StaticModeViolation(self.context.caller)); } - if backend.balance(&self.context.caller)? < value { + if backend.balance(&self.context.caller).await? < value { return Err(Error::InsufficientBalance(self.context.caller, value)); } - backend.transfer(self.context.caller, self.context.contract, value)?; + backend + .transfer(self.context.caller, self.context.contract, value) + .await?; - self.opcode_call_precompile_impl(backend, &address) + self.opcode_call_precompile_impl(backend, &address).await } /// Message-call into this account with an alternative account’s code - pub fn opcode_callcode(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_callcode(&mut self, backend: &mut B) -> Result { let gas_limit = self.stack.pop_u256()?; let address = *self.stack.pop_address()?; let value = self.stack.pop_u256()?; @@ -1071,7 +1155,7 @@ impl Machine { self.return_range = return_offset..(return_offset + return_length); let call_data = self.memory.read_buffer(args_offset, args_length)?; - let code = backend.code(&address)?; + let code = backend.code(&address).await?; let context = Context { caller: self.context.contract, @@ -1093,16 +1177,17 @@ impl Machine { sol_log_data(&[b"ENTER", b"CALLCODE", address.as_bytes()]); - if backend.balance(&self.context.caller)? < value { + if backend.balance(&self.context.caller).await? < value { return Err(Error::InsufficientBalance(self.context.caller, value)); } - self.opcode_call_precompile_impl(backend, &address) + self.opcode_call_precompile_impl(backend, &address).await } /// Homestead hardfork, EIP-7: Message-call into this account with an alternative account’s code, /// but persisting the current values for sender and value - pub fn opcode_delegatecall(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_delegatecall(&mut self, backend: &mut B) -> Result { let gas_limit = self.stack.pop_u256()?; let address = *self.stack.pop_address()?; let args_offset = self.stack.pop_usize()?; @@ -1114,7 +1199,7 @@ impl Machine { self.return_range = return_offset..(return_offset + return_length); let call_data = self.memory.read_buffer(args_offset, args_length)?; - let code = backend.code(&address)?; + let code = backend.code(&address).await?; let context = Context { code_address: Some(address), @@ -1134,12 +1219,13 @@ impl Machine { sol_log_data(&[b"ENTER", b"DELEGATECALL", address.as_bytes()]); - self.opcode_call_precompile_impl(backend, &address) + self.opcode_call_precompile_impl(backend, &address).await } /// Byzantium hardfork, EIP-214: Static message-call into an account /// Disallowed contract creation, event emission, storage modification and contract destruction - pub fn opcode_staticcall(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_staticcall(&mut self, backend: &mut B) -> Result { let gas_limit = self.stack.pop_u256()?; let address = *self.stack.pop_address()?; let args_offset = self.stack.pop_usize()?; @@ -1151,7 +1237,7 @@ impl Machine { self.return_range = return_offset..(return_offset + return_length); let call_data = self.memory.read_buffer(args_offset, args_length)?; - let code = backend.code(&address)?; + let code = backend.code(&address).await?; let context = Context { caller: self.context.contract, @@ -1175,40 +1261,49 @@ impl Machine { sol_log_data(&[b"ENTER", b"STATICCALL", address.as_bytes()]); - self.opcode_call_precompile_impl(backend, &address) + self.opcode_call_precompile_impl(backend, &address).await } /// Call precompile contract. /// Returns `Action::Noop` if address is not a precompile - fn opcode_call_precompile_impl( + #[maybe_async] + async fn opcode_call_precompile_impl( &mut self, backend: &mut B, address: &Address, ) -> Result { - let result = Self::precompile(address, &self.call_data).map(Ok); - let result = result.or_else(|| { - backend.precompile_extension(&self.context, address, &self.call_data, self.is_static) - }); + let result = match Self::precompile(address, &self.call_data).map(Ok) { + Some(x) => Some(x), + None => { + backend + .precompile_extension(&self.context, address, &self.call_data, self.is_static) + .await + } + }; if let Some(return_data) = result.transpose()? { - return self.opcode_return_impl(Buffer::from_slice(&return_data), backend); + return self + .opcode_return_impl(Buffer::from_slice(&return_data), backend) + .await; } Ok(Action::Noop) } /// Halt execution returning output data - pub fn opcode_return(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_return(&mut self, backend: &mut B) -> Result { let offset = self.stack.pop_usize()?; let length = self.stack.pop_usize()?; let return_data = self.memory.read_buffer(offset, length)?; - self.opcode_return_impl(return_data, backend) + self.opcode_return_impl(return_data, backend).await } /// Halt execution returning output data - pub fn opcode_return_impl( + #[maybe_async] + pub async fn opcode_return_impl( &mut self, mut return_data: Buffer, backend: &mut B, @@ -1251,16 +1346,22 @@ impl Machine { } /// Byzantium hardfork, EIP-140: Halt execution reverting state changes but returning data - pub fn opcode_revert(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_revert(&mut self, backend: &mut B) -> Result { let offset = self.stack.pop_usize()?; let length = self.stack.pop_usize()?; let return_data = self.memory.read_buffer(offset, length)?; - self.opcode_revert_impl(return_data, backend) + self.opcode_revert_impl(return_data, backend).await } - pub fn opcode_revert_impl(&mut self, return_data: Buffer, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_revert_impl( + &mut self, + return_data: Buffer, + backend: &mut B, + ) -> Result { backend.revert_snapshot(); sol_log_data(&[b"EXIT", b"REVERT", &return_data]); @@ -1293,7 +1394,8 @@ impl Machine { } /// Invalid instruction - pub fn opcode_invalid(&mut self, _backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_invalid(&mut self, _backend: &mut B) -> Result { Err(Error::InvalidOpcode( self.context.contract, self.execution_code[self.pc], @@ -1301,15 +1403,18 @@ impl Machine { } /// Halt execution, destroys the contract and send all funds to address - pub fn opcode_selfdestruct(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_selfdestruct(&mut self, backend: &mut B) -> Result { if self.is_static { return Err(Error::StaticModeViolation(self.context.contract)); } let address = *self.stack.pop_address()?; - let value = backend.balance(&self.context.contract)?; - backend.transfer(self.context.contract, address, value)?; + let value = backend.balance(&self.context.contract).await?; + backend + .transfer(self.context.contract, address, value) + .await?; backend.selfdestruct(self.context.contract)?; backend.commit_snapshot(); @@ -1342,7 +1447,8 @@ impl Machine { } /// Halts execution of the contract - pub fn opcode_stop(&mut self, backend: &mut B) -> Result { + #[maybe_async] + pub async fn opcode_stop(&mut self, backend: &mut B) -> Result { backend.commit_snapshot(); sol_log_data(&[b"EXIT", b"STOP"]); diff --git a/evm_loader/program/src/evm/opcode_table.rs b/evm_loader/program/src/evm/opcode_table.rs index 086a8e3a1..cc169efc2 100644 --- a/evm_loader/program/src/evm/opcode_table.rs +++ b/evm_loader/program/src/evm/opcode_table.rs @@ -1,173 +1,205 @@ -#![allow(clippy::type_complexity)] - use crate::error::Result; use super::{database::Database, opcode::Action, Machine}; -type OpCode = (&'static str, fn(&mut Machine, &mut B) -> Result); - -impl Machine { - const OPCODE_UNKNOWN: OpCode = ("", Self::opcode_unknown); - pub const OPCODES: [OpCode; 256] = { - let mut opcodes: [OpCode; 256] = [Self::OPCODE_UNKNOWN; 256]; - - opcodes[0x00] = ("STOP", Self::opcode_stop); - opcodes[0x01] = ("ADD", Self::opcode_add); - opcodes[0x02] = ("MUL", Self::opcode_mul); - opcodes[0x03] = ("SUB", Self::opcode_sub); - opcodes[0x04] = ("DIV", Self::opcode_div); - opcodes[0x05] = ("SDIV", Self::opcode_sdiv); - opcodes[0x06] = ("MOD", Self::opcode_mod); - opcodes[0x07] = ("SMOD", Self::opcode_smod); - opcodes[0x08] = ("ADDMOD", Self::opcode_addmod); - opcodes[0x09] = ("MULMOD", Self::opcode_mulmod); - opcodes[0x0A] = ("EXP", Self::opcode_exp); - opcodes[0x0B] = ("SIGNEXTEND", Self::opcode_signextend); - - opcodes[0x10] = ("LT", Self::opcode_lt); - opcodes[0x11] = ("GT", Self::opcode_gt); - opcodes[0x12] = ("SLT", Self::opcode_slt); - opcodes[0x13] = ("SGT", Self::opcode_sgt); - opcodes[0x14] = ("EQ", Self::opcode_eq); - opcodes[0x15] = ("ISZERO", Self::opcode_iszero); - opcodes[0x16] = ("AND", Self::opcode_and); - opcodes[0x17] = ("OR", Self::opcode_or); - opcodes[0x18] = ("XOR", Self::opcode_xor); - opcodes[0x19] = ("NOT", Self::opcode_not); - opcodes[0x1A] = ("BYTE", Self::opcode_byte); - opcodes[0x1B] = ("SHL", Self::opcode_shl); - opcodes[0x1C] = ("SHR", Self::opcode_shr); - opcodes[0x1D] = ("SAR", Self::opcode_sar); - - opcodes[0x20] = ("KECCAK256", Self::opcode_sha3); - - opcodes[0x30] = ("ADDRESS", Self::opcode_address); - opcodes[0x31] = ("BALANCE", Self::opcode_balance); - opcodes[0x32] = ("ORIGIN", Self::opcode_origin); - opcodes[0x33] = ("CALLER", Self::opcode_caller); - opcodes[0x34] = ("CALLVALUE", Self::opcode_callvalue); - opcodes[0x35] = ("CALLDATALOAD", Self::opcode_calldataload); - opcodes[0x36] = ("CALLDATASIZE", Self::opcode_calldatasize); - opcodes[0x37] = ("CALLDATACOPY", Self::opcode_calldatacopy); - opcodes[0x38] = ("CODESIZE", Self::opcode_codesize); - opcodes[0x39] = ("CODECOPY", Self::opcode_codecopy); - opcodes[0x3A] = ("GASPRICE", Self::opcode_gasprice); - opcodes[0x3B] = ("EXTCODESIZE", Self::opcode_extcodesize); - opcodes[0x3C] = ("EXTCODECOPY", Self::opcode_extcodecopy); - opcodes[0x3D] = ("RETURNDATASIZE", Self::opcode_returndatasize); - opcodes[0x3E] = ("RETURNDATACOPY", Self::opcode_returndatacopy); - opcodes[0x3F] = ("EXTCODEHASH", Self::opcode_extcodehash); - opcodes[0x40] = ("BLOCKHASH", Self::opcode_blockhash); - opcodes[0x41] = ("COINBASE", Self::opcode_coinbase); - opcodes[0x42] = ("TIMESTAMP", Self::opcode_timestamp); - opcodes[0x43] = ("NUMBER", Self::opcode_number); - opcodes[0x44] = ("PREVRANDAO", Self::opcode_difficulty); - opcodes[0x45] = ("GASLIMIT", Self::opcode_gaslimit); - opcodes[0x46] = ("CHAINID", Self::opcode_chainid); - opcodes[0x47] = ("SELFBALANCE", Self::opcode_selfbalance); - opcodes[0x48] = ("BASEFEE", Self::opcode_basefee); - - opcodes[0x50] = ("POP", Self::opcode_pop); - opcodes[0x51] = ("MLOAD", Self::opcode_mload); - opcodes[0x52] = ("MSTORE", Self::opcode_mstore); - opcodes[0x53] = ("MSTORE8", Self::opcode_mstore8); - opcodes[0x54] = ("SLOAD", Self::opcode_sload); - opcodes[0x55] = ("SSTORE", Self::opcode_sstore); - opcodes[0x56] = ("JUMP", Self::opcode_jump); - opcodes[0x57] = ("JUMPI", Self::opcode_jumpi); - opcodes[0x58] = ("PC", Self::opcode_pc); - opcodes[0x59] = ("MSIZE", Self::opcode_msize); - opcodes[0x5A] = ("GAS", Self::opcode_gas); - opcodes[0x5B] = ("JUMPDEST", Self::opcode_jumpdest); - - opcodes[0x5F] = ("PUSH0", Self::opcode_push_0); - opcodes[0x60] = ("PUSH1", Self::opcode_push_1); - opcodes[0x61] = ("PUSH2", Self::opcode_push_2_31::<2>); - opcodes[0x62] = ("PUSH3", Self::opcode_push_2_31::<3>); - opcodes[0x63] = ("PUSH4", Self::opcode_push_2_31::<4>); - opcodes[0x64] = ("PUSH5", Self::opcode_push_2_31::<5>); - opcodes[0x65] = ("PUSH6", Self::opcode_push_2_31::<6>); - opcodes[0x66] = ("PUSH7", Self::opcode_push_2_31::<7>); - opcodes[0x67] = ("PUSH8", Self::opcode_push_2_31::<8>); - opcodes[0x68] = ("PUSH9", Self::opcode_push_2_31::<9>); - opcodes[0x69] = ("PUSH10", Self::opcode_push_2_31::<10>); - opcodes[0x6A] = ("PUSH11", Self::opcode_push_2_31::<11>); - opcodes[0x6B] = ("PUSH12", Self::opcode_push_2_31::<12>); - opcodes[0x6C] = ("PUSH13", Self::opcode_push_2_31::<13>); - opcodes[0x6D] = ("PUSH14", Self::opcode_push_2_31::<14>); - opcodes[0x6E] = ("PUSH15", Self::opcode_push_2_31::<15>); - opcodes[0x6F] = ("PUSH16", Self::opcode_push_2_31::<16>); - opcodes[0x70] = ("PUSH17", Self::opcode_push_2_31::<17>); - opcodes[0x71] = ("PUSH18", Self::opcode_push_2_31::<18>); - opcodes[0x72] = ("PUSH19", Self::opcode_push_2_31::<19>); - opcodes[0x73] = ("PUSH20", Self::opcode_push_2_31::<20>); - opcodes[0x74] = ("PUSH21", Self::opcode_push_2_31::<21>); - opcodes[0x75] = ("PUSH22", Self::opcode_push_2_31::<22>); - opcodes[0x76] = ("PUSH23", Self::opcode_push_2_31::<23>); - opcodes[0x77] = ("PUSH24", Self::opcode_push_2_31::<24>); - opcodes[0x78] = ("PUSH25", Self::opcode_push_2_31::<25>); - opcodes[0x79] = ("PUSH26", Self::opcode_push_2_31::<26>); - opcodes[0x7A] = ("PUSH27", Self::opcode_push_2_31::<27>); - opcodes[0x7B] = ("PUSH28", Self::opcode_push_2_31::<28>); - opcodes[0x7C] = ("PUSH29", Self::opcode_push_2_31::<29>); - opcodes[0x7D] = ("PUSH30", Self::opcode_push_2_31::<30>); - opcodes[0x7E] = ("PUSH31", Self::opcode_push_2_31::<31>); - opcodes[0x7F] = ("PUSH32", Self::opcode_push_32); - - opcodes[0x80] = ("DUP1", Self::opcode_dup_1_16::<1>); - opcodes[0x81] = ("DUP2", Self::opcode_dup_1_16::<2>); - opcodes[0x82] = ("DUP3", Self::opcode_dup_1_16::<3>); - opcodes[0x83] = ("DUP4", Self::opcode_dup_1_16::<4>); - opcodes[0x84] = ("DUP5", Self::opcode_dup_1_16::<5>); - opcodes[0x85] = ("DUP6", Self::opcode_dup_1_16::<6>); - opcodes[0x86] = ("DUP7", Self::opcode_dup_1_16::<7>); - opcodes[0x87] = ("DUP8", Self::opcode_dup_1_16::<8>); - opcodes[0x88] = ("DUP9", Self::opcode_dup_1_16::<9>); - opcodes[0x89] = ("DUP10", Self::opcode_dup_1_16::<10>); - opcodes[0x8A] = ("DUP11", Self::opcode_dup_1_16::<11>); - opcodes[0x8B] = ("DUP12", Self::opcode_dup_1_16::<12>); - opcodes[0x8C] = ("DUP13", Self::opcode_dup_1_16::<13>); - opcodes[0x8D] = ("DUP14", Self::opcode_dup_1_16::<14>); - opcodes[0x8E] = ("DUP15", Self::opcode_dup_1_16::<15>); - opcodes[0x8F] = ("DUP16", Self::opcode_dup_1_16::<16>); - - opcodes[0x90] = ("SWAP1", Self::opcode_swap_1_16::<1>); - opcodes[0x91] = ("SWAP2", Self::opcode_swap_1_16::<2>); - opcodes[0x92] = ("SWAP3", Self::opcode_swap_1_16::<3>); - opcodes[0x93] = ("SWAP4", Self::opcode_swap_1_16::<4>); - opcodes[0x94] = ("SWAP5", Self::opcode_swap_1_16::<5>); - opcodes[0x95] = ("SWAP6", Self::opcode_swap_1_16::<6>); - opcodes[0x96] = ("SWAP7", Self::opcode_swap_1_16::<7>); - opcodes[0x97] = ("SWAP8", Self::opcode_swap_1_16::<8>); - opcodes[0x98] = ("SWAP9", Self::opcode_swap_1_16::<9>); - opcodes[0x99] = ("SWAP10", Self::opcode_swap_1_16::<10>); - opcodes[0x9A] = ("SWAP11", Self::opcode_swap_1_16::<11>); - opcodes[0x9B] = ("SWAP12", Self::opcode_swap_1_16::<12>); - opcodes[0x9C] = ("SWAP13", Self::opcode_swap_1_16::<13>); - opcodes[0x9D] = ("SWAP14", Self::opcode_swap_1_16::<14>); - opcodes[0x9E] = ("SWAP15", Self::opcode_swap_1_16::<15>); - opcodes[0x9F] = ("SWAP16", Self::opcode_swap_1_16::<16>); - - opcodes[0xA0] = ("LOG0", Self::opcode_log_0_4::<0>); - opcodes[0xA1] = ("LOG1", Self::opcode_log_0_4::<1>); - opcodes[0xA2] = ("LOG2", Self::opcode_log_0_4::<2>); - opcodes[0xA3] = ("LOG3", Self::opcode_log_0_4::<3>); - opcodes[0xA4] = ("LOG4", Self::opcode_log_0_4::<4>); - - opcodes[0xF0] = ("CREATE", Self::opcode_create); - opcodes[0xF1] = ("CALL", Self::opcode_call); - opcodes[0xF2] = ("CALLCODE", Self::opcode_callcode); - opcodes[0xF3] = ("RETURN", Self::opcode_return); - opcodes[0xF4] = ("DELEGATECALL", Self::opcode_delegatecall); - opcodes[0xF5] = ("CREATE2", Self::opcode_create2); - - opcodes[0xFA] = ("STATICCALL", Self::opcode_staticcall); - - opcodes[0xFD] = ("REVERT", Self::opcode_revert); - opcodes[0xFE] = ("INVALID", Self::opcode_invalid); - - opcodes[0xFF] = ("SELFDESTRUCT", Self::opcode_selfdestruct); - - opcodes - }; +macro_rules! opcode_table { + ($( $opcode:literal, $opname:literal, $op:path;)*) => { + #[cfg(target_os = "solana")] + type OpCode = fn(&mut Machine, &mut B) -> Result; + + #[cfg(target_os = "solana")] + impl Machine { + const OPCODES: [OpCode; 256] = { + let mut opcodes: [OpCode; 256] = [Self::opcode_unknown; 256]; + + $(opcodes[$opcode as usize] = $op;)* + + opcodes + }; + + pub fn execute_opcode(&mut self, backend: &mut B, opcode: u8) -> Result { + // SAFETY: OPCODES.len() == 256, opcode <= 255 + let opcode_fn = unsafe { Self::OPCODES.get_unchecked(opcode as usize) }; + opcode_fn(self, backend) + } + } + + #[cfg(not(target_os = "solana"))] + impl Machine { + pub async fn execute_opcode(&mut self, backend: &mut B, opcode: u8) -> Result { + match opcode { + $($opcode => $op(self, backend).await,)* + _ => Self::opcode_unknown(self, backend).await, + } + } + } + + #[cfg(not(target_os = "solana"))] + pub const OPNAMES: [&str; 256] = { + let mut opnames: [&str; 256] = [""; 256]; + + $(opnames[$opcode as usize] = $opname;)* + + opnames + }; + } } + +opcode_table![ + 0x00, "STOP", Self::opcode_stop; + 0x01, "ADD", Self::opcode_add; + 0x02, "MUL", Self::opcode_mul; + 0x03, "SUB", Self::opcode_sub; + 0x04, "DIV", Self::opcode_div; + 0x05, "SDIV", Self::opcode_sdiv; + 0x06, "MOD", Self::opcode_mod; + 0x07, "SMOD", Self::opcode_smod; + 0x08, "ADDMOD", Self::opcode_addmod; + 0x09, "MULMOD", Self::opcode_mulmod; + 0x0A, "EXP", Self::opcode_exp; + 0x0B, "SIGNEXTEND", Self::opcode_signextend; + + 0x10, "LT", Self::opcode_lt; + 0x11, "GT", Self::opcode_gt; + 0x12, "SLT", Self::opcode_slt; + 0x13, "SGT", Self::opcode_sgt; + 0x14, "EQ", Self::opcode_eq; + 0x15, "ISZERO", Self::opcode_iszero; + 0x16, "AND", Self::opcode_and; + 0x17, "OR", Self::opcode_or; + 0x18, "XOR", Self::opcode_xor; + 0x19, "NOT", Self::opcode_not; + 0x1A, "BYTE", Self::opcode_byte; + 0x1B, "SHL", Self::opcode_shl; + 0x1C, "SHR", Self::opcode_shr; + 0x1D, "SAR", Self::opcode_sar; + + 0x20, "KECCAK256", Self::opcode_sha3; + + 0x30, "ADDRESS", Self::opcode_address; + 0x31, "BALANCE", Self::opcode_balance; + 0x32, "ORIGIN", Self::opcode_origin; + 0x33, "CALLER", Self::opcode_caller; + 0x34, "CALLVALUE", Self::opcode_callvalue; + 0x35, "CALLDATALOAD", Self::opcode_calldataload; + 0x36, "CALLDATASIZE", Self::opcode_calldatasize; + 0x37, "CALLDATACOPY", Self::opcode_calldatacopy; + 0x38, "CODESIZE", Self::opcode_codesize; + 0x39, "CODECOPY", Self::opcode_codecopy; + 0x3A, "GASPRICE", Self::opcode_gasprice; + 0x3B, "EXTCODESIZE", Self::opcode_extcodesize; + 0x3C, "EXTCODECOPY", Self::opcode_extcodecopy; + 0x3D, "RETURNDATASIZE", Self::opcode_returndatasize; + 0x3E, "RETURNDATACOPY", Self::opcode_returndatacopy; + 0x3F, "EXTCODEHASH", Self::opcode_extcodehash; + 0x40, "BLOCKHASH", Self::opcode_blockhash; + 0x41, "COINBASE", Self::opcode_coinbase; + 0x42, "TIMESTAMP", Self::opcode_timestamp; + 0x43, "NUMBER", Self::opcode_number; + 0x44, "PREVRANDAO", Self::opcode_difficulty; + 0x45, "GASLIMIT", Self::opcode_gaslimit; + 0x46, "CHAINID", Self::opcode_chainid; + 0x47, "SELFBALANCE", Self::opcode_selfbalance; + 0x48, "BASEFEE", Self::opcode_basefee; + + 0x50, "POP", Self::opcode_pop; + 0x51, "MLOAD", Self::opcode_mload; + 0x52, "MSTORE", Self::opcode_mstore; + 0x53, "MSTORE8", Self::opcode_mstore8; + 0x54, "SLOAD", Self::opcode_sload; + 0x55, "SSTORE", Self::opcode_sstore; + 0x56, "JUMP", Self::opcode_jump; + 0x57, "JUMPI", Self::opcode_jumpi; + 0x58, "PC", Self::opcode_pc; + 0x59, "MSIZE", Self::opcode_msize; + 0x5A, "GAS", Self::opcode_gas; + 0x5B, "JUMPDEST", Self::opcode_jumpdest; + + 0x5F, "PUSH0", Self::opcode_push_0; + 0x60, "PUSH1", Self::opcode_push_1; + 0x61, "PUSH2", Self::opcode_push_2_31::<2>; + 0x62, "PUSH3", Self::opcode_push_2_31::<3>; + 0x63, "PUSH4", Self::opcode_push_2_31::<4>; + 0x64, "PUSH5", Self::opcode_push_2_31::<5>; + 0x65, "PUSH6", Self::opcode_push_2_31::<6>; + 0x66, "PUSH7", Self::opcode_push_2_31::<7>; + 0x67, "PUSH8", Self::opcode_push_2_31::<8>; + 0x68, "PUSH9", Self::opcode_push_2_31::<9>; + 0x69, "PUSH10", Self::opcode_push_2_31::<10>; + 0x6A, "PUSH11", Self::opcode_push_2_31::<11>; + 0x6B, "PUSH12", Self::opcode_push_2_31::<12>; + 0x6C, "PUSH13", Self::opcode_push_2_31::<13>; + 0x6D, "PUSH14", Self::opcode_push_2_31::<14>; + 0x6E, "PUSH15", Self::opcode_push_2_31::<15>; + 0x6F, "PUSH16", Self::opcode_push_2_31::<16>; + 0x70, "PUSH17", Self::opcode_push_2_31::<17>; + 0x71, "PUSH18", Self::opcode_push_2_31::<18>; + 0x72, "PUSH19", Self::opcode_push_2_31::<19>; + 0x73, "PUSH20", Self::opcode_push_2_31::<20>; + 0x74, "PUSH21", Self::opcode_push_2_31::<21>; + 0x75, "PUSH22", Self::opcode_push_2_31::<22>; + 0x76, "PUSH23", Self::opcode_push_2_31::<23>; + 0x77, "PUSH24", Self::opcode_push_2_31::<24>; + 0x78, "PUSH25", Self::opcode_push_2_31::<25>; + 0x79, "PUSH26", Self::opcode_push_2_31::<26>; + 0x7A, "PUSH27", Self::opcode_push_2_31::<27>; + 0x7B, "PUSH28", Self::opcode_push_2_31::<28>; + 0x7C, "PUSH29", Self::opcode_push_2_31::<29>; + 0x7D, "PUSH30", Self::opcode_push_2_31::<30>; + 0x7E, "PUSH31", Self::opcode_push_2_31::<31>; + 0x7F, "PUSH32", Self::opcode_push_32; + + 0x80, "DUP1", Self::opcode_dup_1_16::<1>; + 0x81, "DUP2", Self::opcode_dup_1_16::<2>; + 0x82, "DUP3", Self::opcode_dup_1_16::<3>; + 0x83, "DUP4", Self::opcode_dup_1_16::<4>; + 0x84, "DUP5", Self::opcode_dup_1_16::<5>; + 0x85, "DUP6", Self::opcode_dup_1_16::<6>; + 0x86, "DUP7", Self::opcode_dup_1_16::<7>; + 0x87, "DUP8", Self::opcode_dup_1_16::<8>; + 0x88, "DUP9", Self::opcode_dup_1_16::<9>; + 0x89, "DUP10", Self::opcode_dup_1_16::<10>; + 0x8A, "DUP11", Self::opcode_dup_1_16::<11>; + 0x8B, "DUP12", Self::opcode_dup_1_16::<12>; + 0x8C, "DUP13", Self::opcode_dup_1_16::<13>; + 0x8D, "DUP14", Self::opcode_dup_1_16::<14>; + 0x8E, "DUP15", Self::opcode_dup_1_16::<15>; + 0x8F, "DUP16", Self::opcode_dup_1_16::<16>; + + 0x90, "SWAP1", Self::opcode_swap_1_16::<1>; + 0x91, "SWAP2", Self::opcode_swap_1_16::<2>; + 0x92, "SWAP3", Self::opcode_swap_1_16::<3>; + 0x93, "SWAP4", Self::opcode_swap_1_16::<4>; + 0x94, "SWAP5", Self::opcode_swap_1_16::<5>; + 0x95, "SWAP6", Self::opcode_swap_1_16::<6>; + 0x96, "SWAP7", Self::opcode_swap_1_16::<7>; + 0x97, "SWAP8", Self::opcode_swap_1_16::<8>; + 0x98, "SWAP9", Self::opcode_swap_1_16::<9>; + 0x99, "SWAP10", Self::opcode_swap_1_16::<10>; + 0x9A, "SWAP11", Self::opcode_swap_1_16::<11>; + 0x9B, "SWAP12", Self::opcode_swap_1_16::<12>; + 0x9C, "SWAP13", Self::opcode_swap_1_16::<13>; + 0x9D, "SWAP14", Self::opcode_swap_1_16::<14>; + 0x9E, "SWAP15", Self::opcode_swap_1_16::<15>; + 0x9F, "SWAP16", Self::opcode_swap_1_16::<16>; + + 0xA0, "LOG0", Self::opcode_log_0_4::<0>; + 0xA1, "LOG1", Self::opcode_log_0_4::<1>; + 0xA2, "LOG2", Self::opcode_log_0_4::<2>; + 0xA3, "LOG3", Self::opcode_log_0_4::<3>; + 0xA4, "LOG4", Self::opcode_log_0_4::<4>; + + 0xF0, "CREATE", Self::opcode_create; + 0xF1, "CALL", Self::opcode_call; + 0xF2, "CALLCODE", Self::opcode_callcode; + 0xF3, "RETURN", Self::opcode_return; + 0xF4, "DELEGATECALL", Self::opcode_delegatecall; + 0xF5, "CREATE2", Self::opcode_create2; + + 0xFA, "STATICCALL", Self::opcode_staticcall; + + 0xFD, "REVERT", Self::opcode_revert; + 0xFE, "INVALID", Self::opcode_invalid; + + 0xFF, "SELFDESTRUCT", Self::opcode_selfdestruct; +]; diff --git a/evm_loader/program/src/evm/precompile/ecrecover.rs b/evm_loader/program/src/evm/precompile/ecrecover.rs index c45186e20..425d074b0 100644 --- a/evm_loader/program/src/evm/precompile/ecrecover.rs +++ b/evm_loader/program/src/evm/precompile/ecrecover.rs @@ -3,6 +3,7 @@ use ethnum::U256; use solana_program::keccak; use solana_program::secp256k1_recover::secp256k1_recover; +#[allow(clippy::manual_let_else)] #[must_use] pub fn ecrecover(input: &[u8]) -> Vec { debug_print!("ecrecover"); diff --git a/evm_loader/program/src/evm/stack.rs b/evm_loader/program/src/evm/stack.rs index 8b7eb2af1..9470e0fd0 100644 --- a/evm_loader/program/src/evm/stack.rs +++ b/evm_loader/program/src/evm/stack.rs @@ -7,8 +7,8 @@ use std::{ use ethnum::{I256, U256}; -#[cfg(feature = "tracing")] -use crate::evm::tracing::TracerTypeOpt; +#[cfg(not(target_os = "solana"))] +use crate::evm::TracerTypeOpt; use crate::{error::Error, types::Address}; use super::tracing_event; @@ -20,12 +20,12 @@ pub struct Stack { begin: *mut u8, end: *mut u8, top: *mut u8, - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] tracer: TracerTypeOpt, } impl Stack { - pub fn new(#[cfg(feature = "tracing")] tracer: TracerTypeOpt) -> Self { + pub fn new(#[cfg(not(target_os = "solana"))] tracer: TracerTypeOpt) -> Self { let (begin, end) = unsafe { let layout = Layout::from_size_align_unchecked(STACK_SIZE, ELEMENT_SIZE); let begin = crate::allocator::EVM.alloc(layout); @@ -42,12 +42,12 @@ impl Stack { begin, end, top: begin, - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] tracer, } } - #[allow(dead_code)] + #[cfg(not(target_os = "solana"))] pub fn to_vec(&self) -> Vec<[u8; 32]> { let slice = unsafe { let start = self.begin.cast::<[u8; 32]>(); @@ -316,7 +316,7 @@ impl<'de> serde::Deserialize<'de> for Stack { } let mut stack = Stack::new( - #[cfg(feature = "tracing")] + #[cfg(not(target_os = "solana"))] None, ); unsafe { diff --git a/evm_loader/program/src/evm/tracing/mod.rs b/evm_loader/program/src/evm/tracing/mod.rs index 024e7d3ed..b30817cb7 100644 --- a/evm_loader/program/src/evm/tracing/mod.rs +++ b/evm_loader/program/src/evm/tracing/mod.rs @@ -1,6 +1,7 @@ +use std::cell::RefCell; use std::collections::HashMap; use std::fmt::Debug; -use std::sync::{Arc, RwLock}; +use std::rc::Rc; use crate::account::EthereumAccount; use crate::executor::Action; @@ -26,7 +27,7 @@ pub trait EventListener: Send + Sync + Debug { fn into_traces(self: Box, emulation_result: EmulationResult) -> Value; } -pub type TracerType = Arc>>; +pub type TracerType = Rc>>; pub type TracerTypeOpt = Option; /// Trace event diff --git a/evm_loader/program/src/evm/tracing/tracers/mod.rs b/evm_loader/program/src/evm/tracing/tracers/mod.rs index 3913a3061..ed98e1af9 100644 --- a/evm_loader/program/src/evm/tracing/tracers/mod.rs +++ b/evm_loader/program/src/evm/tracing/tracers/mod.rs @@ -1,12 +1,13 @@ use crate::evm::tracing::tracers::struct_logger::StructLogger; use crate::evm::tracing::TraceConfig; use crate::evm::tracing::TracerType; -use std::sync::{Arc, RwLock}; +use std::cell::RefCell; +use std::rc::Rc; pub mod struct_logger; pub fn new_tracer(trace_config: &TraceConfig) -> crate::error::Result { - Ok(Arc::new(RwLock::new( + Ok(Rc::new(RefCell::new( match trace_config.tracer.as_deref() { None | Some("") => Box::new(StructLogger::new(trace_config)), _ => { diff --git a/evm_loader/program/src/evm/tracing/tracers/struct_logger.rs b/evm_loader/program/src/evm/tracing/tracers/struct_logger.rs index 6b5380e9b..08ebd2dc1 100644 --- a/evm_loader/program/src/evm/tracing/tracers/struct_logger.rs +++ b/evm_loader/program/src/evm/tracing/tracers/struct_logger.rs @@ -4,11 +4,9 @@ use ethnum::U256; use serde::Serialize; use serde_json::Value; -use crate::account_storage::ProgramAccountStorage; +use crate::evm::opcode_table::OPNAMES; use crate::evm::tracing::TraceConfig; use crate::evm::tracing::{EmulationResult, Event, EventListener}; -use crate::evm::Machine; -use crate::executor::ExecutorState; use crate::types::hexbytes::HexBytes; /// `StructLoggerResult` groups all structured logs emitted by the EVM @@ -68,7 +66,7 @@ impl StructLog { stack: Option>, storage: Option>, ) -> Self { - let (op, _) = Machine::>::OPCODES[opcode as usize]; + let op = OPNAMES[opcode as usize]; Self { pc, op, diff --git a/evm_loader/program/src/executor/action.rs b/evm_loader/program/src/executor/action.rs index 45405f946..83af0d221 100644 --- a/evm_loader/program/src/executor/action.rs +++ b/evm_loader/program/src/executor/action.rs @@ -110,6 +110,7 @@ mod tests { let _deserialized: Action = bincode::deserialize(&serialized).unwrap(); } + #[cfg(not(target_os = "solana"))] #[test] fn roundtrip_json() { let action = Action::EvmSetStorage { diff --git a/evm_loader/program/src/executor/cache.rs b/evm_loader/program/src/executor/cache.rs index dbc8f5f09..062d2829a 100644 --- a/evm_loader/program/src/executor/cache.rs +++ b/evm_loader/program/src/executor/cache.rs @@ -1,11 +1,10 @@ +use std::{cell::RefCell, collections::BTreeMap, rc::Rc}; + use ethnum::U256; use serde::{Deserialize, Serialize}; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; -use std::{cell::RefCell, collections::BTreeMap, rc::Rc}; - -use crate::account_storage::AccountStorage; -#[derive(Serialize, Deserialize, Clone)] +#[derive(Clone, Serialize, Deserialize)] pub struct OwnedAccountInfo { pub key: Pubkey, pub is_signer: bool, @@ -63,15 +62,3 @@ pub struct Cache { #[serde(with = "ethnum::serde::bytes::le")] pub block_timestamp: U256, } - -impl Cache { - pub fn get_account_or_insert( - &mut self, - key: Pubkey, - backend: &B, - ) -> &mut OwnedAccountInfo { - self.solana_accounts - .entry(key) - .or_insert_with(|| backend.clone_solana_account(&key)) - } -} diff --git a/evm_loader/program/src/executor/precompile_extension/metaplex.rs b/evm_loader/program/src/executor/precompile_extension/metaplex.rs index d0358dcd0..180cfed6d 100644 --- a/evm_loader/program/src/executor/precompile_extension/metaplex.rs +++ b/evm_loader/program/src/executor/precompile_extension/metaplex.rs @@ -3,6 +3,7 @@ use std::convert::{Into, TryInto}; use ethnum::U256; +use maybe_async::maybe_async; use mpl_token_metadata::state::{ Creator, Metadata, TokenMetadataAccount, TokenStandard, CREATE_FEE, MAX_MASTER_EDITION_LEN, MAX_METADATA_LEN, @@ -25,8 +26,9 @@ use crate::{ // "[0x69, 0x1f, 0x34, 0x31]": "name(bytes32)" // "[0x6b, 0xaa, 0x03, 0x30]": "symbol(bytes32)" -pub fn metaplex( - state: &mut ExecutorState, +#[maybe_async] +pub async fn metaplex( + state: &mut ExecutorState<'_, B>, address: &Address, input: &[u8], context: &crate::evm::Context, @@ -73,27 +75,27 @@ pub fn metaplex( [0xf7, 0xb6, 0x37, 0xbb] => { // "isInitialized(bytes32)" let mint = read_pubkey(input)?; - is_initialized(context, state, mint) + is_initialized(context, state, mint).await } [0x23, 0x5b, 0x2b, 0x94] => { // "isNFT(bytes32)" let mint = read_pubkey(input)?; - is_nft(context, state, mint) + is_nft(context, state, mint).await } [0x9e, 0xd1, 0x9d, 0xdb] => { // "uri(bytes32)" let mint = read_pubkey(input)?; - uri(context, state, mint) + uri(context, state, mint).await } [0x69, 0x1f, 0x34, 0x31] => { // "name(bytes32)" let mint = read_pubkey(input)?; - token_name(context, state, mint) + token_name(context, state, mint).await } [0x6b, 0xaa, 0x03, 0x30] => { // "symbol(bytes32)" let mint = read_pubkey(input)?; - symbol(context, state, mint) + symbol(context, state, mint).await } _ => Err(Error::UnknownPrecompileMethodSelector(*address, selector)), } @@ -236,22 +238,26 @@ fn create_master_edition( Ok(edition_pubkey.to_bytes().to_vec()) } -fn is_initialized( +#[maybe_async] +async fn is_initialized( context: &crate::evm::Context, - state: &mut ExecutorState, + state: &mut ExecutorState<'_, B>, mint: Pubkey, ) -> Result> { - let is_initialized = metadata(context, state, mint)?.map_or_else(|| false, |_| true); + let is_initialized = metadata(context, state, mint) + .await? + .map_or_else(|| false, |_| true); Ok(to_solidity_bool(is_initialized)) } -fn is_nft( +#[maybe_async] +async fn is_nft( context: &crate::evm::Context, - state: &mut ExecutorState, + state: &mut ExecutorState<'_, B>, mint: Pubkey, ) -> Result> { - let is_nft = metadata(context, state, mint)?.map_or_else( + let is_nft = metadata(context, state, mint).await?.map_or_else( || false, |m| m.token_standard == Some(TokenStandard::NonFungible), ); @@ -259,43 +265,53 @@ fn is_nft( Ok(to_solidity_bool(is_nft)) } -fn uri( +#[maybe_async] +async fn uri( context: &crate::evm::Context, - state: &mut ExecutorState, + state: &mut ExecutorState<'_, B>, mint: Pubkey, ) -> Result> { - let uri = metadata(context, state, mint)?.map_or_else(String::new, |m| m.data.uri); + let uri = metadata(context, state, mint) + .await? + .map_or_else(String::new, |m| m.data.uri); Ok(to_solidity_string(uri.trim_end_matches('\0'))) } -fn token_name( +#[maybe_async] +async fn token_name( context: &crate::evm::Context, - state: &mut ExecutorState, + state: &mut ExecutorState<'_, B>, mint: Pubkey, ) -> Result> { - let token_name = metadata(context, state, mint)?.map_or_else(String::new, |m| m.data.name); + let token_name = metadata(context, state, mint) + .await? + .map_or_else(String::new, |m| m.data.name); Ok(to_solidity_string(token_name.trim_end_matches('\0'))) } -fn symbol( +#[maybe_async] +async fn symbol( context: &crate::evm::Context, - state: &mut ExecutorState, + state: &mut ExecutorState<'_, B>, mint: Pubkey, ) -> Result> { - let symbol = metadata(context, state, mint)?.map_or_else(String::new, |m| m.data.symbol); + let symbol = metadata(context, state, mint) + .await? + .map_or_else(String::new, |m| m.data.symbol); Ok(to_solidity_string(symbol.trim_end_matches('\0'))) } -fn metadata( +#[maybe_async] +async fn metadata( _context: &crate::evm::Context, - state: &mut ExecutorState, + state: &mut ExecutorState<'_, B>, mint: Pubkey, ) -> Result> { let (metadata_pubkey, _) = mpl_token_metadata::pda::find_metadata_account(&mint); - let metadata_account = state.external_account(metadata_pubkey)?; + let metadata_account = state.external_account(metadata_pubkey).await?; let result = { if mpl_token_metadata::check_id(&metadata_account.owner) { diff --git a/evm_loader/program/src/executor/precompile_extension/mod.rs b/evm_loader/program/src/executor/precompile_extension/mod.rs index 06870b608..3936615b0 100644 --- a/evm_loader/program/src/executor/precompile_extension/mod.rs +++ b/evm_loader/program/src/executor/precompile_extension/mod.rs @@ -1,4 +1,5 @@ use crate::{account_storage::AccountStorage, error::Result, evm::Context, types::Address}; +use maybe_async::maybe_async; use super::ExecutorState; @@ -34,7 +35,8 @@ impl<'a, B: AccountStorage> ExecutorState<'a, B> { || *address == Self::SYSTEM_ACCOUNT_METAPLEX } - pub fn call_precompile_extension( + #[maybe_async] + pub async fn call_precompile_extension( &mut self, context: &Context, address: &Address, @@ -42,17 +44,17 @@ impl<'a, B: AccountStorage> ExecutorState<'a, B> { is_static: bool, ) -> Option>> { match *address { - Self::SYSTEM_ACCOUNT_QUERY => Some(query_account::query_account( - self, address, input, context, is_static, - )), - Self::SYSTEM_ACCOUNT_NEON_TOKEN => Some(neon_token::neon_token( - self, address, input, context, is_static, - )), - Self::SYSTEM_ACCOUNT_SPL_TOKEN => Some(spl_token::spl_token( - self, address, input, context, is_static, - )), + Self::SYSTEM_ACCOUNT_QUERY => { + Some(query_account::query_account(self, address, input, context, is_static).await) + } + Self::SYSTEM_ACCOUNT_NEON_TOKEN => { + Some(neon_token::neon_token(self, address, input, context, is_static).await) + } + Self::SYSTEM_ACCOUNT_SPL_TOKEN => { + Some(spl_token::spl_token(self, address, input, context, is_static).await) + } Self::SYSTEM_ACCOUNT_METAPLEX => { - Some(metaplex::metaplex(self, address, input, context, is_static)) + Some(metaplex::metaplex(self, address, input, context, is_static).await) } _ => None, } diff --git a/evm_loader/program/src/executor/precompile_extension/neon_token.rs b/evm_loader/program/src/executor/precompile_extension/neon_token.rs index 0f33d5f24..4247acd0c 100644 --- a/evm_loader/program/src/executor/precompile_extension/neon_token.rs +++ b/evm_loader/program/src/executor/precompile_extension/neon_token.rs @@ -2,6 +2,7 @@ use std::convert::TryInto; use arrayref::array_ref; use ethnum::U256; +use maybe_async::maybe_async; use solana_program::{program_pack::Pack, pubkey::Pubkey, rent::Rent, sysvar::Sysvar}; use spl_associated_token_account::get_associated_token_address; @@ -18,8 +19,9 @@ use crate::{ //-------------------------------------------------- const NEON_TOKEN_METHOD_WITHDRAW_ID: &[u8; 4] = &[0x8e, 0x19, 0x89, 0x9e]; -pub fn neon_token( - state: &mut ExecutorState, +#[maybe_async] +pub async fn neon_token( + state: &mut ExecutorState<'_, B>, address: &Address, input: &[u8], context: &crate::evm::Context, @@ -46,7 +48,7 @@ pub fn neon_token( let destination = array_ref![rest, 0, 32]; let destination = Pubkey::new_from_array(*destination); - withdraw(state, source, destination, context.value)?; + withdraw(state, source, destination, context.value).await?; let mut output = vec![0_u8; 32]; output[31] = 1; // return true @@ -58,8 +60,9 @@ pub fn neon_token( Err(Error::UnknownPrecompileMethodSelector(*address, *method_id)) } -fn withdraw( - state: &mut ExecutorState, +#[maybe_async] +async fn withdraw( + state: &mut ExecutorState<'_, B>, source: Address, target: Pubkey, value: U256, @@ -87,7 +90,7 @@ fn withdraw( } let target_token = get_associated_token_address(&target, state.backend.neon_token_mint()); - let account = state.external_account(target_token)?; + let account = state.external_account(target_token).await?; if !spl_token::check_id(&account.owner) { use spl_associated_token_account::instruction::create_associated_token_account; diff --git a/evm_loader/program/src/executor/precompile_extension/query_account.rs b/evm_loader/program/src/executor/precompile_extension/query_account.rs index 637e7d80f..37ae38f06 100644 --- a/evm_loader/program/src/executor/precompile_extension/query_account.rs +++ b/evm_loader/program/src/executor/precompile_extension/query_account.rs @@ -2,6 +2,7 @@ use std::convert::TryInto; use arrayref::{array_ref, array_refs}; use ethnum::U256; +use maybe_async::maybe_async; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; use crate::{ @@ -30,8 +31,9 @@ use crate::{ // "a9dbaf25": "length(bytes32)", // "7dd6c1a0": "data(bytes32,uint64,uint64)", -pub fn query_account( - state: &mut ExecutorState, +#[maybe_async] +pub async fn query_account( + state: &mut ExecutorState<'_, B>, address: &Address, input: &[u8], context: &crate::evm::Context, @@ -57,23 +59,23 @@ pub fn query_account( } [0xa1, 0x23, 0xc3, 0x3e] | [0x02, 0x57, 0x1b, 0xe3] => { debug_print!("query_account.owner({})", &account_address); - account_owner(state, &account_address) + account_owner(state, &account_address).await } [0xaa, 0x8b, 0x99, 0xd2] | [0xa9, 0xdb, 0xaf, 0x25] => { debug_print!("query_account.length({})", &account_address); - account_data_length(state, &account_address) + account_data_length(state, &account_address).await } [0x74, 0x8f, 0x2d, 0x8a] | [0x62, 0x73, 0x44, 0x8f] => { debug_print!("query_account.lamports({})", &account_address); - account_lamports(state, &account_address) + account_lamports(state, &account_address).await } [0xc2, 0x19, 0xa7, 0x85] | [0xe6, 0xbe, 0xf4, 0x88] => { debug_print!("query_account.executable({})", &account_address); - account_is_executable(state, &account_address) + account_is_executable(state, &account_address).await } [0xc4, 0xd3, 0x69, 0xb5] | [0x8b, 0xb9, 0xe6, 0xf4] => { debug_print!("query_account.rent_epoch({})", &account_address); - account_rent_epoch(state, &account_address) + account_rent_epoch(state, &account_address).await } [0x43, 0xca, 0x51, 0x61] | [0x7d, 0xd6, 0xc1, 0xa0] => { let arguments = array_ref![rest, 0, 64]; @@ -86,11 +88,11 @@ pub fn query_account( offset, length ); - account_data(state, &account_address, offset, length) + account_data(state, &account_address, offset, length).await } [0xb6, 0x4a, 0x09, 0x7e] => { debug_print!("query_account.info({})", &account_address); - account_info(state, &account_address) + account_info(state, &account_address).await } _ => { debug_print!("query_account UNKNOWN {:?}", method_id); @@ -100,25 +102,29 @@ pub fn query_account( } #[allow(clippy::unnecessary_wraps)] -fn account_owner( - state: &mut ExecutorState, +#[maybe_async] +async fn account_owner( + state: &mut ExecutorState<'_, B>, address: &Pubkey, ) -> Result> { let owner = state .backend - .map_solana_account(address, |info| info.owner.to_bytes()); + .map_solana_account(address, |info| info.owner.to_bytes()) + .await; Ok(owner.to_vec()) } #[allow(clippy::unnecessary_wraps)] -fn account_lamports( - state: &mut ExecutorState, +#[maybe_async] +async fn account_lamports( + state: &mut ExecutorState<'_, B>, address: &Pubkey, ) -> Result> { let lamports: U256 = state .backend .map_solana_account(address, |info| **info.lamports.borrow()) + .await .into(); let bytes = lamports.to_be_bytes().to_vec(); @@ -127,13 +133,15 @@ fn account_lamports( } #[allow(clippy::unnecessary_wraps)] -fn account_rent_epoch( - state: &mut ExecutorState, +#[maybe_async] +async fn account_rent_epoch( + state: &mut ExecutorState<'_, B>, address: &Pubkey, ) -> Result> { let epoch: U256 = state .backend .map_solana_account(address, |info| info.rent_epoch) + .await .into(); let bytes = epoch.to_be_bytes().to_vec(); @@ -142,13 +150,15 @@ fn account_rent_epoch( } #[allow(clippy::unnecessary_wraps)] -fn account_is_executable( - state: &mut ExecutorState, +#[maybe_async] +async fn account_is_executable( + state: &mut ExecutorState<'_, B>, address: &Pubkey, ) -> Result> { let executable: U256 = state .backend .map_solana_account(address, |info| info.executable) + .await .into(); let bytes = executable.to_be_bytes().to_vec(); @@ -157,13 +167,15 @@ fn account_is_executable( } #[allow(clippy::unnecessary_wraps)] -fn account_data_length( - state: &mut ExecutorState, +#[maybe_async] +async fn account_data_length( + state: &mut ExecutorState<'_, B>, address: &Pubkey, ) -> Result> { let length: U256 = state .backend .map_solana_account(address, |info| info.data.borrow().len()) + .await .try_into()?; let bytes = length.to_be_bytes().to_vec(); @@ -172,8 +184,9 @@ fn account_data_length( } #[allow(clippy::unnecessary_wraps)] -fn account_data( - state: &mut ExecutorState, +#[maybe_async] +async fn account_data( + state: &mut ExecutorState<'_, B>, address: &Pubkey, offset: usize, length: usize, @@ -192,12 +205,14 @@ fn account_data( .get(offset..offset + length) .map(<[u8]>::to_vec) }) + .await .ok_or_else(|| Error::Custom("Query Account: data() - out of bounds".to_string())) } #[allow(clippy::unnecessary_wraps)] -fn account_info( - state: &mut ExecutorState, +#[maybe_async] +async fn account_info( + state: &mut ExecutorState<'_, B>, address: &Pubkey, ) -> Result> { fn to_solidity_account_value(info: &AccountInfo) -> Vec { @@ -216,7 +231,8 @@ fn account_info( let info = state .backend - .map_solana_account(address, to_solidity_account_value); + .map_solana_account(address, to_solidity_account_value) + .await; Ok(info) } diff --git a/evm_loader/program/src/executor/precompile_extension/spl_token.rs b/evm_loader/program/src/executor/precompile_extension/spl_token.rs index 674f95419..7d3502b33 100644 --- a/evm_loader/program/src/executor/precompile_extension/spl_token.rs +++ b/evm_loader/program/src/executor/precompile_extension/spl_token.rs @@ -1,6 +1,7 @@ use std::convert::{Into, TryInto}; use ethnum::U256; +use maybe_async::maybe_async; use solana_program::{ program_error::ProgramError, program_pack::Pack, pubkey::Pubkey, rent::Rent, system_instruction, system_program, sysvar::Sysvar, @@ -33,8 +34,9 @@ use crate::{ // [0x7c, 0x0e, 0xb8, 0x10] : "transferWithSeed(bytes32,bytes32,bytes32,uint64)" #[allow(clippy::too_many_lines)] -pub fn spl_token( - state: &mut ExecutorState, +#[maybe_async] +pub async fn spl_token( + state: &mut ExecutorState<'_, B>, address: &Address, input: &[u8], context: &crate::evm::Context, @@ -63,7 +65,7 @@ pub fn spl_token( let seed = read_salt(input)?; let decimals = read_u8(&input[32..])?; - initialize_mint(context, state, seed, decimals, None, None) + initialize_mint(context, state, seed, decimals, None, None).await } [0xc3, 0xf3, 0xf2, 0xf2] => { // initializeMint(bytes32 seed, uint8 decimals, bytes32 mint_authority, bytes32 freeze_authority) @@ -83,6 +85,7 @@ pub fn spl_token( Some(mint_authority), Some(freeze_authority), ) + .await } [0xda, 0xa1, 0x2c, 0x5c] => { // initializeAccount(bytes32 seed, bytes32 mint) @@ -93,7 +96,7 @@ pub fn spl_token( let seed = read_salt(input)?; let mint = read_pubkey(&input[32..])?; - initialize_account(context, state, seed, mint, None) + initialize_account(context, state, seed, mint, None).await } [0xfc, 0x86, 0xb7, 0x17] => { // initializeAccount(bytes32 seed, bytes32 mint, bytes32 owner) @@ -104,7 +107,7 @@ pub fn spl_token( let seed = read_salt(input)?; let mint = read_pubkey(&input[32..])?; let owner = read_pubkey(&input[64..])?; - initialize_account(context, state, seed, mint, Some(owner)) + initialize_account(context, state, seed, mint, Some(owner)).await } [0x57, 0x82, 0xa0, 0x43] => { // closeAccount(bytes32 account) @@ -209,17 +212,17 @@ pub fn spl_token( [0x6d, 0xa9, 0xde, 0x75] => { // isSystemAccount(bytes32 account) let account = read_pubkey(input)?; - is_system_account(context, state, account) + is_system_account(context, state, account).await } [0xd1, 0xde, 0x50, 0x11] => { // getAccount(bytes32 account) let account = read_pubkey(input)?; - get_account(context, state, account) + get_account(context, state, account).await } [0xa2, 0xce, 0x9c, 0x1f] => { // getMint(bytes32 account) let account = read_pubkey(input)?; - get_mint(context, state, account) + get_mint(context, state, account).await } _ => Err(Error::UnknownPrecompileMethodSelector(*address, selector)), } @@ -281,9 +284,10 @@ fn create_account( Ok(()) } -fn initialize_mint( +#[maybe_async] +async fn initialize_mint( context: &crate::evm::Context, - state: &mut ExecutorState, + state: &mut ExecutorState<'_, B>, seed: &[u8], decimals: u8, mint_authority: Option, @@ -302,7 +306,7 @@ fn initialize_mint( state.backend.program_id(), ); - let account = state.external_account(mint_key)?; + let account = state.external_account(mint_key).await?; if !system_program::check_id(&account.owner) { return Err(Error::AccountInvalidOwner(mint_key, system_program::ID)); } @@ -329,9 +333,10 @@ fn initialize_mint( Ok(mint_key.to_bytes().to_vec()) } -fn initialize_account( +#[maybe_async] +async fn initialize_account( context: &crate::evm::Context, - state: &mut ExecutorState, + state: &mut ExecutorState<'_, B>, seed: &[u8], mint: Pubkey, owner: Option, @@ -349,7 +354,7 @@ fn initialize_account( state.backend.program_id(), ); - let account = state.external_account(account_key)?; + let account = state.external_account(account_key).await?; if !system_program::check_id(&account.owner) { return Err(Error::AccountInvalidOwner(account_key, system_program::ID)); } @@ -652,12 +657,13 @@ fn find_account( Ok(account_key.to_bytes().to_vec()) } -fn is_system_account( +#[maybe_async] +async fn is_system_account( _context: &crate::evm::Context, - state: &mut ExecutorState, + state: &mut ExecutorState<'_, B>, account: Pubkey, ) -> Result> { - let account = state.external_account(account)?; + let account = state.external_account(account).await?; if system_program::check_id(&account.owner) { let mut result = vec![0_u8; 32]; result[31] = 1; // return true @@ -668,12 +674,13 @@ fn is_system_account( } } -fn get_account( +#[maybe_async] +async fn get_account( _context: &crate::evm::Context, - state: &mut ExecutorState, + state: &mut ExecutorState<'_, B>, account: Pubkey, ) -> Result> { - let account = state.external_account(account)?; + let account = state.external_account(account).await?; let token = if spl_token::check_id(&account.owner) { spl_token::state::Account::unpack(&account.data)? } else if system_program::check_id(&account.owner) { @@ -702,12 +709,13 @@ fn get_account( Ok(result.to_vec()) } -fn get_mint( +#[maybe_async] +async fn get_mint( _context: &crate::evm::Context, - state: &mut ExecutorState, + state: &mut ExecutorState<'_, B>, account: Pubkey, ) -> Result> { - let account = state.external_account(account)?; + let account = state.external_account(account).await?; let mint = if spl_token::check_id(&account.owner) { spl_token::state::Mint::unpack(&account.data)? } else if system_program::check_id(&account.owner) { diff --git a/evm_loader/program/src/executor/state.rs b/evm_loader/program/src/executor/state.rs index 031d855f3..0d04a36c1 100644 --- a/evm_loader/program/src/executor/state.rs +++ b/evm_loader/program/src/executor/state.rs @@ -2,6 +2,7 @@ use std::cell::RefCell; use std::collections::BTreeMap; use ethnum::{AsU256, U256}; +use maybe_async::maybe_async; use solana_program::instruction::Instruction; use solana_program::pubkey::Pubkey; @@ -103,9 +104,8 @@ impl<'a, B: AccountStorage> ExecutorState<'a, B> { self.actions.push(action); } - pub fn external_account(&self, address: Pubkey) -> Result { - let mut cache = self.cache.borrow_mut(); - + #[maybe_async] + pub async fn external_account(&self, address: Pubkey) -> Result { let metas = self .actions .iter() @@ -120,18 +120,30 @@ impl<'a, B: AccountStorage> ExecutorState<'a, B> { .collect::>(); if !metas.iter().any(|m| (m.pubkey == address) && m.is_writable) { - return Ok(cache.get_account_or_insert(address, self.backend).clone()); + insert_account_if_not_present(&self.cache, address, self.backend).await; + return Ok(self + .cache + .borrow() + .solana_accounts + .get(&address) + .unwrap() + .clone()); } - let mut accounts = metas - .into_iter() - .map(|m| { - ( - m.pubkey, - cache.get_account_or_insert(m.pubkey, self.backend).clone(), - ) - }) - .collect::>(); + let mut accounts = BTreeMap::::new(); + + for m in metas { + insert_account_if_not_present(&self.cache, m.pubkey, self.backend).await; + accounts.insert( + m.pubkey, + self.cache + .borrow() + .solana_accounts + .get(&m.pubkey) + .unwrap() + .clone(), + ); + } for action in &self.actions { if let Action::ExternalInstruction { @@ -171,14 +183,30 @@ impl<'a, B: AccountStorage> ExecutorState<'a, B> { } } +#[maybe_async] +async fn insert_account_if_not_present( + cache: &RefCell, + key: Pubkey, + backend: &B, +) { + if !cache.borrow().solana_accounts.contains_key(&key) { + let owned_account_info = backend.clone_solana_account(&key).await; + cache + .borrow_mut() + .solana_accounts + .insert(key, owned_account_info); + } +} + +#[maybe_async(?Send)] impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { fn chain_id(&self) -> U256 { let chain_id = self.backend.chain_id(); U256::from(chain_id) } - fn nonce(&self, from_address: &Address) -> Result { - let mut nonce = self.backend.nonce(from_address); + async fn nonce(&self, from_address: &Address) -> Result { + let mut nonce = self.backend.nonce(from_address).await; for action in &self.actions { if let Action::EvmIncrementNonce { address } = action { @@ -198,8 +226,8 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { Ok(()) } - fn balance(&self, from_address: &Address) -> Result { - let mut balance = self.backend.balance(from_address); + async fn balance(&self, from_address: &Address) -> Result { + let mut balance = self.backend.balance(from_address).await; for action in &self.actions { match action { @@ -228,7 +256,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { Ok(balance) } - fn transfer(&mut self, source: Address, target: Address, value: U256) -> Result<()> { + async fn transfer(&mut self, source: Address, target: Address, value: U256) -> Result<()> { if value == U256::ZERO { return Ok(()); } @@ -237,7 +265,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { return Ok(()); } - if self.balance(&source)? < value { + if self.balance(&source).await? < value { return Err(Error::InsufficientBalance(source, value)); } @@ -251,7 +279,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { Ok(()) } - fn code_size(&self, from_address: &Address) -> Result { + async fn code_size(&self, from_address: &Address) -> Result { if self.is_precompile_extension(from_address) { return Ok(1); // This is required in order to make a normal call to an extension contract } @@ -264,10 +292,10 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { } } - Ok(self.backend.code_size(from_address)) + Ok(self.backend.code_size(from_address).await) } - fn code_hash(&self, from_address: &Address) -> Result<[u8; 32]> { + async fn code_hash(&self, from_address: &Address) -> Result<[u8; 32]> { use solana_program::keccak::hash; for action in &self.actions { @@ -278,10 +306,10 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { } } - Ok(self.backend.code_hash(from_address)) + Ok(self.backend.code_hash(from_address).await) } - fn code(&self, from_address: &Address) -> Result { + async fn code(&self, from_address: &Address) -> Result { for action in &self.actions { if let Action::EvmSetCode { address, code } = action { if from_address == address { @@ -290,7 +318,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { } } - Ok(self.backend.code(from_address)) + Ok(self.backend.code(from_address).await) } fn set_code(&mut self, address: Address, code: crate::evm::Buffer) -> Result<()> { @@ -317,7 +345,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { Ok(()) } - fn storage(&self, from_address: &Address, from_index: &U256) -> Result<[u8; 32]> { + async fn storage(&self, from_address: &Address, from_index: &U256) -> Result<[u8; 32]> { for action in self.actions.iter().rev() { if let Action::EvmSetStorage { address, @@ -331,7 +359,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { } } - Ok(self.backend.storage(from_address, from_index)) + Ok(self.backend.storage(from_address, from_index).await) } fn set_storage(&mut self, address: Address, index: U256, value: [u8; 32]) -> Result<()> { @@ -345,7 +373,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { Ok(()) } - fn block_hash(&self, number: U256) -> Result<[u8; 32]> { + async fn block_hash(&self, number: U256) -> Result<[u8; 32]> { // geth: // - checks the overflow // - converts to u64 @@ -367,7 +395,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { return Ok(<[u8; 32]>::default()); } - Ok(self.backend.block_hash(number)) + Ok(self.backend.block_hash(number).await) } fn block_number(&self) -> Result { @@ -380,11 +408,11 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { Ok(cache.block_timestamp) } - fn map_solana_account(&self, address: &Pubkey, action: F) -> R + async fn map_solana_account(&self, address: &Pubkey, action: F) -> R where F: FnOnce(&solana_program::account_info::AccountInfo) -> R, { - self.backend.map_solana_account(address, action) + self.backend.map_solana_account(address, action).await } fn snapshot(&mut self) { @@ -412,7 +440,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { .expect("Fatal Error: Inconsistent EVM Call Stack"); } - fn precompile_extension( + async fn precompile_extension( &mut self, context: &Context, address: &Address, @@ -420,5 +448,6 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { is_static: bool, ) -> Option>> { self.call_precompile_extension(context, address, data, is_static) + .await } } diff --git a/evm_loader/program/src/instruction/transaction_execute.rs b/evm_loader/program/src/instruction/transaction_execute.rs index 28acefcb4..3fdd83405 100644 --- a/evm_loader/program/src/instruction/transaction_execute.rs +++ b/evm_loader/program/src/instruction/transaction_execute.rs @@ -54,13 +54,7 @@ pub fn execute<'a>( let (exit_reason, apply_state) = { let mut backend = ExecutorState::new(account_storage); - let mut evm = Machine::new( - trx, - caller_address, - &mut backend, - #[cfg(feature = "tracing")] - None, - )?; + let mut evm = Machine::new(trx, caller_address, &mut backend)?; let (result, _) = evm.execute(u64::MAX, &mut backend)?; let actions = backend.into_actions(); diff --git a/evm_loader/program/src/instruction/transaction_step.rs b/evm_loader/program/src/instruction/transaction_step.rs index 3396ec5d0..7b1aa8ef6 100644 --- a/evm_loader/program/src/instruction/transaction_step.rs +++ b/evm_loader/program/src/instruction/transaction_step.rs @@ -38,13 +38,7 @@ pub fn do_begin<'a>( account_storage.block_accounts(true); let mut backend = ExecutorState::new(account_storage); - let evm = Machine::new( - trx, - caller, - &mut backend, - #[cfg(feature = "tracing")] - None, - )?; + let evm = Machine::new(trx, caller, &mut backend)?; serialize_evm_state(&mut storage, &backend, &evm)?; diff --git a/evm_loader/program/src/lib.rs b/evm_loader/program/src/lib.rs index aaa79338a..005757f81 100644 --- a/evm_loader/program/src/lib.rs +++ b/evm_loader/program/src/lib.rs @@ -6,7 +6,8 @@ #![allow( clippy::module_name_repetitions, clippy::missing_const_for_fn, - clippy::use_self + clippy::use_self, + clippy::future_not_send )] #![allow(missing_docs, clippy::missing_panics_doc, clippy::missing_errors_doc)] @@ -18,11 +19,13 @@ pub mod error; pub mod account; pub mod account_storage; pub mod config; +#[cfg(target_os = "solana")] pub mod entrypoint; pub mod evm; pub mod executor; pub mod external_programs; pub mod gasometer; +#[cfg(target_os = "solana")] pub mod instruction; pub mod state_account; pub mod types; diff --git a/evm_loader/program/src/state_account.rs b/evm_loader/program/src/state_account.rs index e93407ba1..7e4c520c7 100644 --- a/evm_loader/program/src/state_account.rs +++ b/evm_loader/program/src/state_account.rs @@ -1,15 +1,23 @@ -use crate::{ - account::{program, EthereumAccount, FinalizedState, Holder, Incinerator, Operator, State}, - config::OPERATOR_PRIORITY_SLOTS, - error::Error, - types::{Address, Transaction}, +#[cfg(target_os = "solana")] +use { + crate::account::program, + crate::types::{Address, Transaction}, + ethnum::U256, }; -use ethnum::U256; -use solana_program::{ - account_info::AccountInfo, clock::Clock, program_error::ProgramError, pubkey::Pubkey, - sysvar::Sysvar, + +use { + crate::account::EthereumAccount, + crate::account::Holder, + crate::config::OPERATOR_PRIORITY_SLOTS, + crate::error::Error, + solana_program::account_info::AccountInfo, + solana_program::clock::Clock, + solana_program::sysvar::Sysvar, + std::cell::{Ref, RefMut}, }; -use std::cell::{Ref, RefMut}; + +use crate::account::{FinalizedState, Incinerator, Operator, State}; +use solana_program::{program_error::ProgramError, pubkey::Pubkey}; const ACCOUNT_CHUNK_LEN: usize = 1 + 1 + 32; @@ -34,6 +42,7 @@ impl<'a> FinalizedState<'a> { } impl<'a> State<'a> { + #[cfg(target_os = "solana")] pub fn new( program_id: &'a Pubkey, info: &'a AccountInfo<'a>, @@ -136,6 +145,7 @@ impl<'a> State<'a> { Ok(finalized) } + #[cfg(target_os = "solana")] fn make_deposit( &self, system_program: &program::System<'a>, @@ -186,6 +196,7 @@ impl<'a> State<'a> { Ok(accounts) } + #[cfg(target_os = "solana")] fn write_blocked_accounts( &mut self, program_id: &Pubkey, diff --git a/evm_loader/program/src/types/mod.rs b/evm_loader/program/src/types/mod.rs index 422350278..06000d18f 100644 --- a/evm_loader/program/src/types/mod.rs +++ b/evm_loader/program/src/types/mod.rs @@ -6,5 +6,6 @@ pub use transaction::Transaction; pub use transaction::TransactionPayload; mod address; +#[cfg(not(target_os = "solana"))] pub mod hexbytes; mod transaction; diff --git a/evm_loader/program/src/types/transaction.rs b/evm_loader/program/src/types/transaction.rs index 7d4d5a664..b6d1e202f 100644 --- a/evm_loader/program/src/types/transaction.rs +++ b/evm_loader/program/src/types/transaction.rs @@ -20,6 +20,7 @@ impl rlp::Decodable for StorageKey { } } +#[cfg(not(target_os = "solana"))] impl TryFrom for StorageKey { type Error = String; From dda5a76a9efbd3f08c45304e6894b62355175688 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Wed, 27 Sep 2023 13:25:49 +0300 Subject: [PATCH 037/318] NDEV-2222: Revert env!(NEON_REVISION) initialization (#206) --- evm_loader/lib/src/commands/init_environment.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/evm_loader/lib/src/commands/init_environment.rs b/evm_loader/lib/src/commands/init_environment.rs index 018b2443d..028bf82b0 100644 --- a/evm_loader/lib/src/commands/init_environment.rs +++ b/evm_loader/lib/src/commands/init_environment.rs @@ -139,16 +139,14 @@ pub async fn execute( let program_parameters = Parameters::new(read_elf_parameters(config, &data)); let neon_revision = program_parameters.get::("NEON_REVISION")?; - let build_neon_revision = - build_info::format!("{}", $.version_control.unwrap().git().unwrap().commit_id); - if neon_revision != build_neon_revision { + if neon_revision != env!("NEON_REVISION") { if force { warn!("NeonEVM revision doesn't match CLI revision. This check has been disabled with `--force` flag"); } else { error!("NeonEVM revision doesn't match CLI revision. Use appropriate neon-cli version or add `--force` flag"); return Err(EnvironmentError::RevisionMismatch( neon_revision, - build_neon_revision.to_string(), + env!("NEON_REVISION").to_string(), ) .into()); } From ff805af9eadc386354ad5413f181d2e69db7e0dc Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Wed, 27 Sep 2023 13:25:23 +0100 Subject: [PATCH 038/318] Fix bn256 precompile arguments (#205) --- .../program/src/evm/precompile/bn256.rs | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/evm_loader/program/src/evm/precompile/bn256.rs b/evm_loader/program/src/evm/precompile/bn256.rs index dfc2f4daa..a9405cf1d 100644 --- a/evm_loader/program/src/evm/precompile/bn256.rs +++ b/evm_loader/program/src/evm/precompile/bn256.rs @@ -1,19 +1,42 @@ +use ethnum::U256; use solana_program::alt_bn128::prelude::*; /// Call inner `bn256Add` #[must_use] pub fn bn256_add(input: &[u8]) -> Vec { - alt_bn128_addition(input).unwrap_or_else(|_| vec![]) + if input.len() >= ALT_BN128_ADDITION_INPUT_LEN { + alt_bn128_addition(&input[..ALT_BN128_ADDITION_INPUT_LEN]) + } else { + let mut buffer = vec![0_u8; ALT_BN128_ADDITION_INPUT_LEN]; + buffer[..input.len()].copy_from_slice(input); + alt_bn128_addition(&buffer) + } + .unwrap() } /// Call inner `bn256ScalarMul` #[must_use] pub fn bn256_scalar_mul(input: &[u8]) -> Vec { - alt_bn128_multiplication(input).unwrap_or_else(|_| vec![]) + if input.len() >= ALT_BN128_MULTIPLICATION_INPUT_LEN { + alt_bn128_multiplication(&input[..ALT_BN128_MULTIPLICATION_INPUT_LEN]) + } else { + let mut buffer = vec![0_u8; ALT_BN128_MULTIPLICATION_INPUT_LEN]; + buffer[..input.len()].copy_from_slice(input); + alt_bn128_multiplication(&buffer) + } + .unwrap() } /// Call inner `bn256Pairing` #[must_use] pub fn bn256_pairing(input: &[u8]) -> Vec { - alt_bn128_pairing(input).unwrap_or_else(|_| vec![]) + if input.is_empty() { + return U256::ONE.to_be_bytes().to_vec(); + } + + if (input.len() % ALT_BN128_PAIRING_ELEMENT_LEN) != 0 { + return U256::ZERO.to_be_bytes().to_vec(); + } + + alt_bn128_pairing(input).unwrap() } From 59f0ebd2f8176a65e29e9107ae0d7d6f0164e419 Mon Sep 17 00:00:00 2001 From: Kristina Nikolaeva <112946046+kristinaNikolaevaa@users.noreply.github.com> Date: Thu, 28 Sep 2023 19:59:26 +0200 Subject: [PATCH 039/318] move tests from evm_loader folder (#207) * move tests from evm_loader folder * chmod --- .github/workflows/deploy.py | 8 +- Dockerfile | 32 +- {evm_loader => ci}/create-test-accounts.sh | 0 {evm_loader => ci}/deploy-evm.sh | 0 {evm_loader => ci}/deploy-test.sh | 0 {evm_loader => ci}/docker-compose-ci.yml | 0 {evm_loader => ci}/docker-compose-test.yml | 0 {evm_loader => ci}/evm_loader-keypair.json | 0 .../keys/neon_token_keypair.json | 0 {evm_loader => ci}/operator-keypairs/id.json | 0 .../operator-keypairs/id10.json | 0 .../operator-keypairs/id11.json | 0 .../operator-keypairs/id12.json | 0 .../operator-keypairs/id13.json | 0 .../operator-keypairs/id14.json | 0 .../operator-keypairs/id15.json | 0 .../operator-keypairs/id16.json | 0 .../operator-keypairs/id17.json | 0 .../operator-keypairs/id18.json | 0 .../operator-keypairs/id19.json | 0 {evm_loader => ci}/operator-keypairs/id2.json | 0 .../operator-keypairs/id20.json | 0 .../operator-keypairs/id21.json | 0 .../operator-keypairs/id22.json | 0 .../operator-keypairs/id23.json | 0 .../operator-keypairs/id24.json | 0 .../operator-keypairs/id25.json | 0 .../operator-keypairs/id26.json | 0 .../operator-keypairs/id27.json | 0 .../operator-keypairs/id28.json | 0 .../operator-keypairs/id29.json | 0 {evm_loader => ci}/operator-keypairs/id3.json | 0 .../operator-keypairs/id30.json | 0 {evm_loader => ci}/operator-keypairs/id4.json | 0 {evm_loader => ci}/operator-keypairs/id5.json | 0 {evm_loader => ci}/operator-keypairs/id6.json | 0 {evm_loader => ci}/operator-keypairs/id7.json | 0 {evm_loader => ci}/operator-keypairs/id8.json | 0 {evm_loader => ci}/operator-keypairs/id9.json | 0 {evm_loader => ci}/wait-for-neon.sh | 0 {evm_loader => ci}/wait-for-solana.sh | 0 .../solidity => solidity}/Metaplex.sol | 0 .../solidity => solidity}/SPLToken.sol | 0 .../solidity => solidity}/big_contract.sol | 0 .../solidity => solidity}/erc20_for_spl.sol | 0 .../erc20_for_spl_factory.sol | 0 .../erc721_for_metaplex.sol | 0 .../lib_query_account.sol | 0 .../solidity => solidity}/neon_wrapper.sol | 0 {evm_loader/tests => tests}/.gitignore | 0 {evm_loader/tests => tests}/README.md | 0 {evm_loader/tests => tests}/__init__.py | 0 {evm_loader/tests => tests}/conftest.py | 334 +++++++++--------- .../tests => tests}/contracts/contracts.sol | 0 {evm_loader/tests => tests}/eth_tx_utils.py | 0 {evm_loader/tests => tests}/requirements.txt | 0 {evm_loader/tests => tests}/solana_utils.py | 0 .../tests => tests}/test_cancel_trx.py | 0 {evm_loader/tests => tests}/test_cli.py | 0 .../test_execute_trx_from_instruction.py | 0 .../tests => tests}/test_holder_account.py | 0 .../tests => tests}/test_neon_core_api.py | 0 {evm_loader/tests => tests}/test_parallel.py | 0 .../test_step_instructions_work_the_same.py | 0 .../test_transaction_step_from_account.py | 0 ...ransaction_step_from_account_no_chainid.py | 0 .../test_transaction_step_from_instruction.py | 0 {evm_loader/tests => tests}/utils/__init__.py | 0 .../tests => tests}/utils/assert_messages.py | 0 .../tests => tests}/utils/constants.py | 0 {evm_loader/tests => tests}/utils/contract.py | 0 {evm_loader/tests => tests}/utils/ethereum.py | 0 .../tests => tests}/utils/instructions.py | 0 {evm_loader/tests => tests}/utils/layouts.py | 0 .../tests => tests}/utils/neon_api_client.py | 0 {evm_loader/tests => tests}/utils/storage.py | 0 .../utils/transaction_checks.py | 0 {evm_loader/tests => tests}/utils/types.py | 0 78 files changed, 187 insertions(+), 187 deletions(-) rename {evm_loader => ci}/create-test-accounts.sh (100%) rename {evm_loader => ci}/deploy-evm.sh (100%) rename {evm_loader => ci}/deploy-test.sh (100%) rename {evm_loader => ci}/docker-compose-ci.yml (100%) rename {evm_loader => ci}/docker-compose-test.yml (100%) rename {evm_loader => ci}/evm_loader-keypair.json (100%) rename {evm_loader => ci}/keys/neon_token_keypair.json (100%) rename {evm_loader => ci}/operator-keypairs/id.json (100%) rename {evm_loader => ci}/operator-keypairs/id10.json (100%) rename {evm_loader => ci}/operator-keypairs/id11.json (100%) rename {evm_loader => ci}/operator-keypairs/id12.json (100%) rename {evm_loader => ci}/operator-keypairs/id13.json (100%) rename {evm_loader => ci}/operator-keypairs/id14.json (100%) rename {evm_loader => ci}/operator-keypairs/id15.json (100%) rename {evm_loader => ci}/operator-keypairs/id16.json (100%) rename {evm_loader => ci}/operator-keypairs/id17.json (100%) rename {evm_loader => ci}/operator-keypairs/id18.json (100%) rename {evm_loader => ci}/operator-keypairs/id19.json (100%) rename {evm_loader => ci}/operator-keypairs/id2.json (100%) rename {evm_loader => ci}/operator-keypairs/id20.json (100%) rename {evm_loader => ci}/operator-keypairs/id21.json (100%) rename {evm_loader => ci}/operator-keypairs/id22.json (100%) rename {evm_loader => ci}/operator-keypairs/id23.json (100%) rename {evm_loader => ci}/operator-keypairs/id24.json (100%) rename {evm_loader => ci}/operator-keypairs/id25.json (100%) rename {evm_loader => ci}/operator-keypairs/id26.json (100%) rename {evm_loader => ci}/operator-keypairs/id27.json (100%) rename {evm_loader => ci}/operator-keypairs/id28.json (100%) rename {evm_loader => ci}/operator-keypairs/id29.json (100%) rename {evm_loader => ci}/operator-keypairs/id3.json (100%) rename {evm_loader => ci}/operator-keypairs/id30.json (100%) rename {evm_loader => ci}/operator-keypairs/id4.json (100%) rename {evm_loader => ci}/operator-keypairs/id5.json (100%) rename {evm_loader => ci}/operator-keypairs/id6.json (100%) rename {evm_loader => ci}/operator-keypairs/id7.json (100%) rename {evm_loader => ci}/operator-keypairs/id8.json (100%) rename {evm_loader => ci}/operator-keypairs/id9.json (100%) rename {evm_loader => ci}/wait-for-neon.sh (100%) rename {evm_loader => ci}/wait-for-solana.sh (100%) rename {evm_loader/solidity => solidity}/Metaplex.sol (100%) rename {evm_loader/solidity => solidity}/SPLToken.sol (100%) rename {evm_loader/solidity => solidity}/big_contract.sol (100%) rename {evm_loader/solidity => solidity}/erc20_for_spl.sol (100%) rename {evm_loader/solidity => solidity}/erc20_for_spl_factory.sol (100%) rename {evm_loader/solidity => solidity}/erc721_for_metaplex.sol (100%) rename {evm_loader/solidity => solidity}/lib_query_account.sol (100%) rename {evm_loader/solidity => solidity}/neon_wrapper.sol (100%) rename {evm_loader/tests => tests}/.gitignore (100%) rename {evm_loader/tests => tests}/README.md (100%) rename {evm_loader/tests => tests}/__init__.py (100%) rename {evm_loader/tests => tests}/conftest.py (97%) rename {evm_loader/tests => tests}/contracts/contracts.sol (100%) rename {evm_loader/tests => tests}/eth_tx_utils.py (100%) rename {evm_loader/tests => tests}/requirements.txt (100%) rename {evm_loader/tests => tests}/solana_utils.py (100%) rename {evm_loader/tests => tests}/test_cancel_trx.py (100%) rename {evm_loader/tests => tests}/test_cli.py (100%) rename {evm_loader/tests => tests}/test_execute_trx_from_instruction.py (100%) rename {evm_loader/tests => tests}/test_holder_account.py (100%) rename {evm_loader/tests => tests}/test_neon_core_api.py (100%) rename {evm_loader/tests => tests}/test_parallel.py (100%) rename {evm_loader/tests => tests}/test_step_instructions_work_the_same.py (100%) rename {evm_loader/tests => tests}/test_transaction_step_from_account.py (100%) rename {evm_loader/tests => tests}/test_transaction_step_from_account_no_chainid.py (100%) rename {evm_loader/tests => tests}/test_transaction_step_from_instruction.py (100%) rename {evm_loader/tests => tests}/utils/__init__.py (100%) rename {evm_loader/tests => tests}/utils/assert_messages.py (100%) rename {evm_loader/tests => tests}/utils/constants.py (100%) rename {evm_loader/tests => tests}/utils/contract.py (100%) rename {evm_loader/tests => tests}/utils/ethereum.py (100%) rename {evm_loader/tests => tests}/utils/instructions.py (100%) rename {evm_loader/tests => tests}/utils/layouts.py (100%) rename {evm_loader/tests => tests}/utils/neon_api_client.py (100%) rename {evm_loader/tests => tests}/utils/storage.py (100%) rename {evm_loader/tests => tests}/utils/transaction_checks.py (100%) rename {evm_loader/tests => tests}/utils/types.py (100%) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index 297cac4fd..d65775c49 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -105,7 +105,7 @@ def run_tests(github_sha): project_name = f"neon-evm-{github_sha}" stop_containers(project_name) - run_subprocess(f"docker-compose -p {project_name} -f ./evm_loader/docker-compose-ci.yml up -d") + run_subprocess(f"docker-compose -p {project_name} -f ./ci/docker-compose-ci.yml up -d") container_name = get_solana_container_name(project_name) click.echo("Start tests") exec_id = docker_client.exec_create( @@ -127,7 +127,7 @@ def run_tests(github_sha): exec_status = docker_client.exec_inspect(exec_id['Id'])["ExitCode"] - run_subprocess(f"docker-compose -p {project_name} -f ./evm_loader/docker-compose-ci.yml logs dk-neon-api") + run_subprocess(f"docker-compose -p {project_name} -f ./ci/docker-compose-ci.yml logs dk-neon-api") stop_containers(project_name) @@ -137,7 +137,7 @@ def run_tests(github_sha): def get_solana_container_name(project_name): data = subprocess.run( - f"docker-compose -p {project_name} -f ./evm_loader/docker-compose-ci.yml ps", + f"docker-compose -p {project_name} -f ./ci/docker-compose-ci.yml ps", shell=True, capture_output=True, text=True).stdout click.echo(data) pattern = rf'{project_name}_solana_[1-9]+' @@ -147,7 +147,7 @@ def get_solana_container_name(project_name): def stop_containers(project_name): - run_subprocess(f"docker-compose -p {project_name} -f ./evm_loader/docker-compose-ci.yml down") + run_subprocess(f"docker-compose -p {project_name} -f ./ci/docker-compose-ci.yml down") @cli.command(name="trigger_proxy_action") diff --git a/Dockerfile b/Dockerfile index 5d11bd626..55744efae 100644 --- a/Dockerfile +++ b/Dockerfile @@ -32,8 +32,8 @@ FROM ubuntu:20.04 AS contracts RUN apt-get update && \ DEBIAN_FRONTEND=nontineractive apt-get -y install xxd && \ rm -rf /var/lib/apt/lists/* /var/lib/apt/cache/* -COPY evm_loader/tests/contracts/*.sol /opt/ -COPY evm_loader/solidity/*.sol /opt/ +COPY tests/contracts/*.sol /opt/ +COPY solidity/*.sol /opt/ #COPY evm_loader/tests/test_solidity_precompiles.json /opt/ COPY --from=solc /usr/bin/solc /usr/bin/solc WORKDIR /opt/ @@ -51,10 +51,10 @@ RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get -y install vim less openssl ca-certificates curl python3 python3-pip parallel && \ rm -rf /var/lib/apt/lists/* -COPY evm_loader/tests/requirements.txt /tmp/ +COPY tests/requirements.txt /tmp/ RUN pip3 install -r /tmp/requirements.txt -COPY /evm_loader/solidity/ /opt/contracts/contracts/ +#COPY /evm_loader/solidity/ /opt/contracts/contracts/ WORKDIR /opt COPY --from=solana \ @@ -80,19 +80,19 @@ COPY --from=evm-loader-builder /opt/neon-evm/evm_loader/target/release/neon-api COPY --from=solana /usr/bin/spl-token /opt/spl-token COPY --from=contracts /opt/ /opt/solidity/ COPY --from=contracts /usr/bin/solc /usr/bin/solc -COPY evm_loader/wait-for-solana.sh \ - evm_loader/wait-for-neon.sh \ - evm_loader/deploy-evm.sh \ - evm_loader/deploy-test.sh \ - evm_loader/create-test-accounts.sh \ - evm_loader/evm_loader-keypair.json \ +COPY ci/wait-for-solana.sh \ + ci/wait-for-neon.sh \ + ci/deploy-evm.sh \ + ci/deploy-test.sh \ + ci/create-test-accounts.sh \ + ci/evm_loader-keypair.json \ /opt/ -COPY evm_loader/operator-keypairs/ /opt/operator-keypairs -COPY evm_loader/tests /opt/tests -COPY evm_loader/operator-keypairs/id.json /root/.config/solana/id.json -COPY evm_loader/operator-keypairs/id2.json /root/.config/solana/id2.json -COPY evm_loader/keys/ /opt/keys +COPY ci/operator-keypairs/ /opt/operator-keypairs +COPY tests /opt/tests +COPY ci/operator-keypairs/id.json /root/.config/solana/id.json +COPY ci/operator-keypairs/id2.json /root/.config/solana/id2.json +COPY ci/keys/ /opt/keys -ENV CONTRACTS_DIR=/opt/solidity/ +#ENV CONTRACTS_DIR=/opt/solidity/ ENV PATH=/opt/solana/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt diff --git a/evm_loader/create-test-accounts.sh b/ci/create-test-accounts.sh similarity index 100% rename from evm_loader/create-test-accounts.sh rename to ci/create-test-accounts.sh diff --git a/evm_loader/deploy-evm.sh b/ci/deploy-evm.sh similarity index 100% rename from evm_loader/deploy-evm.sh rename to ci/deploy-evm.sh diff --git a/evm_loader/deploy-test.sh b/ci/deploy-test.sh similarity index 100% rename from evm_loader/deploy-test.sh rename to ci/deploy-test.sh diff --git a/evm_loader/docker-compose-ci.yml b/ci/docker-compose-ci.yml similarity index 100% rename from evm_loader/docker-compose-ci.yml rename to ci/docker-compose-ci.yml diff --git a/evm_loader/docker-compose-test.yml b/ci/docker-compose-test.yml similarity index 100% rename from evm_loader/docker-compose-test.yml rename to ci/docker-compose-test.yml diff --git a/evm_loader/evm_loader-keypair.json b/ci/evm_loader-keypair.json similarity index 100% rename from evm_loader/evm_loader-keypair.json rename to ci/evm_loader-keypair.json diff --git a/evm_loader/keys/neon_token_keypair.json b/ci/keys/neon_token_keypair.json similarity index 100% rename from evm_loader/keys/neon_token_keypair.json rename to ci/keys/neon_token_keypair.json diff --git a/evm_loader/operator-keypairs/id.json b/ci/operator-keypairs/id.json similarity index 100% rename from evm_loader/operator-keypairs/id.json rename to ci/operator-keypairs/id.json diff --git a/evm_loader/operator-keypairs/id10.json b/ci/operator-keypairs/id10.json similarity index 100% rename from evm_loader/operator-keypairs/id10.json rename to ci/operator-keypairs/id10.json diff --git a/evm_loader/operator-keypairs/id11.json b/ci/operator-keypairs/id11.json similarity index 100% rename from evm_loader/operator-keypairs/id11.json rename to ci/operator-keypairs/id11.json diff --git a/evm_loader/operator-keypairs/id12.json b/ci/operator-keypairs/id12.json similarity index 100% rename from evm_loader/operator-keypairs/id12.json rename to ci/operator-keypairs/id12.json diff --git a/evm_loader/operator-keypairs/id13.json b/ci/operator-keypairs/id13.json similarity index 100% rename from evm_loader/operator-keypairs/id13.json rename to ci/operator-keypairs/id13.json diff --git a/evm_loader/operator-keypairs/id14.json b/ci/operator-keypairs/id14.json similarity index 100% rename from evm_loader/operator-keypairs/id14.json rename to ci/operator-keypairs/id14.json diff --git a/evm_loader/operator-keypairs/id15.json b/ci/operator-keypairs/id15.json similarity index 100% rename from evm_loader/operator-keypairs/id15.json rename to ci/operator-keypairs/id15.json diff --git a/evm_loader/operator-keypairs/id16.json b/ci/operator-keypairs/id16.json similarity index 100% rename from evm_loader/operator-keypairs/id16.json rename to ci/operator-keypairs/id16.json diff --git a/evm_loader/operator-keypairs/id17.json b/ci/operator-keypairs/id17.json similarity index 100% rename from evm_loader/operator-keypairs/id17.json rename to ci/operator-keypairs/id17.json diff --git a/evm_loader/operator-keypairs/id18.json b/ci/operator-keypairs/id18.json similarity index 100% rename from evm_loader/operator-keypairs/id18.json rename to ci/operator-keypairs/id18.json diff --git a/evm_loader/operator-keypairs/id19.json b/ci/operator-keypairs/id19.json similarity index 100% rename from evm_loader/operator-keypairs/id19.json rename to ci/operator-keypairs/id19.json diff --git a/evm_loader/operator-keypairs/id2.json b/ci/operator-keypairs/id2.json similarity index 100% rename from evm_loader/operator-keypairs/id2.json rename to ci/operator-keypairs/id2.json diff --git a/evm_loader/operator-keypairs/id20.json b/ci/operator-keypairs/id20.json similarity index 100% rename from evm_loader/operator-keypairs/id20.json rename to ci/operator-keypairs/id20.json diff --git a/evm_loader/operator-keypairs/id21.json b/ci/operator-keypairs/id21.json similarity index 100% rename from evm_loader/operator-keypairs/id21.json rename to ci/operator-keypairs/id21.json diff --git a/evm_loader/operator-keypairs/id22.json b/ci/operator-keypairs/id22.json similarity index 100% rename from evm_loader/operator-keypairs/id22.json rename to ci/operator-keypairs/id22.json diff --git a/evm_loader/operator-keypairs/id23.json b/ci/operator-keypairs/id23.json similarity index 100% rename from evm_loader/operator-keypairs/id23.json rename to ci/operator-keypairs/id23.json diff --git a/evm_loader/operator-keypairs/id24.json b/ci/operator-keypairs/id24.json similarity index 100% rename from evm_loader/operator-keypairs/id24.json rename to ci/operator-keypairs/id24.json diff --git a/evm_loader/operator-keypairs/id25.json b/ci/operator-keypairs/id25.json similarity index 100% rename from evm_loader/operator-keypairs/id25.json rename to ci/operator-keypairs/id25.json diff --git a/evm_loader/operator-keypairs/id26.json b/ci/operator-keypairs/id26.json similarity index 100% rename from evm_loader/operator-keypairs/id26.json rename to ci/operator-keypairs/id26.json diff --git a/evm_loader/operator-keypairs/id27.json b/ci/operator-keypairs/id27.json similarity index 100% rename from evm_loader/operator-keypairs/id27.json rename to ci/operator-keypairs/id27.json diff --git a/evm_loader/operator-keypairs/id28.json b/ci/operator-keypairs/id28.json similarity index 100% rename from evm_loader/operator-keypairs/id28.json rename to ci/operator-keypairs/id28.json diff --git a/evm_loader/operator-keypairs/id29.json b/ci/operator-keypairs/id29.json similarity index 100% rename from evm_loader/operator-keypairs/id29.json rename to ci/operator-keypairs/id29.json diff --git a/evm_loader/operator-keypairs/id3.json b/ci/operator-keypairs/id3.json similarity index 100% rename from evm_loader/operator-keypairs/id3.json rename to ci/operator-keypairs/id3.json diff --git a/evm_loader/operator-keypairs/id30.json b/ci/operator-keypairs/id30.json similarity index 100% rename from evm_loader/operator-keypairs/id30.json rename to ci/operator-keypairs/id30.json diff --git a/evm_loader/operator-keypairs/id4.json b/ci/operator-keypairs/id4.json similarity index 100% rename from evm_loader/operator-keypairs/id4.json rename to ci/operator-keypairs/id4.json diff --git a/evm_loader/operator-keypairs/id5.json b/ci/operator-keypairs/id5.json similarity index 100% rename from evm_loader/operator-keypairs/id5.json rename to ci/operator-keypairs/id5.json diff --git a/evm_loader/operator-keypairs/id6.json b/ci/operator-keypairs/id6.json similarity index 100% rename from evm_loader/operator-keypairs/id6.json rename to ci/operator-keypairs/id6.json diff --git a/evm_loader/operator-keypairs/id7.json b/ci/operator-keypairs/id7.json similarity index 100% rename from evm_loader/operator-keypairs/id7.json rename to ci/operator-keypairs/id7.json diff --git a/evm_loader/operator-keypairs/id8.json b/ci/operator-keypairs/id8.json similarity index 100% rename from evm_loader/operator-keypairs/id8.json rename to ci/operator-keypairs/id8.json diff --git a/evm_loader/operator-keypairs/id9.json b/ci/operator-keypairs/id9.json similarity index 100% rename from evm_loader/operator-keypairs/id9.json rename to ci/operator-keypairs/id9.json diff --git a/evm_loader/wait-for-neon.sh b/ci/wait-for-neon.sh similarity index 100% rename from evm_loader/wait-for-neon.sh rename to ci/wait-for-neon.sh diff --git a/evm_loader/wait-for-solana.sh b/ci/wait-for-solana.sh similarity index 100% rename from evm_loader/wait-for-solana.sh rename to ci/wait-for-solana.sh diff --git a/evm_loader/solidity/Metaplex.sol b/solidity/Metaplex.sol similarity index 100% rename from evm_loader/solidity/Metaplex.sol rename to solidity/Metaplex.sol diff --git a/evm_loader/solidity/SPLToken.sol b/solidity/SPLToken.sol similarity index 100% rename from evm_loader/solidity/SPLToken.sol rename to solidity/SPLToken.sol diff --git a/evm_loader/solidity/big_contract.sol b/solidity/big_contract.sol similarity index 100% rename from evm_loader/solidity/big_contract.sol rename to solidity/big_contract.sol diff --git a/evm_loader/solidity/erc20_for_spl.sol b/solidity/erc20_for_spl.sol similarity index 100% rename from evm_loader/solidity/erc20_for_spl.sol rename to solidity/erc20_for_spl.sol diff --git a/evm_loader/solidity/erc20_for_spl_factory.sol b/solidity/erc20_for_spl_factory.sol similarity index 100% rename from evm_loader/solidity/erc20_for_spl_factory.sol rename to solidity/erc20_for_spl_factory.sol diff --git a/evm_loader/solidity/erc721_for_metaplex.sol b/solidity/erc721_for_metaplex.sol similarity index 100% rename from evm_loader/solidity/erc721_for_metaplex.sol rename to solidity/erc721_for_metaplex.sol diff --git a/evm_loader/solidity/lib_query_account.sol b/solidity/lib_query_account.sol similarity index 100% rename from evm_loader/solidity/lib_query_account.sol rename to solidity/lib_query_account.sol diff --git a/evm_loader/solidity/neon_wrapper.sol b/solidity/neon_wrapper.sol similarity index 100% rename from evm_loader/solidity/neon_wrapper.sol rename to solidity/neon_wrapper.sol diff --git a/evm_loader/tests/.gitignore b/tests/.gitignore similarity index 100% rename from evm_loader/tests/.gitignore rename to tests/.gitignore diff --git a/evm_loader/tests/README.md b/tests/README.md similarity index 100% rename from evm_loader/tests/README.md rename to tests/README.md diff --git a/evm_loader/tests/__init__.py b/tests/__init__.py similarity index 100% rename from evm_loader/tests/__init__.py rename to tests/__init__.py diff --git a/evm_loader/tests/conftest.py b/tests/conftest.py similarity index 97% rename from evm_loader/tests/conftest.py rename to tests/conftest.py index ef25a219a..b19051ee0 100644 --- a/evm_loader/tests/conftest.py +++ b/tests/conftest.py @@ -1,167 +1,167 @@ -import os -import json -import pathlib - -import eth_abi -import pytest - -from solana.keypair import Keypair -from eth_keys import keys as eth_keys -from solana.publickey import PublicKey -from solana.rpc.commitment import Confirmed - -from .solana_utils import EvmLoader, create_treasury_pool_address, make_new_user, \ - deposit_neon, solana_client, spl_cli, wait_confirm_transaction, get_solana_balance -from .utils.constants import NEON_TOKEN_MINT_ID -from .utils.contract import deploy_contract -from .utils.storage import create_holder -from .utils.types import TreasuryPool, Caller, Contract -from .utils.neon_api_client import NeonApiClient - - -def pytest_addoption(parser): - parser.addoption( - "--neon-api-uri", action="store", default="http://neon_api:8085/api", - help="" - ) - - -def pytest_configure(): - if "RUST_LOG" in os.environ: - pytest.CONTRACTS_PATH = pathlib.Path("/opt/solidity") - else: - pytest.CONTRACTS_PATH = pathlib.Path(__file__).parent / "contracts" - - -@pytest.fixture(scope="session") -def evm_loader(operator_keypair) -> EvmLoader: - loader = EvmLoader(operator_keypair) - return loader - - -def prepare_operator(key_file): - with open(key_file, "r") as key: - secret_key = json.load(key)[:32] - account = Keypair.from_secret_key(secret_key) - tx = solana_client.request_airdrop(account.public_key, 1000000 * 10 ** 9, commitment=Confirmed) - wait_confirm_transaction(solana_client, tx.value) - caller_ether = eth_keys.PrivateKey(account.secret_key[:32]).public_key.to_canonical_address() - evm_loader = EvmLoader(account) - evm_loader.ether2program(caller_ether) - caller, caller_nonce = evm_loader.ether2program(caller_ether) - acc_info = solana_client.get_account_info(PublicKey(caller), commitment=Confirmed) - if acc_info.value is None: - token = spl_cli.create_token_account(NEON_TOKEN_MINT_ID, account.public_key, fee_payer=key_file) - spl_cli.mint(NEON_TOKEN_MINT_ID, token, 5000000, fee_payer=key_file) - evm_loader.create_ether_account(caller_ether) - return account - - -@pytest.fixture(scope="session") -def operator_keypair(worker_id) -> Keypair: - """ - Initialized solana keypair with balance. Get private keys from ci/operator-keypairs - """ - key_path = pathlib.Path(__file__).parent.parent / "operator-keypairs" - if worker_id in ("master", "gw1"): - key_file = key_path / "id.json" - else: - file_id = int(worker_id[-1]) + 2 - key_file = key_path / f"id{file_id}.json" - return prepare_operator(key_file) - - -@pytest.fixture(scope="session") -def second_operator_keypair(worker_id) -> Keypair: - """ - Initialized solana keypair with balance. Get private key from cli or ./ci/operator-keypairs - """ - key_path = pathlib.Path(__file__).parent.parent / "operator-keypairs" - if worker_id in ("master", "gw1"): - key_file = key_path / "id20.json" - else: - file_id = 20 + int(worker_id[-1]) + 2 - key_file = key_path / f"id{file_id}.json" - - return prepare_operator(key_file) - - -@pytest.fixture(scope="session") -def treasury_pool(evm_loader) -> TreasuryPool: - index = 2 - address = create_treasury_pool_address(index) - index_buf = index.to_bytes(4, 'little') - return TreasuryPool(index, address, index_buf) - - -@pytest.fixture(scope="function") -def user_account(evm_loader) -> Caller: - return make_new_user(evm_loader) - - -@pytest.fixture(scope="session") -def session_user(evm_loader) -> Caller: - return make_new_user(evm_loader) - - -@pytest.fixture(scope="session") -def second_session_user(evm_loader) -> Caller: - return make_new_user(evm_loader) - - -@pytest.fixture(scope="session") -def sender_with_tokens(evm_loader, operator_keypair) -> Caller: - user = make_new_user(evm_loader) - deposit_neon(evm_loader, operator_keypair, user.eth_address, 100000) - return user - - -@pytest.fixture(scope="session") -def holder_acc(operator_keypair) -> PublicKey: - return create_holder(operator_keypair) - - -@pytest.fixture(scope="function") -def new_holder_acc(operator_keypair) -> PublicKey: - return create_holder(operator_keypair) - - -@pytest.fixture(scope="function") -def rw_lock_contract(evm_loader: EvmLoader, operator_keypair: Keypair, session_user: Caller, - treasury_pool) -> Contract: - return deploy_contract(operator_keypair, session_user, "rw_lock.binary", evm_loader, treasury_pool) - - -@pytest.fixture(scope="function") -def rw_lock_caller(evm_loader: EvmLoader, operator_keypair: Keypair, - session_user: Caller, treasury_pool: TreasuryPool, rw_lock_contract: Contract) -> Contract: - constructor_args = eth_abi.encode(['address'], [rw_lock_contract.eth_address.hex()]) - return deploy_contract(operator_keypair, session_user, "rw_lock_caller.binary", evm_loader, - treasury_pool, encoded_args=constructor_args) - - -@pytest.fixture(scope="function") -def string_setter_contract(evm_loader: EvmLoader, operator_keypair: Keypair, session_user: Caller, - treasury_pool) -> Contract: - return deploy_contract(operator_keypair, session_user, "string_setter.binary", evm_loader, treasury_pool) - - -@pytest.fixture(scope="session") -def calculator_contract(evm_loader: EvmLoader, operator_keypair: Keypair, session_user: Caller, - treasury_pool) -> Contract: - return deploy_contract(operator_keypair, session_user, "Calculator.binary", evm_loader, treasury_pool) - - -@pytest.fixture(scope="session") -def calculator_caller_contract(evm_loader: EvmLoader, operator_keypair: Keypair, session_user: Caller, - treasury_pool, calculator_contract) -> Contract: - constructor_args = eth_abi.encode(['address'], [calculator_contract.eth_address.hex()]) - - return deploy_contract(operator_keypair, session_user, "CalculatorCaller.binary", evm_loader, treasury_pool, - encoded_args=constructor_args) - - -@pytest.fixture(scope="session") -def neon_api_client(request): - client = NeonApiClient(url=request.config.getoption("--neon-api-uri")) - return client +import os +import json +import pathlib + +import eth_abi +import pytest + +from solana.keypair import Keypair +from eth_keys import keys as eth_keys +from solana.publickey import PublicKey +from solana.rpc.commitment import Confirmed + +from .solana_utils import EvmLoader, create_treasury_pool_address, make_new_user, \ + deposit_neon, solana_client, spl_cli, wait_confirm_transaction, get_solana_balance +from .utils.constants import NEON_TOKEN_MINT_ID +from .utils.contract import deploy_contract +from .utils.storage import create_holder +from .utils.types import TreasuryPool, Caller, Contract +from .utils.neon_api_client import NeonApiClient + + +def pytest_addoption(parser): + parser.addoption( + "--neon-api-uri", action="store", default="http://neon_api:8085/api", + help="" + ) + + +def pytest_configure(): + if "RUST_LOG" in os.environ: + pytest.CONTRACTS_PATH = pathlib.Path("/opt/solidity") + else: + pytest.CONTRACTS_PATH = pathlib.Path(__file__).parent / "contracts" + + +@pytest.fixture(scope="session") +def evm_loader(operator_keypair) -> EvmLoader: + loader = EvmLoader(operator_keypair) + return loader + + +def prepare_operator(key_file): + with open(key_file, "r") as key: + secret_key = json.load(key)[:32] + account = Keypair.from_secret_key(secret_key) + tx = solana_client.request_airdrop(account.public_key, 1000000 * 10 ** 9, commitment=Confirmed) + wait_confirm_transaction(solana_client, tx.value) + caller_ether = eth_keys.PrivateKey(account.secret_key[:32]).public_key.to_canonical_address() + evm_loader = EvmLoader(account) + evm_loader.ether2program(caller_ether) + caller, caller_nonce = evm_loader.ether2program(caller_ether) + acc_info = solana_client.get_account_info(PublicKey(caller), commitment=Confirmed) + if acc_info.value is None: + token = spl_cli.create_token_account(NEON_TOKEN_MINT_ID, account.public_key, fee_payer=key_file) + spl_cli.mint(NEON_TOKEN_MINT_ID, token, 5000000, fee_payer=key_file) + evm_loader.create_ether_account(caller_ether) + return account + + +@pytest.fixture(scope="session") +def operator_keypair(worker_id) -> Keypair: + """ + Initialized solana keypair with balance. Get private keys from ci/operator-keypairs + """ + key_path = pathlib.Path(__file__).parent.parent / "operator-keypairs" + if worker_id in ("master", "gw1"): + key_file = key_path / "id.json" + else: + file_id = int(worker_id[-1]) + 2 + key_file = key_path / f"id{file_id}.json" + return prepare_operator(key_file) + + +@pytest.fixture(scope="session") +def second_operator_keypair(worker_id) -> Keypair: + """ + Initialized solana keypair with balance. Get private key from cli or ./ci/operator-keypairs + """ + key_path = pathlib.Path(__file__).parent.parent / "operator-keypairs" + if worker_id in ("master", "gw1"): + key_file = key_path / "id20.json" + else: + file_id = 20 + int(worker_id[-1]) + 2 + key_file = key_path / f"id{file_id}.json" + + return prepare_operator(key_file) + + +@pytest.fixture(scope="session") +def treasury_pool(evm_loader) -> TreasuryPool: + index = 2 + address = create_treasury_pool_address(index) + index_buf = index.to_bytes(4, 'little') + return TreasuryPool(index, address, index_buf) + + +@pytest.fixture(scope="function") +def user_account(evm_loader) -> Caller: + return make_new_user(evm_loader) + + +@pytest.fixture(scope="session") +def session_user(evm_loader) -> Caller: + return make_new_user(evm_loader) + + +@pytest.fixture(scope="session") +def second_session_user(evm_loader) -> Caller: + return make_new_user(evm_loader) + + +@pytest.fixture(scope="session") +def sender_with_tokens(evm_loader, operator_keypair) -> Caller: + user = make_new_user(evm_loader) + deposit_neon(evm_loader, operator_keypair, user.eth_address, 100000) + return user + + +@pytest.fixture(scope="session") +def holder_acc(operator_keypair) -> PublicKey: + return create_holder(operator_keypair) + + +@pytest.fixture(scope="function") +def new_holder_acc(operator_keypair) -> PublicKey: + return create_holder(operator_keypair) + + +@pytest.fixture(scope="function") +def rw_lock_contract(evm_loader: EvmLoader, operator_keypair: Keypair, session_user: Caller, + treasury_pool) -> Contract: + return deploy_contract(operator_keypair, session_user, "rw_lock.binary", evm_loader, treasury_pool) + + +@pytest.fixture(scope="function") +def rw_lock_caller(evm_loader: EvmLoader, operator_keypair: Keypair, + session_user: Caller, treasury_pool: TreasuryPool, rw_lock_contract: Contract) -> Contract: + constructor_args = eth_abi.encode(['address'], [rw_lock_contract.eth_address.hex()]) + return deploy_contract(operator_keypair, session_user, "rw_lock_caller.binary", evm_loader, + treasury_pool, encoded_args=constructor_args) + + +@pytest.fixture(scope="function") +def string_setter_contract(evm_loader: EvmLoader, operator_keypair: Keypair, session_user: Caller, + treasury_pool) -> Contract: + return deploy_contract(operator_keypair, session_user, "string_setter.binary", evm_loader, treasury_pool) + + +@pytest.fixture(scope="session") +def calculator_contract(evm_loader: EvmLoader, operator_keypair: Keypair, session_user: Caller, + treasury_pool) -> Contract: + return deploy_contract(operator_keypair, session_user, "Calculator.binary", evm_loader, treasury_pool) + + +@pytest.fixture(scope="session") +def calculator_caller_contract(evm_loader: EvmLoader, operator_keypair: Keypair, session_user: Caller, + treasury_pool, calculator_contract) -> Contract: + constructor_args = eth_abi.encode(['address'], [calculator_contract.eth_address.hex()]) + + return deploy_contract(operator_keypair, session_user, "CalculatorCaller.binary", evm_loader, treasury_pool, + encoded_args=constructor_args) + + +@pytest.fixture(scope="session") +def neon_api_client(request): + client = NeonApiClient(url=request.config.getoption("--neon-api-uri")) + return client diff --git a/evm_loader/tests/contracts/contracts.sol b/tests/contracts/contracts.sol similarity index 100% rename from evm_loader/tests/contracts/contracts.sol rename to tests/contracts/contracts.sol diff --git a/evm_loader/tests/eth_tx_utils.py b/tests/eth_tx_utils.py similarity index 100% rename from evm_loader/tests/eth_tx_utils.py rename to tests/eth_tx_utils.py diff --git a/evm_loader/tests/requirements.txt b/tests/requirements.txt similarity index 100% rename from evm_loader/tests/requirements.txt rename to tests/requirements.txt diff --git a/evm_loader/tests/solana_utils.py b/tests/solana_utils.py similarity index 100% rename from evm_loader/tests/solana_utils.py rename to tests/solana_utils.py diff --git a/evm_loader/tests/test_cancel_trx.py b/tests/test_cancel_trx.py similarity index 100% rename from evm_loader/tests/test_cancel_trx.py rename to tests/test_cancel_trx.py diff --git a/evm_loader/tests/test_cli.py b/tests/test_cli.py similarity index 100% rename from evm_loader/tests/test_cli.py rename to tests/test_cli.py diff --git a/evm_loader/tests/test_execute_trx_from_instruction.py b/tests/test_execute_trx_from_instruction.py similarity index 100% rename from evm_loader/tests/test_execute_trx_from_instruction.py rename to tests/test_execute_trx_from_instruction.py diff --git a/evm_loader/tests/test_holder_account.py b/tests/test_holder_account.py similarity index 100% rename from evm_loader/tests/test_holder_account.py rename to tests/test_holder_account.py diff --git a/evm_loader/tests/test_neon_core_api.py b/tests/test_neon_core_api.py similarity index 100% rename from evm_loader/tests/test_neon_core_api.py rename to tests/test_neon_core_api.py diff --git a/evm_loader/tests/test_parallel.py b/tests/test_parallel.py similarity index 100% rename from evm_loader/tests/test_parallel.py rename to tests/test_parallel.py diff --git a/evm_loader/tests/test_step_instructions_work_the_same.py b/tests/test_step_instructions_work_the_same.py similarity index 100% rename from evm_loader/tests/test_step_instructions_work_the_same.py rename to tests/test_step_instructions_work_the_same.py diff --git a/evm_loader/tests/test_transaction_step_from_account.py b/tests/test_transaction_step_from_account.py similarity index 100% rename from evm_loader/tests/test_transaction_step_from_account.py rename to tests/test_transaction_step_from_account.py diff --git a/evm_loader/tests/test_transaction_step_from_account_no_chainid.py b/tests/test_transaction_step_from_account_no_chainid.py similarity index 100% rename from evm_loader/tests/test_transaction_step_from_account_no_chainid.py rename to tests/test_transaction_step_from_account_no_chainid.py diff --git a/evm_loader/tests/test_transaction_step_from_instruction.py b/tests/test_transaction_step_from_instruction.py similarity index 100% rename from evm_loader/tests/test_transaction_step_from_instruction.py rename to tests/test_transaction_step_from_instruction.py diff --git a/evm_loader/tests/utils/__init__.py b/tests/utils/__init__.py similarity index 100% rename from evm_loader/tests/utils/__init__.py rename to tests/utils/__init__.py diff --git a/evm_loader/tests/utils/assert_messages.py b/tests/utils/assert_messages.py similarity index 100% rename from evm_loader/tests/utils/assert_messages.py rename to tests/utils/assert_messages.py diff --git a/evm_loader/tests/utils/constants.py b/tests/utils/constants.py similarity index 100% rename from evm_loader/tests/utils/constants.py rename to tests/utils/constants.py diff --git a/evm_loader/tests/utils/contract.py b/tests/utils/contract.py similarity index 100% rename from evm_loader/tests/utils/contract.py rename to tests/utils/contract.py diff --git a/evm_loader/tests/utils/ethereum.py b/tests/utils/ethereum.py similarity index 100% rename from evm_loader/tests/utils/ethereum.py rename to tests/utils/ethereum.py diff --git a/evm_loader/tests/utils/instructions.py b/tests/utils/instructions.py similarity index 100% rename from evm_loader/tests/utils/instructions.py rename to tests/utils/instructions.py diff --git a/evm_loader/tests/utils/layouts.py b/tests/utils/layouts.py similarity index 100% rename from evm_loader/tests/utils/layouts.py rename to tests/utils/layouts.py diff --git a/evm_loader/tests/utils/neon_api_client.py b/tests/utils/neon_api_client.py similarity index 100% rename from evm_loader/tests/utils/neon_api_client.py rename to tests/utils/neon_api_client.py diff --git a/evm_loader/tests/utils/storage.py b/tests/utils/storage.py similarity index 100% rename from evm_loader/tests/utils/storage.py rename to tests/utils/storage.py diff --git a/evm_loader/tests/utils/transaction_checks.py b/tests/utils/transaction_checks.py similarity index 100% rename from evm_loader/tests/utils/transaction_checks.py rename to tests/utils/transaction_checks.py diff --git a/evm_loader/tests/utils/types.py b/tests/utils/types.py similarity index 100% rename from evm_loader/tests/utils/types.py rename to tests/utils/types.py From c342072f96df9cdc839b16ccacdf8ec2711efb14 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Mon, 9 Oct 2023 12:31:28 +0300 Subject: [PATCH 040/318] NDEV-2292: Upgrade Solana to v1.16.15 (#211) --- .github/workflows/deploy.py | 4 +- evm_loader/Cargo.lock | 148 +++++++++++++++++----------------- evm_loader/api/Cargo.toml | 4 +- evm_loader/cli/Cargo.toml | 8 +- evm_loader/lib/Cargo.toml | 12 +-- evm_loader/program/Cargo.toml | 2 +- 6 files changed, 89 insertions(+), 89 deletions(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index d65775c49..646939377 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -30,8 +30,8 @@ DOCKER_USER = os.environ.get("DHUBU") DOCKER_PASSWORD = os.environ.get("DHUBP") IMAGE_NAME = 'neonlabsorg/evm_loader' -SOLANA_NODE_VERSION = 'v1.16.14' -SOLANA_BPF_VERSION = 'v1.16.14' +SOLANA_NODE_VERSION = 'v1.16.15' +SOLANA_BPF_VERSION = 'v1.16.15' VERSION_BRANCH_TEMPLATE = r"[vt]{1}\d{1,2}\.\d{1,2}\.x.*" docker_client = docker.APIClient() diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 8ad657fb7..1d1b1b288 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -4233,9 +4233,9 @@ dependencies = [ [[package]] name = "solana-account-decoder" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0ada16ccd5ca6884ae28b716211c4f09d22225a9ebde14eccd4f605cc321e42" +checksum = "850d5d9dc8fa6ea42f4e61c78e296bbbce5a3531ff4cb3c58ef36ee31781049c" dependencies = [ "Inflector", "base64 0.21.4", @@ -4257,9 +4257,9 @@ dependencies = [ [[package]] name = "solana-address-lookup-table-program" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248b435722d18100b70bb8f09fd38b8a8c46031a0de86f6b31768f64cf4092c5" +checksum = "8a7f867cde478a078d4c4ceb113f4f9ac7e29c2efea98f80a2b30cdcd7be83c5" dependencies = [ "bincode", "bytemuck", @@ -4278,9 +4278,9 @@ dependencies = [ [[package]] name = "solana-bpf-loader-program" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70b84a554f12f89c72f3c2dea973a5105740814aeebfb04998cc0afd9e2e6a2e" +checksum = "1eaf42dbfe8a42b80e24f2c087a3935d6e7bb49886313b006d88fb04fdc2a02f" dependencies = [ "bincode", "byteorder", @@ -4297,9 +4297,9 @@ dependencies = [ [[package]] name = "solana-clap-utils" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2782dc1178498135d438ea51998e5a28be05f2ed5b9ff97e224d8ca1f6b16fe5" +checksum = "c3c99636da9a4acad58d0e8142e36395ece48fc41c396e297e702b6a789b190f" dependencies = [ "chrono", "clap 2.34.0", @@ -4315,9 +4315,9 @@ dependencies = [ [[package]] name = "solana-cli" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1feeff64c3c26c609e4824ed8154d3da2086dc712009a3e762e96c6490f164" +checksum = "27cd5c7630ad1469cfe959f9e7dfde97892c8c66666602d141c39d4d17605771" dependencies = [ "bincode", "bs58", @@ -4366,9 +4366,9 @@ dependencies = [ [[package]] name = "solana-cli-config" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "538e8c1de6e6a948930a11f7debdbb21ff5492d09b67fb0d37a03c5208c233c7" +checksum = "7ae4ba224e834b5d71c884a356bf1e23b5999ef4edd8996a42a8ac0dd680315b" dependencies = [ "dirs-next", "lazy_static", @@ -4382,9 +4382,9 @@ dependencies = [ [[package]] name = "solana-cli-output" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb41ef997e186c81a42d8b359eff0d8f0f3c61a02ad4a66111f189664a4f9d0d" +checksum = "56d56e77a341047880483438de34a5dea76eb79449ea9f969422710fb7f932b6" dependencies = [ "Inflector", "base64 0.21.4", @@ -4409,9 +4409,9 @@ dependencies = [ [[package]] name = "solana-client" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "969294bec354ba003bb4dc2e95e94beee4202d3244d6011434c282337601cc1f" +checksum = "acc7a437165d8fcfac3c63963e394f0ea497b5d2a75159bb3a1ed75dbeb36a7e" dependencies = [ "async-trait", "bincode", @@ -4442,9 +4442,9 @@ dependencies = [ [[package]] name = "solana-config-program" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0622d8798d060c84883572483f214b0d5c1640450e4322483cfe2e72823a6d7" +checksum = "d6f9f2201c7e526581511fa6525e281518be5cabaee82bd5b29fe4b78744148d" dependencies = [ "bincode", "chrono", @@ -4456,9 +4456,9 @@ dependencies = [ [[package]] name = "solana-connection-cache" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1439d38886d31690d8e2573e656e6767d3ae790229050dfe71ade309d5664cb" +checksum = "3ee52de352e10e53b252df0815d685a9c6f3e8d3baa0f65e214dfcd247db0e21" dependencies = [ "async-trait", "bincode", @@ -4477,9 +4477,9 @@ dependencies = [ [[package]] name = "solana-faucet" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ec77384c3c93e9f755ef0352c0c90ec98017e9db9908a9e7878dad60ea3244b" +checksum = "8e7a5d760f9bb71eb73a26c7950ddce2dc3257262cf6cc9fc92918c3c7ac9022" dependencies = [ "bincode", "byteorder", @@ -4501,9 +4501,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e74d294241df12a73a229e38a819e810d54234da494c3d43f8a1a828631047d" +checksum = "361cc834e5fbbe1a73f1d904fcb8ab052a665e5be6061bd1ba7ab478d7d17c9c" dependencies = [ "ahash 0.8.3", "blake3", @@ -4534,9 +4534,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi-macro" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dabde7fbd88a68eb083ae9d6d5f6855b7ba1bfc45d200c786b1b448ac49da5f" +checksum = "575d875dc050689f9f88c542e292e295e2f081d4e96e0df297981e45cbad8824" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", @@ -4546,9 +4546,9 @@ dependencies = [ [[package]] name = "solana-logger" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24dc0037a389d782c8de3c6f509b74efa1d60523ef9e5561cefe41f1a354fee0" +checksum = "c00faf7aa6a3f47c542bd45d2d7f13af9a382d993e647976a676fe1b0eec4eb2" dependencies = [ "env_logger", "lazy_static", @@ -4557,9 +4557,9 @@ dependencies = [ [[package]] name = "solana-measure" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19563c27f12801e0e65b42d0f216db1d910dfeaad88d8f1335dd6369697eda60" +checksum = "0e19c6e1b35df3c212619a7995ae3576fa92ab15ecfc065899f21385cbe45c95" dependencies = [ "log", "solana-sdk", @@ -4567,9 +4567,9 @@ dependencies = [ [[package]] name = "solana-metrics" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f74c557e821c7ff48c9b4ef4ab3a296918d7fb745e3f2e820ebdb38e8e3555b" +checksum = "10e62760a5f87d836169eb3bb446bae174181db07d2c8016be36de49c04fd432" dependencies = [ "crossbeam-channel", "gethostname", @@ -4581,9 +4581,9 @@ dependencies = [ [[package]] name = "solana-net-utils" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7d5599760f8a287c59d96a5c52752028c1c72c815fe74e0d7990bb90684cbfc" +checksum = "308c4c36c634d418589cf1df121d143819feff81932de81640de3d64878934eb" dependencies = [ "bincode", "clap 3.2.23", @@ -4603,9 +4603,9 @@ dependencies = [ [[package]] name = "solana-perf" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76b2adb00aa09d92cd3b4f614ddd4f81366524a0d8ae9dd63b64418f696171c6" +checksum = "a4d44a4998ba6d9b37e89399d9ce2812e84489dd4665df619fb23366e1c2ec1b" dependencies = [ "ahash 0.8.3", "bincode", @@ -4630,9 +4630,9 @@ dependencies = [ [[package]] name = "solana-program" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a2faeb9c89b354b547a229e3b39fa8fd6d11c78362ba8580f0c4721739725b6" +checksum = "9863ff5c6e828015bec331c26fb53e48352a264a9be682e7e078d2c3b3e93b46" dependencies = [ "ark-bn254", "ark-ec", @@ -4685,9 +4685,9 @@ dependencies = [ [[package]] name = "solana-program-runtime" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f65907a405764cda63be89335ffd2138ade18f065e5cae09d20adab7fb09502" +checksum = "05813d4d2e141ab4449cf684cc5b05512dfaabb7251561c5bb1ccf1e4221b210" dependencies = [ "base64 0.21.4", "bincode", @@ -4713,9 +4713,9 @@ dependencies = [ [[package]] name = "solana-pubsub-client" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "367e70572ebc81de7d8ca742342f7cf19b6b47d182dd9aa8932c7cfa71bb6dc4" +checksum = "7cd0753cdde1710f50d58bd40a45e58f5368a25dabff6b18ba635c3d6959a558" dependencies = [ "crossbeam-channel", "futures-util", @@ -4738,9 +4738,9 @@ dependencies = [ [[package]] name = "solana-quic-client" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87daa01ce0ecd6667425c7f19f10388cbce63a62f8f69767ea37b69293e814cf" +checksum = "212d96abde446eaa903d16961cfd3a6e98dc0d680b9edd61c39938c61548d53e" dependencies = [ "async-mutex", "async-trait", @@ -4766,9 +4766,9 @@ dependencies = [ [[package]] name = "solana-rayon-threadlimit" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb6593da84631b9b523dac91b04f4e2a366205f61112d677e8cbe2bfda57a176" +checksum = "82ab62fc62458271d746678a3f5625e1654e3cb42a8f318ef4f1ea25991bb085" dependencies = [ "lazy_static", "num_cpus", @@ -4776,9 +4776,9 @@ dependencies = [ [[package]] name = "solana-remote-wallet" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a431bdda7679de1381722f6eef63dfc301f07cbd51a930a28e61ee42167448a5" +checksum = "863f10b8c2a893d1ec85b3ae8020c714512a67302b80c24dde0016eea4034a7c" dependencies = [ "console", "dialoguer", @@ -4796,9 +4796,9 @@ dependencies = [ [[package]] name = "solana-rpc-client" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2771ac12cdbde1aa6b55a129947f1428bb44d14314059c1e69674e1d58aaf9e1" +checksum = "df04998cef2d0fe1291599b69acafc7f8cd87305d7f1525c8ae10aef1cc5411c" dependencies = [ "async-trait", "base64 0.21.4", @@ -4822,9 +4822,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-api" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f401e2ae586fd60c1c8c0f406be521bfe4889c6c2854fbb76bd20e8bc2d57284" +checksum = "5e2912ddbff841fbce1e30b0b9a420993c63b6cc7866e5f0af3740fcd6d85bb8" dependencies = [ "base64 0.21.4", "bs58", @@ -4844,9 +4844,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-nonce-utils" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46df2d20521eab49fadb9afe93808e9764767e193bd701c7d380a56d0dc7f8ad" +checksum = "d31100f6cc340dd322f57d00a334fa0a96f628ba86b04fcda1f84307deb14c31" dependencies = [ "clap 2.34.0", "solana-clap-utils", @@ -4857,9 +4857,9 @@ dependencies = [ [[package]] name = "solana-sdk" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57f4046d0d487e3d79be809ff29c63c1484793956e6ccbc5d3307b0aafbf989d" +checksum = "621e6973766420162541b26e7974783d32d5471571610da30c5bb0b6263046c9" dependencies = [ "assert_matches", "base64 0.21.4", @@ -4910,9 +4910,9 @@ dependencies = [ [[package]] name = "solana-sdk-macro" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "760fdfd4b7edb02fd9173a6dcec899ffae06ac21b66b65f8c7c5f3d17b12fa64" +checksum = "bd177a74fb3a0a362f1292c027d668eff609ac189f08b78158324587a0a4f8d1" dependencies = [ "bs58", "proc-macro2 1.0.66", @@ -4923,9 +4923,9 @@ dependencies = [ [[package]] name = "solana-streamer" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0125d00ca7e8e67d12f7f192a18d1dff2801a9c3e3239033af40b3e72ad92d76" +checksum = "3942a60afb0282b07ef0f3c32078145ab7545cbed2cac98f1ec4b9f63016df62" dependencies = [ "async-channel", "bytes", @@ -4956,9 +4956,9 @@ dependencies = [ [[package]] name = "solana-thin-client" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61b6137bb86d37323482474d841dd5baba41d5e3cb8827e4f0f5e37e9ff09153" +checksum = "d712aaf7701a4504521fc09f1743c647edf596e3852a64f6d66b2e5a822388f8" dependencies = [ "bincode", "log", @@ -4971,9 +4971,9 @@ dependencies = [ [[package]] name = "solana-tpu-client" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe350f0f2e6a098c118e9a5820280bb3c512f27560ad848f793825f2cd76fa5" +checksum = "48cb32f7443f80cb45e244d514a706b030b5a71ef86b0436c1d39cbfff5491b4" dependencies = [ "async-trait", "bincode", @@ -4996,9 +4996,9 @@ dependencies = [ [[package]] name = "solana-transaction-status" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bdf7379a72c051d7879f1c36cfdab5fed0653a2a613718bc5d343e44e603401" +checksum = "8aed485ddb4268b4e4ec64012016cd54ba3a4142377a99706fc3ab7768eb2bea" dependencies = [ "Inflector", "base64 0.21.4", @@ -5022,9 +5022,9 @@ dependencies = [ [[package]] name = "solana-udp-client" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22c5d62db9c69e8eced8eb8fdb1f8317dbcb3ad37cb5cc0d495aec85b5a46f7f" +checksum = "0c92798affef44c1ae2a694006209608044e99106b7945966d53586f5a95d9e2" dependencies = [ "async-trait", "solana-connection-cache", @@ -5037,9 +5037,9 @@ dependencies = [ [[package]] name = "solana-version" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d62712e119d6c616d1dea0fa5c1464f7316abe446e0b1eb4796cc9c77324c69" +checksum = "a80a20dfea2afed91761ab3fecc8f96b973a742dc7728f3e343711efe6e8e05f" dependencies = [ "log", "rustc_version", @@ -5053,9 +5053,9 @@ dependencies = [ [[package]] name = "solana-vote-program" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfde11af84827c25b484baf1743b5d0db068af32cf2e4f533148a2d2a31c2263" +checksum = "ab8b719e077cc9e42b8965dd06ff6b5f09fa2a436f2297efdcf471c05d187a6c" dependencies = [ "bincode", "log", @@ -5075,9 +5075,9 @@ dependencies = [ [[package]] name = "solana-zk-token-sdk" -version = "1.16.14" +version = "1.16.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bdec366a15133a70a8dfc4f027b5d0f508bd7cb46af11971076c9ebaf9ede2d" +checksum = "61aabdec9fe1b311dce5d21fa5bd58fbaa985e8003e0d0aedf3795113aacc1ea" dependencies = [ "aes-gcm-siv", "base64 0.21.4", diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 3f7ddc40c..5c2ab3447 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -8,8 +8,8 @@ edition = "2021" [dependencies] clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } -solana-sdk = "=1.16.14" -solana-client = "=1.16.14" +solana-sdk = "=1.16.15" +solana-client = "=1.16.15" serde = "1.0.186" serde_json = "1.0.85" ethnum = { version = "1.4", default-features = false, features = ["serde"] } diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index e223224bb..9dd6cbffd 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -8,10 +8,10 @@ edition = "2021" [dependencies] clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } -solana-sdk = "=1.16.14" -solana-client = "=1.16.14" -solana-clap-utils = "=1.16.14" -solana-cli-config = "=1.16.14" +solana-sdk = "=1.16.15" +solana-client = "=1.16.15" +solana-clap-utils = "=1.16.15" +solana-cli-config = "=1.16.15" hex = "0.4.2" serde = "1.0.186" serde_json = "1.0.85" diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index c193af9cf..5f4e56d8d 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -10,12 +10,12 @@ thiserror = "1.0" anyhow = "1.0" bincode = "1.3.1" evm-loader = { path = "../program", default-features = false, features = ["log", "async-trait", "serde_json"] } -solana-sdk = "=1.16.14" -solana-client = "=1.16.14" -solana-clap-utils = "=1.16.14" -solana-cli-config = "=1.16.14" -solana-cli = "=1.16.14" -solana-transaction-status = "=1.16.14" +solana-sdk = "=1.16.15" +solana-client = "=1.16.15" +solana-clap-utils = "=1.16.15" +solana-cli-config = "=1.16.15" +solana-cli = "=1.16.15" +solana-transaction-status = "=1.16.15" spl-token = { version = "~3.5", default-features = false, features = ["no-entrypoint"] } spl-associated-token-account = { version = "~1.1", default-features = false, features = ["no-entrypoint"] } bs58 = "0.4.0" diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index f1fab8ba7..800269a84 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -37,7 +37,7 @@ default = ["custom-heap"] [dependencies] linked_list_allocator = { version = "0.10", default-features = false } evm-loader-macro = { path = "../program-macro" } -solana-program = { version = "=1.16.14", default-features = false } +solana-program = { version = "=1.16.15", default-features = false } spl-token = { version = "~3.5", default-features = false, features = ["no-entrypoint"] } spl-associated-token-account = { version = "~1.1", default-features = false, features = ["no-entrypoint"] } mpl-token-metadata = { version = "1.13.2", default-features = false, features = ["no-entrypoint"] } From f6bd5185b38a1802a60b038613b1bdf1b91b913e Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Tue, 10 Oct 2023 12:58:56 +0300 Subject: [PATCH 041/318] NDEV-2252: Clean up tracer implementation (#208) * NDEV-2252: Use preserve_order serde_json feature * NDEV-2252: Make StructLog and StructLoggerResult Geth-compatible NDEV-2252: Fix StructLog field order NDEV-2252: Fix StructLoggerResult field order NDEV-2252: Output storage only on SLOAD and SSTORE opcodes NDEV-2252: Output storage in hex format without 0x prefix NDEV-2252: Output memory in hex format without 0x prefix NDEV-2252: Add StructLoggerResult serialization tests NDEV-2252: Fix StructLog format NDEV-2252: Add github link * NDEV-2252: Make tracer_config optional * NDEV-2252: Remove unused trace Events * NDEV-2252: Add more links to Geth structs --- evm_loader/Cargo.lock | 5 +- evm_loader/api/Cargo.toml | 2 +- evm_loader/cli/Cargo.toml | 2 +- evm_loader/lib/Cargo.toml | 2 +- evm_loader/program/Cargo.toml | 2 +- evm_loader/program/src/evm/memory.rs | 68 +------- evm_loader/program/src/evm/mod.rs | 30 +--- evm_loader/program/src/evm/opcode.rs | 1 - evm_loader/program/src/evm/stack.rs | 22 +-- evm_loader/program/src/evm/tracing/mod.rs | 18 +- .../src/evm/tracing/tracers/struct_logger.rs | 155 +++++++++++++----- 11 files changed, 143 insertions(+), 164 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 1d1b1b288..1cbfcb4d2 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -3998,10 +3998,11 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.105" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" +checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" dependencies = [ + "indexmap 2.0.0", "itoa", "ryu", "serde", diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 5c2ab3447..a68c3a4e6 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -11,7 +11,7 @@ evm-loader = { path = "../program", default-features = false, features = ["log"] solana-sdk = "=1.16.15" solana-client = "=1.16.15" serde = "1.0.186" -serde_json = "1.0.85" +serde_json = { version = "1.0.107", features = ["preserve_order"] } ethnum = { version = "1.4", default-features = false, features = ["serde"] } tokio = { version = "1", features = ["full"] } tracing = "0.1" diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index 9dd6cbffd..3304562fa 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -14,7 +14,7 @@ solana-clap-utils = "=1.16.15" solana-cli-config = "=1.16.15" hex = "0.4.2" serde = "1.0.186" -serde_json = "1.0.85" +serde_json = { version = "1.0.107", features = ["preserve_order"] } log = "0.4.17" fern = "0.6" ethnum = { version = "1.4", default-features = false, features = ["serde"] } diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 5f4e56d8d..49bc51c39 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -21,7 +21,7 @@ spl-associated-token-account = { version = "~1.1", default-features = false, fea bs58 = "0.4.0" hex = "0.4.2" serde = "1.0.186" -serde_json = "1.0.105" +serde_json = { version = "1.0.107", features = ["preserve_order"] } log = "0.4.17" rand = "0.8" ethnum = { version = "1.4", default-features = false, features = ["serde"] } diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 800269a84..3aa57a42e 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -51,7 +51,7 @@ borsh = "0.9" bincode = "1" serde_bytes = "0.11.12" serde = { version = "1.0.186", default-features = false, features = ["derive", "rc"] } -serde_json = { version = "1.0.105", optional = true } +serde_json = { version = "1.0.107", features = ["preserve_order"], optional = true } ethnum = { version = "1.4", default-features = false, features = ["serde"] } const_format = { version = "0.2.21" } cfg-if = { version = "1.0" } diff --git a/evm_loader/program/src/evm/memory.rs b/evm_loader/program/src/evm/memory.rs index 2ccb671fe..bff80dd62 100644 --- a/evm_loader/program/src/evm/memory.rs +++ b/evm_loader/program/src/evm/memory.rs @@ -4,11 +4,9 @@ use std::ops::Range; use solana_program::program_memory::{sol_memcpy, sol_memset}; use crate::error::Error; -#[cfg(not(target_os = "solana"))] -use crate::evm::tracing::TracerTypeOpt; use super::utils::checked_next_multiple_of_32; -use super::{tracing_event, Buffer}; +use super::Buffer; const MAX_MEMORY_SIZE: usize = 64 * 1024; const MEMORY_CAPACITY: usize = 1024; @@ -20,23 +18,14 @@ pub struct Memory { data: *mut u8, capacity: usize, size: usize, - #[cfg(not(target_os = "solana"))] - tracer: TracerTypeOpt, } impl Memory { - pub fn new(#[cfg(not(target_os = "solana"))] tracer: TracerTypeOpt) -> Self { - Self::with_capacity( - MEMORY_CAPACITY, - #[cfg(not(target_os = "solana"))] - tracer, - ) + pub fn new() -> Self { + Self::with_capacity(MEMORY_CAPACITY) } - pub fn with_capacity( - capacity: usize, - #[cfg(not(target_os = "solana"))] tracer: TracerTypeOpt, - ) -> Self { + pub fn with_capacity(capacity: usize) -> Self { unsafe { let layout = Layout::from_size_align_unchecked(capacity, MEMORY_ALIGN); let data = crate::allocator::EVM.alloc_zeroed(layout); @@ -48,8 +37,6 @@ impl Memory { data, capacity, size: 0, - #[cfg(not(target_os = "solana"))] - tracer, } } } @@ -70,8 +57,6 @@ impl Memory { data, capacity, size: v.len(), - #[cfg(not(target_os = "solana"))] - tracer: None, } } } @@ -157,14 +142,6 @@ impl Memory { } pub fn write_32(&mut self, offset: usize, value: &[u8; 32]) -> Result<(), Error> { - tracing_event!( - self, - super::tracing::Event::MemorySet { - offset, - data: value.to_vec() - } - ); - self.realloc(offset, 32)?; unsafe { @@ -176,14 +153,6 @@ impl Memory { } pub fn write_byte(&mut self, offset: usize, value: u8) -> Result<(), Error> { - tracing_event!( - self, - super::tracing::Event::MemorySet { - offset, - data: vec![value] - } - ); - self.realloc(offset, 1)?; unsafe { @@ -214,45 +183,16 @@ impl Memory { match source_offset { source_offset if source_offset >= source.len() => { - tracing_event!( - self, - super::tracing::Event::MemorySet { - offset, - data: vec![0; length] - } - ); - sol_memset(data, 0, length); } source_offset if (source_offset + length) > source.len() => { let source = &source[source_offset..]; - tracing_event!( - self, - super::tracing::Event::MemorySet { - offset, - data: { - let mut buffer = vec![0_u8; length]; - buffer[..source.len()].copy_from_slice(source); - buffer - } - } - ); - data[..source.len()].copy_from_slice(source); data[source.len()..].fill(0_u8); } source_offset => { let source = &source[source_offset..source_offset + length]; - - tracing_event!( - self, - super::tracing::Event::MemorySet { - offset, - data: source.to_vec() - } - ); - sol_memcpy(data, source, length); } } diff --git a/evm_loader/program/src/evm/mod.rs b/evm_loader/program/src/evm/mod.rs index 9e270e81b..add5b66f2 100644 --- a/evm_loader/program/src/evm/mod.rs +++ b/evm_loader/program/src/evm/mod.rs @@ -284,14 +284,8 @@ impl Machine { call_data: trx.extract_call_data(), return_data: Buffer::empty(), return_range: 0..0, - stack: Stack::new( - #[cfg(not(target_os = "solana"))] - tracer.clone(), - ), - memory: Memory::new( - #[cfg(not(target_os = "solana"))] - tracer.clone(), - ), + stack: Stack::new(), + memory: Memory::new(), pc: 0_usize, is_static: false, reason: Reason::Call, @@ -336,14 +330,8 @@ impl Machine { gas_limit: trx.gas_limit(), return_data: Buffer::empty(), return_range: 0..0, - stack: Stack::new( - #[cfg(not(target_os = "solana"))] - tracer.clone(), - ), - memory: Memory::new( - #[cfg(not(target_os = "solana"))] - tracer.clone(), - ), + stack: Stack::new(), + memory: Memory::new(), pc: 0_usize, is_static: false, reason: Reason::Create, @@ -449,14 +437,8 @@ impl Machine { call_data, return_data: Buffer::empty(), return_range: 0..0, - stack: Stack::new( - #[cfg(not(target_os = "solana"))] - self.tracer.clone(), - ), - memory: Memory::new( - #[cfg(not(target_os = "solana"))] - self.tracer.clone(), - ), + stack: Stack::new(), + memory: Memory::new(), pc: 0_usize, is_static: self.is_static, reason, diff --git a/evm_loader/program/src/evm/opcode.rs b/evm_loader/program/src/evm/opcode.rs index f1f8c9b48..6e3690291 100644 --- a/evm_loader/program/src/evm/opcode.rs +++ b/evm_loader/program/src/evm/opcode.rs @@ -811,7 +811,6 @@ impl Machine { let index = self.stack.pop_u256()?; let value = *self.stack.pop_array()?; - tracing_event!(self, super::tracing::Event::StorageSet { index, value }); tracing_event!(self, super::tracing::Event::StorageAccess { index, value }); backend.set_storage(self.context.contract, index, value)?; diff --git a/evm_loader/program/src/evm/stack.rs b/evm_loader/program/src/evm/stack.rs index 9470e0fd0..71d45258f 100644 --- a/evm_loader/program/src/evm/stack.rs +++ b/evm_loader/program/src/evm/stack.rs @@ -7,12 +7,8 @@ use std::{ use ethnum::{I256, U256}; -#[cfg(not(target_os = "solana"))] -use crate::evm::TracerTypeOpt; use crate::{error::Error, types::Address}; -use super::tracing_event; - const ELEMENT_SIZE: usize = 32; const STACK_SIZE: usize = ELEMENT_SIZE * 128; @@ -20,12 +16,10 @@ pub struct Stack { begin: *mut u8, end: *mut u8, top: *mut u8, - #[cfg(not(target_os = "solana"))] - tracer: TracerTypeOpt, } impl Stack { - pub fn new(#[cfg(not(target_os = "solana"))] tracer: TracerTypeOpt) -> Self { + pub fn new() -> Self { let (begin, end) = unsafe { let layout = Layout::from_size_align_unchecked(STACK_SIZE, ELEMENT_SIZE); let begin = crate::allocator::EVM.alloc(layout); @@ -42,8 +36,6 @@ impl Stack { begin, end, top: begin, - #[cfg(not(target_os = "solana"))] - tracer, } } @@ -70,13 +62,6 @@ impl Stack { return Err(Error::StackOverflow); } - tracing_event!( - self, - super::tracing::Event::StackPush { - value: unsafe { *self.read() } - } - ); - unsafe { self.top = self.top.add(32); } @@ -315,10 +300,7 @@ impl<'de> serde::Deserialize<'de> for Stack { return Err(E::invalid_length(v.len(), &self)); } - let mut stack = Stack::new( - #[cfg(not(target_os = "solana"))] - None, - ); + let mut stack = Stack::new(); unsafe { stack.top = stack.begin.add(v.len()); diff --git a/evm_loader/program/src/evm/tracing/mod.rs b/evm_loader/program/src/evm/tracing/mod.rs index b30817cb7..aed26b2e6 100644 --- a/evm_loader/program/src/evm/tracing/mod.rs +++ b/evm_loader/program/src/evm/tracing/mod.rs @@ -49,23 +49,13 @@ pub enum Event { gas_used: u64, return_data: Option>, }, - StackPush { - value: [u8; 32], - }, - MemorySet { - offset: usize, - data: Vec, - }, - StorageSet { - index: U256, - value: [u8; 32], - }, StorageAccess { index: U256, value: [u8; 32], }, } +/// See #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub struct BlockOverrides { @@ -83,6 +73,7 @@ pub struct BlockOverrides { pub base_fee: Option, // NOT SUPPORTED BY Neon EVM } +/// See #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub struct AccountOverride { @@ -108,8 +99,10 @@ impl AccountOverride { } } +/// See pub type AccountOverrides = HashMap; +/// See #[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] #[allow(clippy::module_name_repetitions, clippy::struct_excessive_bools)] @@ -124,9 +117,10 @@ pub struct TraceConfig { pub enable_return_data: bool, pub tracer: Option, pub timeout: Option, - pub tracer_config: Value, + pub tracer_config: Option, } +/// See #[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] #[allow(clippy::module_name_repetitions)] diff --git a/evm_loader/program/src/evm/tracing/tracers/struct_logger.rs b/evm_loader/program/src/evm/tracing/tracers/struct_logger.rs index 08ebd2dc1..8687c7a17 100644 --- a/evm_loader/program/src/evm/tracing/tracers/struct_logger.rs +++ b/evm_loader/program/src/evm/tracing/tracers/struct_logger.rs @@ -12,13 +12,14 @@ use crate::types::hexbytes::HexBytes; /// `StructLoggerResult` groups all structured logs emitted by the EVM /// while replaying a transaction in debug mode as well as transaction /// execution status, the amount of gas used and the return value +/// see #[derive(Serialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct StructLoggerResult { - /// Is execution failed or not - pub failed: bool, /// Total used gas but include the refunded gas pub gas: u64, + /// Is execution failed or not + pub failed: bool, /// The data after execution or revert reason pub return_value: String, /// Logs emitted during execution @@ -27,6 +28,7 @@ pub struct StructLoggerResult { /// `StructLog` stores a structured log emitted by the EVM while replaying a /// transaction in debug mode +/// see #[derive(Serialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct StructLog { @@ -35,24 +37,34 @@ pub struct StructLog { /// Operation name op: &'static str, /// Amount of used gas - gas: Option, + gas: u64, /// Gas cost for this instruction. gas_cost: u64, /// Current depth depth: usize, - /// Snapshot of the current memory sate #[serde(skip_serializing_if = "Option::is_none")] - memory: Option>, // U256 sized chunks + error: Option, /// Snapshot of the current stack sate #[serde(skip_serializing_if = "Option::is_none")] stack: Option>, - /// Result of the step + #[serde(skip_serializing_if = "Option::is_none")] return_data: Option, - /// Snapshot of the current storage + /// Snapshot of the current memory sate #[serde(skip_serializing_if = "Option::is_none")] - storage: Option>, + memory: Option>, // chunks of 32 bytes + /// Result of the step + /// Snapshot of the current storage #[serde(skip_serializing_if = "Option::is_none")] - error: Option, + storage: Option>, + /// Refund counter + #[serde(skip_serializing_if = "is_zero")] + refund: u64, +} + +/// This is only used for serialize +#[allow(clippy::trivially_copy_pass_by_ref)] +fn is_zero(num: &u64) -> bool { + *num == 0 } impl StructLog { @@ -62,22 +74,22 @@ impl StructLog { pc: u64, gas_cost: u64, depth: usize, - memory: Option>, + memory: Option>, stack: Option>, - storage: Option>, ) -> Self { let op = OPNAMES[opcode as usize]; Self { pc, op, - gas: None, + gas: 0, gas_cost, depth, memory, stack, return_data: None, - storage, + storage: None, error: None, + refund: 0, } } } @@ -148,27 +160,13 @@ impl EventListener for StructLogger { ) }; - let memory = if !self.config.enable_memory || memory.is_empty() { - None + let memory = if self.config.enable_memory { + Some(memory.chunks(32).map(hex::encode).collect()) } else { - Some( - memory - .chunks(32) - .map(|slice| slice.to_vec().into()) - .collect(), - ) - }; - - let storage = if self.config.disable_storage { None - } else { - self.logs - .last() - .and_then(|log| log.storage.clone()) - .or(None) }; - let log = StructLog::new(opcode, pc as u64, 0, self.depth, memory, stack, storage); + let log = StructLog::new(opcode, pc as u64, 0, self.depth, memory, stack); self.logs.push(log); } Event::EndStep { @@ -179,22 +177,24 @@ impl EventListener for StructLogger { .logs .last_mut() .expect("`EndStep` event before `BeginStep`"); - last.gas = Some(gas_used); + last.gas = gas_used; if !self.config.disable_storage { if let Some((index, value)) = self.storage_access.take() { - last.storage - .get_or_insert_with(Default::default) - .insert(index, value); + last.storage.get_or_insert_with(Default::default).insert( + hex::encode(index.to_be_bytes()), + hex::encode(value.to_be_bytes()), + ); }; } if self.config.enable_return_data { last.return_data = return_data.map(Into::into); } } - Event::StorageAccess { index, value } if !self.config.disable_storage => { - self.storage_access = Some((index, U256::from_be_bytes(value))); + Event::StorageAccess { index, value } => { + if !self.config.disable_storage { + self.storage_access = Some((index, U256::from_be_bytes(value))); + } } - _ => (), }; } @@ -217,3 +217,84 @@ impl EventListener for StructLogger { serde_json::to_value(result).expect("Conversion error") } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_serialize_struct_logger_result_all_fields() { + let struct_logger_result = StructLoggerResult { + gas: 20000, + failed: false, + return_value: "000000000000000000000000000000000000000000000000000000000000001b" + .to_string(), + struct_logs: vec![StructLog { + pc: 8, + op: "PUSH2", + gas: 0, + gas_cost: 0, + depth: 1, + stack: Some(vec![U256::from(0u8), U256::from(1u8)]), + memory: Some(vec![ + "0000000000000000000000000000000000000000000000000000000000000000".to_string(), + "0000000000000000000000000000000000000000000000000000000000000000".to_string(), + "0000000000000000000000000000000000000000000000000000000000000080".to_string(), + ]), + return_data: None, + storage: None, + refund: 0, + error: None, + }], + }; + assert_eq!(serde_json::to_string(&struct_logger_result).unwrap(), "{\"gas\":20000,\"failed\":false,\"returnValue\":\"000000000000000000000000000000000000000000000000000000000000001b\",\"structLogs\":[{\"pc\":8,\"op\":\"PUSH2\",\"gas\":0,\"gasCost\":0,\"depth\":1,\"stack\":[\"0x0\",\"0x1\"],\"memory\":[\"0000000000000000000000000000000000000000000000000000000000000000\",\"0000000000000000000000000000000000000000000000000000000000000000\",\"0000000000000000000000000000000000000000000000000000000000000080\"]}]}"); + } + + #[test] + fn test_serialize_struct_logger_result_no_optional_fields() { + let struct_logger_result = StructLoggerResult { + gas: 20000, + failed: false, + return_value: "000000000000000000000000000000000000000000000000000000000000001b" + .to_string(), + struct_logs: vec![StructLog { + pc: 0, + op: "PUSH1", + gas: 0, + gas_cost: 0, + depth: 1, + stack: None, + memory: None, + return_data: None, + storage: None, + refund: 0, + error: None, + }], + }; + assert_eq!(serde_json::to_string(&struct_logger_result).unwrap(), "{\"gas\":20000,\"failed\":false,\"returnValue\":\"000000000000000000000000000000000000000000000000000000000000001b\",\"structLogs\":[{\"pc\":0,\"op\":\"PUSH1\",\"gas\":0,\"gasCost\":0,\"depth\":1}]}"); + } + + #[test] + fn test_serialize_struct_logger_result_empty_stack_empty_memory() { + let struct_logger_result = StructLoggerResult { + gas: 20000, + failed: false, + return_value: "000000000000000000000000000000000000000000000000000000000000001b" + .to_string(), + struct_logs: vec![StructLog { + pc: 0, + op: "PUSH1", + gas: 0, + gas_cost: 0, + depth: 1, + stack: Some(vec![]), + memory: Some(vec![]), + return_data: None, + storage: None, + refund: 0, + error: None, + }], + }; + assert_eq!(serde_json::to_string(&struct_logger_result).unwrap(), "{\"gas\":20000,\"failed\":false,\"returnValue\":\"000000000000000000000000000000000000000000000000000000000000001b\",\"structLogs\":[{\"pc\":0,\"op\":\"PUSH1\",\"gas\":0,\"gasCost\":0,\"depth\":1,\"stack\":[],\"memory\":[]}]}"); + } +} From 641bc1d16421d3622933730572c8adae033a0cb9 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Thu, 12 Oct 2023 11:03:41 +0300 Subject: [PATCH 042/318] NDEV-2312: Upgrade Solana to v1.16.16 (#216) --- .github/workflows/deploy.py | 4 +- evm_loader/Cargo.lock | 445 +++++++++++++++++++++++++--------- evm_loader/api/Cargo.toml | 4 +- evm_loader/cli/Cargo.toml | 8 +- evm_loader/lib/Cargo.toml | 12 +- evm_loader/program/Cargo.toml | 2 +- 6 files changed, 350 insertions(+), 125 deletions(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index 646939377..85ab8d573 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -30,8 +30,8 @@ DOCKER_USER = os.environ.get("DHUBU") DOCKER_PASSWORD = os.environ.get("DHUBP") IMAGE_NAME = 'neonlabsorg/evm_loader' -SOLANA_NODE_VERSION = 'v1.16.15' -SOLANA_BPF_VERSION = 'v1.16.15' +SOLANA_NODE_VERSION = 'v1.16.16' +SOLANA_BPF_VERSION = 'v1.16.16' VERSION_BRANCH_TEMPLATE = r"[vt]{1}\d{1,2}\.\d{1,2}\.x.*" docker_client = docker.APIClient() diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 1cbfcb4d2..158ce6b22 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -865,9 +865,9 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.13.1" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" +checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" dependencies = [ "bytemuck_derive", ] @@ -1732,8 +1732,8 @@ dependencies = [ "serde_bytes", "serde_json", "solana-program", - "spl-associated-token-account", - "spl-token", + "spl-associated-token-account 1.1.3", + "spl-token 3.5.0", "static_assertions", "thiserror", ] @@ -2699,7 +2699,7 @@ dependencies = [ "borsh 0.9.3", "bytemuck", "mpl-token-metadata-context-derive 0.2.1", - "num-derive", + "num-derive 0.3.3", "num-traits", "rmp-serde", "serde", @@ -2720,12 +2720,12 @@ dependencies = [ "mpl-token-auth-rules", "mpl-token-metadata-context-derive 0.3.0", "mpl-utils", - "num-derive", + "num-derive 0.3.3", "num-traits", "shank", "solana-program", - "spl-associated-token-account", - "spl-token", + "spl-associated-token-account 1.1.3", + "spl-token 3.5.0", "thiserror", ] @@ -2757,7 +2757,7 @@ checksum = "3f2e4f92aec317d5853c0cc4c03c55f5178511c45bb3dbb441aea63117bf3dc9" dependencies = [ "arrayref", "solana-program", - "spl-token-2022", + "spl-token-2022 0.6.1", ] [[package]] @@ -2850,8 +2850,8 @@ dependencies = [ "solana-client", "solana-sdk", "solana-transaction-status", - "spl-associated-token-account", - "spl-token", + "spl-associated-token-account 1.1.3", + "spl-token 3.5.0", "thiserror", "tokio", "tracing", @@ -2959,6 +2959,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "num-derive" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfb77679af88f8b125209d354a202862602672222e7f2313fdd6dc349bad4712" +dependencies = [ + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 2.0.28", +] + [[package]] name = "num-integer" version = "0.1.45" @@ -3029,6 +3040,15 @@ dependencies = [ "num_enum_derive 0.6.1", ] +[[package]] +name = "num_enum" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70bf6736f74634d299d00086f02986875b3c2d924781a6a2cb6c201e73da0ceb" +dependencies = [ + "num_enum_derive 0.7.0", +] + [[package]] name = "num_enum_derive" version = "0.5.11" @@ -3053,6 +3073,18 @@ dependencies = [ "syn 2.0.28", ] +[[package]] +name = "num_enum_derive" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ea360eafe1022f7cc56cd7b869ed57330fb2453d0c7831d99b74c65d2f5597" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 2.0.28", +] + [[package]] name = "number_prefix" version = "0.4.0" @@ -4234,9 +4266,9 @@ dependencies = [ [[package]] name = "solana-account-decoder" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "850d5d9dc8fa6ea42f4e61c78e296bbbce5a3531ff4cb3c58ef36ee31781049c" +checksum = "f52aec62a85932e26d1085864b0f7b99b31934aec8dd132429bfef6d7fb1d3a6" dependencies = [ "Inflector", "base64 0.21.4", @@ -4250,22 +4282,23 @@ dependencies = [ "solana-address-lookup-table-program", "solana-config-program", "solana-sdk", - "spl-token", - "spl-token-2022", + "spl-token 4.0.0", + "spl-token-2022 0.9.0", + "spl-token-metadata-interface", "thiserror", "zstd 0.11.2+zstd.1.5.2", ] [[package]] name = "solana-address-lookup-table-program" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7f867cde478a078d4c4ceb113f4f9ac7e29c2efea98f80a2b30cdcd7be83c5" +checksum = "ee0bd25f4ba0a15fc16c57b41b1e1b14f5271b83214fda158fdedb58758d394e" dependencies = [ "bincode", "bytemuck", "log", - "num-derive", + "num-derive 0.3.3", "num-traits", "rustc_version", "serde", @@ -4279,9 +4312,9 @@ dependencies = [ [[package]] name = "solana-bpf-loader-program" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1eaf42dbfe8a42b80e24f2c087a3935d6e7bb49886313b006d88fb04fdc2a02f" +checksum = "05fb3284ae3a51bd173c7f61fcd9d6c1a10cfe46b082ce3189dec9f86120c245" dependencies = [ "bincode", "byteorder", @@ -4298,9 +4331,9 @@ dependencies = [ [[package]] name = "solana-clap-utils" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c99636da9a4acad58d0e8142e36395ece48fc41c396e297e702b6a789b190f" +checksum = "e963043668c640183d48472b281ebb9f713e0c36df0271961d23e6a394e09070" dependencies = [ "chrono", "clap 2.34.0", @@ -4316,9 +4349,9 @@ dependencies = [ [[package]] name = "solana-cli" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27cd5c7630ad1469cfe959f9e7dfde97892c8c66666602d141c39d4d17605771" +checksum = "6f30e53107537d92eed3a0f933905b3d5cc4c224d29df89460f971a58de8bf0c" dependencies = [ "bincode", "bs58", @@ -4360,16 +4393,16 @@ dependencies = [ "solana-version", "solana-vote-program", "solana_rbpf", - "spl-memo", + "spl-memo 4.0.0", "thiserror", "tiny-bip39", ] [[package]] name = "solana-cli-config" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ae4ba224e834b5d71c884a356bf1e23b5999ef4edd8996a42a8ac0dd680315b" +checksum = "febecf05517593d6da0592fc6039b069e659a1e062b114eeaf4c22d44293b2db" dependencies = [ "dirs-next", "lazy_static", @@ -4383,9 +4416,9 @@ dependencies = [ [[package]] name = "solana-cli-output" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56d56e77a341047880483438de34a5dea76eb79449ea9f969422710fb7f932b6" +checksum = "864c328349439ea0f451d722d804392741b66a7237d05cd69dea0bb23d74f5cb" dependencies = [ "Inflector", "base64 0.21.4", @@ -4405,14 +4438,14 @@ dependencies = [ "solana-sdk", "solana-transaction-status", "solana-vote-program", - "spl-memo", + "spl-memo 4.0.0", ] [[package]] name = "solana-client" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acc7a437165d8fcfac3c63963e394f0ea497b5d2a75159bb3a1ed75dbeb36a7e" +checksum = "52ccf7bb34fb81c74582a9011babaa2e0220da56c71186e77f45a6f352017fdb" dependencies = [ "async-trait", "bincode", @@ -4443,9 +4476,9 @@ dependencies = [ [[package]] name = "solana-config-program" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6f9f2201c7e526581511fa6525e281518be5cabaee82bd5b29fe4b78744148d" +checksum = "7fd0fc1efb91a1661aeb1ff6a691156c3b1bffdaed0aa096589499dd83f9e50b" dependencies = [ "bincode", "chrono", @@ -4457,9 +4490,9 @@ dependencies = [ [[package]] name = "solana-connection-cache" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ee52de352e10e53b252df0815d685a9c6f3e8d3baa0f65e214dfcd247db0e21" +checksum = "8759e9cb9b1e92a94c31812169ecb5e65b5e215fb70fb68691e03655de5b7b6c" dependencies = [ "async-trait", "bincode", @@ -4478,9 +4511,9 @@ dependencies = [ [[package]] name = "solana-faucet" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e7a5d760f9bb71eb73a26c7950ddce2dc3257262cf6cc9fc92918c3c7ac9022" +checksum = "f24d2bd1a6f5834700d6bbef9abfebad37dd31a11156867bb5bb39b635f2a7f6" dependencies = [ "bincode", "byteorder", @@ -4495,16 +4528,16 @@ dependencies = [ "solana-metrics", "solana-sdk", "solana-version", - "spl-memo", + "spl-memo 4.0.0", "thiserror", "tokio", ] [[package]] name = "solana-frozen-abi" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "361cc834e5fbbe1a73f1d904fcb8ab052a665e5be6061bd1ba7ab478d7d17c9c" +checksum = "02eb4f0ed3eade20f4abdcc0031167344237cd6e16808bd0f33945f9db7861fe" dependencies = [ "ahash 0.8.3", "blake3", @@ -4535,9 +4568,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi-macro" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "575d875dc050689f9f88c542e292e295e2f081d4e96e0df297981e45cbad8824" +checksum = "f28514761a285944cbad5b3d7930546369b80a713ba37d84bcf6ed2753611765" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", @@ -4547,9 +4580,9 @@ dependencies = [ [[package]] name = "solana-logger" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00faf7aa6a3f47c542bd45d2d7f13af9a382d993e647976a676fe1b0eec4eb2" +checksum = "2c310c6749435ce1ea25a9ae3edfb2fd2c2aed2aa4d4f7e0487a8077a0b1ee30" dependencies = [ "env_logger", "lazy_static", @@ -4558,9 +4591,9 @@ dependencies = [ [[package]] name = "solana-measure" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e19c6e1b35df3c212619a7995ae3576fa92ab15ecfc065899f21385cbe45c95" +checksum = "0d171357580e62aa4ca19c780e25f4e74de064e2780cb8b9f6b6901d986fcd23" dependencies = [ "log", "solana-sdk", @@ -4568,9 +4601,9 @@ dependencies = [ [[package]] name = "solana-metrics" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10e62760a5f87d836169eb3bb446bae174181db07d2c8016be36de49c04fd432" +checksum = "013cbb3c82588278d2be18d3317ece5286cb54a3a06d5d38fc31e2a76a6d5e2d" dependencies = [ "crossbeam-channel", "gethostname", @@ -4582,9 +4615,9 @@ dependencies = [ [[package]] name = "solana-net-utils" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308c4c36c634d418589cf1df121d143819feff81932de81640de3d64878934eb" +checksum = "c50d7cac0694b1fe07499de25404a0c7d6836457e359aba3b08c3983c3dc5eb6" dependencies = [ "bincode", "clap 3.2.23", @@ -4604,9 +4637,9 @@ dependencies = [ [[package]] name = "solana-perf" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4d44a4998ba6d9b37e89399d9ce2812e84489dd4665df619fb23366e1c2ec1b" +checksum = "395d559e5be2c439551298e9fa95561807f24921fd9a1e08bb82a3dc05c02dea" dependencies = [ "ahash 0.8.3", "bincode", @@ -4631,9 +4664,9 @@ dependencies = [ [[package]] name = "solana-program" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9863ff5c6e828015bec331c26fb53e48352a264a9be682e7e078d2c3b3e93b46" +checksum = "cff2aa5434a77413e9d43e971ceb47bdb003f2e8bbc0365a25b684aca2605c25" dependencies = [ "ark-bn254", "ark-ec", @@ -4662,7 +4695,7 @@ dependencies = [ "log", "memoffset 0.9.0", "num-bigint 0.4.3", - "num-derive", + "num-derive 0.3.3", "num-traits", "parking_lot", "rand 0.7.3", @@ -4686,9 +4719,9 @@ dependencies = [ [[package]] name = "solana-program-runtime" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05813d4d2e141ab4449cf684cc5b05512dfaabb7251561c5bb1ccf1e4221b210" +checksum = "9d1832fefc2187142dac169812518ec20da68b09abad86e4a78f8ae1787e4f56" dependencies = [ "base64 0.21.4", "bincode", @@ -4697,7 +4730,7 @@ dependencies = [ "itertools", "libc", "log", - "num-derive", + "num-derive 0.3.3", "num-traits", "percentage", "rand 0.7.3", @@ -4714,9 +4747,9 @@ dependencies = [ [[package]] name = "solana-pubsub-client" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd0753cdde1710f50d58bd40a45e58f5368a25dabff6b18ba635c3d6959a558" +checksum = "89388addbc3192407d948634f82c95c4dbe1efbe578582abfd136720e059556e" dependencies = [ "crossbeam-channel", "futures-util", @@ -4739,9 +4772,9 @@ dependencies = [ [[package]] name = "solana-quic-client" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d96abde446eaa903d16961cfd3a6e98dc0d680b9edd61c39938c61548d53e" +checksum = "b7897b876a6df2d97b3a5ddfd764155c0591e3497e863fd7fdf32b54de4e2644" dependencies = [ "async-mutex", "async-trait", @@ -4767,9 +4800,9 @@ dependencies = [ [[package]] name = "solana-rayon-threadlimit" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82ab62fc62458271d746678a3f5625e1654e3cb42a8f318ef4f1ea25991bb085" +checksum = "6ba17a930f9974a17a9a6c6e82e7f89b40127e9cc0f9c17cfc29fc5b149d2c38" dependencies = [ "lazy_static", "num_cpus", @@ -4777,15 +4810,15 @@ dependencies = [ [[package]] name = "solana-remote-wallet" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "863f10b8c2a893d1ec85b3ae8020c714512a67302b80c24dde0016eea4034a7c" +checksum = "80fb35e3fa78ef1d08a6a1d852e2c357e6ae388cb307d24fad359f57c34429f0" dependencies = [ "console", "dialoguer", "hidapi", "log", - "num-derive", + "num-derive 0.3.3", "num-traits", "parking_lot", "qstring", @@ -4797,9 +4830,9 @@ dependencies = [ [[package]] name = "solana-rpc-client" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df04998cef2d0fe1291599b69acafc7f8cd87305d7f1525c8ae10aef1cc5411c" +checksum = "c512944689d747a87f76936c89bb59f5be6c9a3189631857f49746cfa47d5bd1" dependencies = [ "async-trait", "base64 0.21.4", @@ -4823,9 +4856,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-api" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e2912ddbff841fbce1e30b0b9a420993c63b6cc7866e5f0af3740fcd6d85bb8" +checksum = "6e918b75f8ac4c358a6b512bf8b7dafc8166ddcb52ded5164c6235e0693ccb09" dependencies = [ "base64 0.21.4", "bs58", @@ -4839,15 +4872,15 @@ dependencies = [ "solana-sdk", "solana-transaction-status", "solana-version", - "spl-token-2022", + "spl-token-2022 0.9.0", "thiserror", ] [[package]] name = "solana-rpc-client-nonce-utils" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d31100f6cc340dd322f57d00a334fa0a96f628ba86b04fcda1f84307deb14c31" +checksum = "c6e360ea2f3a756bdf6256c1f6ef13f8b01b5d2a7855b4f16cafb4a4017f0557" dependencies = [ "clap 2.34.0", "solana-clap-utils", @@ -4858,9 +4891,9 @@ dependencies = [ [[package]] name = "solana-sdk" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "621e6973766420162541b26e7974783d32d5471571610da30c5bb0b6263046c9" +checksum = "8b1002048941cedbd7dd6a96fdaa3dc5238b998aaa70b81946b1e3ec108cc2be" dependencies = [ "assert_matches", "base64 0.21.4", @@ -4883,7 +4916,7 @@ dependencies = [ "libsecp256k1", "log", "memmap2", - "num-derive", + "num-derive 0.3.3", "num-traits", "num_enum 0.6.1", "pbkdf2 0.11.0", @@ -4911,9 +4944,9 @@ dependencies = [ [[package]] name = "solana-sdk-macro" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd177a74fb3a0a362f1292c027d668eff609ac189f08b78158324587a0a4f8d1" +checksum = "4b41b63b2da4a37ce323aba108db21f4c7bfa638dd1bf58fdc870f83bdce48ba" dependencies = [ "bs58", "proc-macro2 1.0.66", @@ -4924,9 +4957,9 @@ dependencies = [ [[package]] name = "solana-streamer" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3942a60afb0282b07ef0f3c32078145ab7545cbed2cac98f1ec4b9f63016df62" +checksum = "f00e575f2bd5ae2776870fbd1d7379d4ad392c015e2a4e2a328953b821a9d36d" dependencies = [ "async-channel", "bytes", @@ -4957,9 +4990,9 @@ dependencies = [ [[package]] name = "solana-thin-client" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d712aaf7701a4504521fc09f1743c647edf596e3852a64f6d66b2e5a822388f8" +checksum = "df328e2624cce68c9949a53eac317a264eceb997131cb9bd22175698a5f5dc74" dependencies = [ "bincode", "log", @@ -4972,9 +5005,9 @@ dependencies = [ [[package]] name = "solana-tpu-client" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48cb32f7443f80cb45e244d514a706b030b5a71ef86b0436c1d39cbfff5491b4" +checksum = "6a8ce6fe221c0e1fd8aa3078b8fcb0cc3f4c27942f1256b57a60608d81ae5348" dependencies = [ "async-trait", "bincode", @@ -4997,14 +5030,14 @@ dependencies = [ [[package]] name = "solana-transaction-status" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8aed485ddb4268b4e4ec64012016cd54ba3a4142377a99706fc3ab7768eb2bea" +checksum = "db0b811793e78a908119cc02edca3ff8b54d5660104ebd06cc0e2e7e2f66900b" dependencies = [ "Inflector", "base64 0.21.4", "bincode", - "borsh 0.9.3", + "borsh 0.10.3", "bs58", "lazy_static", "log", @@ -5014,18 +5047,18 @@ dependencies = [ "solana-account-decoder", "solana-address-lookup-table-program", "solana-sdk", - "spl-associated-token-account", - "spl-memo", - "spl-token", - "spl-token-2022", + "spl-associated-token-account 2.2.0", + "spl-memo 4.0.0", + "spl-token 4.0.0", + "spl-token-2022 0.9.0", "thiserror", ] [[package]] name = "solana-udp-client" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c92798affef44c1ae2a694006209608044e99106b7945966d53586f5a95d9e2" +checksum = "897ff303a15ba956e80573dee4cf96d94d41a69adc5362898b98851e347505ad" dependencies = [ "async-trait", "solana-connection-cache", @@ -5038,9 +5071,9 @@ dependencies = [ [[package]] name = "solana-version" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a80a20dfea2afed91761ab3fecc8f96b973a742dc7728f3e343711efe6e8e05f" +checksum = "9513754d3b2203a0e1045a211c5d68e72e4ed135e477344c21d096897fd2bf70" dependencies = [ "log", "rustc_version", @@ -5054,13 +5087,13 @@ dependencies = [ [[package]] name = "solana-vote-program" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab8b719e077cc9e42b8965dd06ff6b5f09fa2a436f2297efdcf471c05d187a6c" +checksum = "3b6bfc5302ce0383eb129aa3a916705a20d22c4ad448144ef684b7b028d4053f" dependencies = [ "bincode", "log", - "num-derive", + "num-derive 0.3.3", "num-traits", "rustc_version", "serde", @@ -5076,9 +5109,9 @@ dependencies = [ [[package]] name = "solana-zk-token-sdk" -version = "1.16.15" +version = "1.16.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61aabdec9fe1b311dce5d21fa5bd58fbaa985e8003e0d0aedf3795113aacc1ea" +checksum = "5d1fe77918563768a65fd5d6cd2fa06cf0aeb11e529a1ef8c230b0fe018600e3" dependencies = [ "aes-gcm-siv", "base64 0.21.4", @@ -5090,7 +5123,7 @@ dependencies = [ "itertools", "lazy_static", "merlin", - "num-derive", + "num-derive 0.3.3", "num-traits", "rand 0.7.3", "serde", @@ -5146,11 +5179,62 @@ checksum = "978dba3bcbe88d0c2c58366c254d9ea41c5f73357e72fc0bdee4d6b5fc99c8f4" dependencies = [ "assert_matches", "borsh 0.9.3", - "num-derive", + "num-derive 0.3.3", + "num-traits", + "solana-program", + "spl-token 3.5.0", + "spl-token-2022 0.6.1", + "thiserror", +] + +[[package]] +name = "spl-associated-token-account" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "385e31c29981488f2820b2022d8e731aae3b02e6e18e2fd854e4c9a94dc44fc3" +dependencies = [ + "assert_matches", + "borsh 0.10.3", + "num-derive 0.4.1", "num-traits", "solana-program", - "spl-token", - "spl-token-2022", + "spl-token 4.0.0", + "spl-token-2022 0.9.0", + "thiserror", +] + +[[package]] +name = "spl-discriminator" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cce5d563b58ef1bb2cdbbfe0dfb9ffdc24903b10ae6a4df2d8f425ece375033f" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator-derive", +] + +[[package]] +name = "spl-discriminator-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fadbefec4f3c678215ca72bd71862697bb06b41fd77c0088902dd3203354387b" +dependencies = [ + "quote 1.0.32", + "spl-discriminator-syn", + "syn 2.0.28", +] + +[[package]] +name = "spl-discriminator-syn" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e5f2044ca42c8938d54d1255ce599c79a1ffd86b677dfab695caa20f9ffc3f2" +dependencies = [ + "proc-macro2 1.0.66", + "quote 1.0.32", + "sha2 0.10.6", + "syn 2.0.28", "thiserror", ] @@ -5163,6 +5247,67 @@ dependencies = [ "solana-program", ] +[[package]] +name = "spl-memo" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f180b03318c3dbab3ef4e1e4d46d5211ae3c780940dd0a28695aba4b59a75a" +dependencies = [ + "solana-program", +] + +[[package]] +name = "spl-pod" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2881dddfca792737c0706fa0175345ab282b1b0879c7d877bad129645737c079" +dependencies = [ + "borsh 0.10.3", + "bytemuck", + "solana-program", + "solana-zk-token-sdk", + "spl-program-error", +] + +[[package]] +name = "spl-program-error" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "249e0318493b6bcf27ae9902600566c689b7dfba9f1bdff5893e92253374e78c" +dependencies = [ + "num-derive 0.4.1", + "num-traits", + "solana-program", + "spl-program-error-derive", + "thiserror", +] + +[[package]] +name = "spl-program-error-derive" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5269c8e868da17b6552ef35a51355a017bd8e0eae269c201fef830d35fa52c" +dependencies = [ + "proc-macro2 1.0.66", + "quote 1.0.32", + "sha2 0.10.6", + "syn 2.0.28", +] + +[[package]] +name = "spl-tlv-account-resolution" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "062e148d3eab7b165582757453632ffeef490c02c86a48bfdb4988f63eefb3b9" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator", + "spl-pod", + "spl-program-error", + "spl-type-length-value", +] + [[package]] name = "spl-token" version = "3.5.0" @@ -5171,13 +5316,28 @@ checksum = "8e85e168a785e82564160dcb87b2a8e04cee9bfd1f4d488c729d53d6a4bd300d" dependencies = [ "arrayref", "bytemuck", - "num-derive", + "num-derive 0.3.3", "num-traits", "num_enum 0.5.11", "solana-program", "thiserror", ] +[[package]] +name = "spl-token" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08459ba1b8f7c1020b4582c4edf0f5c7511a5e099a7a97570c9698d4f2337060" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive 0.3.3", + "num-traits", + "num_enum 0.6.1", + "solana-program", + "thiserror", +] + [[package]] name = "spl-token-2022" version = "0.6.1" @@ -5186,16 +5346,81 @@ checksum = "0043b590232c400bad5ee9eb983ced003d15163c4c5d56b090ac6d9a57457b47" dependencies = [ "arrayref", "bytemuck", - "num-derive", + "num-derive 0.3.3", "num-traits", "num_enum 0.5.11", "solana-program", "solana-zk-token-sdk", - "spl-memo", - "spl-token", + "spl-memo 3.0.1", + "spl-token 3.5.0", + "thiserror", +] + +[[package]] +name = "spl-token-2022" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4abf34a65ba420584a0c35f3903f8d727d1f13ababbdc3f714c6b065a686e86" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive 0.4.1", + "num-traits", + "num_enum 0.7.0", + "solana-program", + "solana-zk-token-sdk", + "spl-memo 4.0.0", + "spl-pod", + "spl-token 4.0.0", + "spl-token-metadata-interface", + "spl-transfer-hook-interface", + "spl-type-length-value", "thiserror", ] +[[package]] +name = "spl-token-metadata-interface" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c16ce3ba6979645fb7627aa1e435576172dd63088dc7848cb09aa331fa1fe4f" +dependencies = [ + "borsh 0.10.3", + "solana-program", + "spl-discriminator", + "spl-pod", + "spl-program-error", + "spl-type-length-value", +] + +[[package]] +name = "spl-transfer-hook-interface" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "051d31803f873cabe71aec3c1b849f35248beae5d19a347d93a5c9cccc5d5a9b" +dependencies = [ + "arrayref", + "bytemuck", + "solana-program", + "spl-discriminator", + "spl-pod", + "spl-program-error", + "spl-tlv-account-resolution", + "spl-type-length-value", +] + +[[package]] +name = "spl-type-length-value" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a468e6f6371f9c69aae760186ea9f1a01c2908351b06a5e0026d21cfc4d7ecac" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator", + "spl-pod", + "spl-program-error", +] + [[package]] name = "static_assertions" version = "1.1.0" diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index a68c3a4e6..c116aefb6 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -8,8 +8,8 @@ edition = "2021" [dependencies] clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } -solana-sdk = "=1.16.15" -solana-client = "=1.16.15" +solana-sdk = "=1.16.16" +solana-client = "=1.16.16" serde = "1.0.186" serde_json = { version = "1.0.107", features = ["preserve_order"] } ethnum = { version = "1.4", default-features = false, features = ["serde"] } diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index 3304562fa..63585f473 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -8,10 +8,10 @@ edition = "2021" [dependencies] clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } -solana-sdk = "=1.16.15" -solana-client = "=1.16.15" -solana-clap-utils = "=1.16.15" -solana-cli-config = "=1.16.15" +solana-sdk = "=1.16.16" +solana-client = "=1.16.16" +solana-clap-utils = "=1.16.16" +solana-cli-config = "=1.16.16" hex = "0.4.2" serde = "1.0.186" serde_json = { version = "1.0.107", features = ["preserve_order"] } diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 49bc51c39..5dcf73d02 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -10,12 +10,12 @@ thiserror = "1.0" anyhow = "1.0" bincode = "1.3.1" evm-loader = { path = "../program", default-features = false, features = ["log", "async-trait", "serde_json"] } -solana-sdk = "=1.16.15" -solana-client = "=1.16.15" -solana-clap-utils = "=1.16.15" -solana-cli-config = "=1.16.15" -solana-cli = "=1.16.15" -solana-transaction-status = "=1.16.15" +solana-sdk = "=1.16.16" +solana-client = "=1.16.16" +solana-clap-utils = "=1.16.16" +solana-cli-config = "=1.16.16" +solana-cli = "=1.16.16" +solana-transaction-status = "=1.16.16" spl-token = { version = "~3.5", default-features = false, features = ["no-entrypoint"] } spl-associated-token-account = { version = "~1.1", default-features = false, features = ["no-entrypoint"] } bs58 = "0.4.0" diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 3aa57a42e..159ef55a6 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -37,7 +37,7 @@ default = ["custom-heap"] [dependencies] linked_list_allocator = { version = "0.10", default-features = false } evm-loader-macro = { path = "../program-macro" } -solana-program = { version = "=1.16.15", default-features = false } +solana-program = { version = "=1.16.16", default-features = false } spl-token = { version = "~3.5", default-features = false, features = ["no-entrypoint"] } spl-associated-token-account = { version = "~1.1", default-features = false, features = ["no-entrypoint"] } mpl-token-metadata = { version = "1.13.2", default-features = false, features = ["no-entrypoint"] } From a04990ff0220dedd6a9691c10df3541451e35bc1 Mon Sep 17 00:00:00 2001 From: Stanislav Tkach Date: Thu, 12 Oct 2023 16:32:23 +0200 Subject: [PATCH 043/318] Add 'write version' to EmulateRequestModel (#212) * Add 'write version' to EmulateRequestModel --- evm_loader/api/src/api_context.rs | 10 +- .../api/src/api_server/handlers/emulate.rs | 8 +- .../handlers/get_ether_account_data.rs | 2 +- .../src/api_server/handlers/get_storage_at.rs | 2 +- .../api/src/api_server/handlers/trace.rs | 15 ++- evm_loader/cli/src/main.rs | 1 + evm_loader/lib/src/rpc/db_call_client.rs | 21 ++-- evm_loader/lib/src/types/request_models.rs | 1 + evm_loader/lib/src/types/tracer_ch_db.rs | 100 +++++++++++++++--- 9 files changed, 125 insertions(+), 35 deletions(-) diff --git a/evm_loader/api/src/api_context.rs b/evm_loader/api/src/api_context.rs index 409638aff..1d040a2d1 100644 --- a/evm_loader/api/src/api_context.rs +++ b/evm_loader/api/src/api_context.rs @@ -6,19 +6,21 @@ use std::sync::Arc; pub async fn build_rpc_client( state: &NeonApiState, slot: Option, + tx_index_in_block: Option, ) -> Result, NeonError> { if let Some(slot) = slot { - return build_call_db_client(state, slot).await; + build_call_db_client(state, slot, tx_index_in_block).await + } else { + Ok(state.rpc_client.clone()) } - - Ok(state.rpc_client.clone()) } pub async fn build_call_db_client( state: &NeonApiState, slot: u64, + tx_index_in_block: Option, ) -> Result, NeonError> { Ok(Arc::new( - CallDbClient::new(state.tracer_db.clone(), slot).await?, + CallDbClient::new(state.tracer_db.clone(), slot, tx_index_in_block).await?, )) } diff --git a/evm_loader/api/src/api_server/handlers/emulate.rs b/evm_loader/api/src/api_server/handlers/emulate.rs index 1a3da87a7..f2d2119bd 100644 --- a/evm_loader/api/src/api_server/handlers/emulate.rs +++ b/evm_loader/api/src/api_server/handlers/emulate.rs @@ -19,7 +19,13 @@ pub async fn emulate( ) -> impl Responder { let tx = emulate_request.tx_params.into(); - let rpc_client = match api_context::build_rpc_client(&state, emulate_request.slot).await { + let rpc_client = match api_context::build_rpc_client( + &state, + emulate_request.slot, + emulate_request.tx_index_in_block, + ) + .await + { Ok(rpc_client) => rpc_client, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; diff --git a/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs b/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs index e0e77e50d..bc4d9b70d 100644 --- a/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs +++ b/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs @@ -14,7 +14,7 @@ pub async fn get_ether_account_data( request_id: RequestId, Query(req_params): Query, ) -> impl Responder { - let rpc_client = match api_context::build_rpc_client(&state, req_params.slot).await { + let rpc_client = match api_context::build_rpc_client(&state, req_params.slot, None).await { Ok(rpc_client) => rpc_client, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; diff --git a/evm_loader/api/src/api_server/handlers/get_storage_at.rs b/evm_loader/api/src/api_server/handlers/get_storage_at.rs index c19d0046a..7e3d36d2a 100644 --- a/evm_loader/api/src/api_server/handlers/get_storage_at.rs +++ b/evm_loader/api/src/api_server/handlers/get_storage_at.rs @@ -17,7 +17,7 @@ pub async fn get_storage_at( request_id: RequestId, Query(req_params): Query, ) -> impl Responder { - let rpc_client = match api_context::build_rpc_client(&state, req_params.slot).await { + let rpc_client = match api_context::build_rpc_client(&state, req_params.slot, None).await { Ok(rpc_client) => rpc_client, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; diff --git a/evm_loader/api/src/api_server/handlers/trace.rs b/evm_loader/api/src/api_server/handlers/trace.rs index d53d552de..1a707b8b5 100644 --- a/evm_loader/api/src/api_server/handlers/trace.rs +++ b/evm_loader/api/src/api_server/handlers/trace.rs @@ -19,11 +19,16 @@ pub async fn trace( ) -> impl Responder { let tx = trace_request.emulate_request.tx_params.into(); - let rpc_client = - match api_context::build_rpc_client(&state, trace_request.emulate_request.slot).await { - Ok(rpc_client) => rpc_client, - Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), - }; + let rpc_client = match api_context::build_rpc_client( + &state, + trace_request.emulate_request.slot, + trace_request.emulate_request.tx_index_in_block, + ) + .await + { + Ok(rpc_client) => rpc_client, + Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), + }; let context = Context::new(&*rpc_client, &state.config); diff --git a/evm_loader/cli/src/main.rs b/evm_loader/cli/src/main.rs index 615ce4419..333ab0e73 100644 --- a/evm_loader/cli/src/main.rs +++ b/evm_loader/cli/src/main.rs @@ -59,6 +59,7 @@ async fn run<'a>(options: &'a ArgMatches<'a>) -> NeonCliResult { CallDbClient::new( TracerDb::new(config.db_config.as_ref().expect("db-config not found")), slot, + None, ) .await?, ) diff --git a/evm_loader/lib/src/rpc/db_call_client.rs b/evm_loader/lib/src/rpc/db_call_client.rs index 29a972f41..aa3e9ab74 100644 --- a/evm_loader/lib/src/rpc/db_call_client.rs +++ b/evm_loader/lib/src/rpc/db_call_client.rs @@ -24,11 +24,16 @@ use std::any::Any; pub struct CallDbClient { tracer_db: TracerDb, - pub slot: u64, + slot: u64, + tx_index_in_block: Option, } impl CallDbClient { - pub async fn new(tracer_db: TracerDb, slot: u64) -> Result { + pub async fn new( + tracer_db: TracerDb, + slot: u64, + tx_index_in_block: Option, + ) -> Result { let earliest_rooted_slot = tracer_db .get_earliest_rooted_slot() .await @@ -37,7 +42,11 @@ impl CallDbClient { return Err(NeonError::EarlySlot(slot, earliest_rooted_slot)); } - Ok(Self { tracer_db, slot }) + Ok(Self { + tracer_db, + slot, + tx_index_in_block, + }) } } @@ -60,7 +69,7 @@ impl Rpc for CallDbClient { async fn get_account(&self, key: &Pubkey) -> ClientResult { self.tracer_db - .get_account_at(key, self.slot) + .get_account_at(key, self.slot, self.tx_index_in_block) .await .map_err(|e| e!("load account error", key, e))? .ok_or_else(|| e!("account not found", key)) @@ -73,7 +82,7 @@ impl Rpc for CallDbClient { ) -> RpcResult> { let account = self .tracer_db - .get_account_at(key, self.slot) + .get_account_at(key, self.slot, self.tx_index_in_block) .await .map_err(|e| e!("load account error", key, e))?; @@ -95,7 +104,7 @@ impl Rpc for CallDbClient { for key in pubkeys { let account = self .tracer_db - .get_account_at(key, self.slot) + .get_account_at(key, self.slot, self.tx_index_in_block) .await .map_err(|e| e!("load account error", key, e))?; result.push(account); diff --git a/evm_loader/lib/src/types/request_models.rs b/evm_loader/lib/src/types/request_models.rs index a1f3b180e..54cdb2db9 100644 --- a/evm_loader/lib/src/types/request_models.rs +++ b/evm_loader/lib/src/types/request_models.rs @@ -102,6 +102,7 @@ pub struct EmulateRequestModel { #[serde(flatten)] pub emulation_params: EmulationParamsRequestModel, pub slot: Option, + pub tx_index_in_block: Option, } #[derive(Deserialize, Serialize, Debug, Default)] diff --git a/evm_loader/lib/src/types/tracer_ch_db.rs b/evm_loader/lib/src/types/tracer_ch_db.rs index f60cf9c2b..81851ac7f 100644 --- a/evm_loader/lib/src/types/tracer_ch_db.rs +++ b/evm_loader/lib/src/types/tracer_ch_db.rs @@ -9,7 +9,7 @@ use super::{ }; use clickhouse::Client; -use log::{debug, info}; +use log::{debug, error, info}; use rand::Rng; use solana_sdk::{ account::Account, @@ -220,11 +220,32 @@ impl ClickHouseDb { Ok(slot_opt) } - #[allow(clippy::too_many_lines)] - pub async fn get_account_at(&self, pubkey: &Pubkey, slot: u64) -> ChResult> { - info!("get_account_at {{ pubkey: {pubkey}, slot: {slot} }}"); + pub async fn get_account_at( + &self, + pubkey: &Pubkey, + slot: u64, + tx_index_in_block: Option, + ) -> ChResult> { + if let Some(tx_index_in_block) = tx_index_in_block { + if let Some(account) = self + .get_account_at_index_in_block(pubkey, slot, tx_index_in_block) + .await? + { + return Ok(Some(account)); + } + } + + self.get_account_at_slot(pubkey, slot).await + } + + async fn get_account_at_slot( + &self, + pubkey: &Pubkey, + slot: u64, + ) -> Result, ChError> { + info!("get_account_at_slot {{ pubkey: {pubkey}, slot: {slot} }}"); let (first, mut branch) = self.get_branch_slots(Some(slot)).await.map_err(|e| { - println!("get_branch_slots error: {:?}", e); + error!("get_branch_slots error: {:?}", e); e })?; @@ -234,7 +255,7 @@ impl ClickHouseDb { .get_account_rooted_slot(&pubkey_str, first) .await .map_err(|e| { - println!("get_account_rooted_slot error: {:?}", e); + error!("get_account_rooted_slot error: {:?}", e); e })? { @@ -263,12 +284,12 @@ impl ClickHouseDb { .await, ) .map_err(|e| { - println!("get_account_at error: {e}"); + error!("get_account_at_slot error: {e}"); ChError::Db(e) })?; let execution_time = Instant::now().duration_since(time_start); info!( - "get_account_at {{ pubkey: {pubkey}, slot: {slot} }} sql(1) returned {row:?}, time: {} sec", + "get_account_at_slot {{ pubkey: {pubkey}, slot: {slot} }} sql(1) returned {row:?}, time: {} sec", execution_time.as_secs_f64() ); @@ -285,19 +306,64 @@ impl ClickHouseDb { ); } - let result = if let Some(acc) = row { - acc.try_into() - .map(Some) - .map_err(|err| ChError::Db(clickhouse::error::Error::Custom(err))) - } else { - Ok(None) - }; + let result = row + .map(|a| a.try_into()) + .transpose() + .map_err(|e| ChError::Db(clickhouse::error::Error::Custom(e))); - info!("get_account_at {{ pubkey: {pubkey}, slot: {slot} }} -> {result:?}"); + info!("get_account_at_slot {{ pubkey: {pubkey}, slot: {slot} }} -> {result:?}"); result } + async fn get_account_at_index_in_block( + &self, + pubkey: &Pubkey, + slot: u64, + tx_index_in_block: u64, + ) -> ChResult> { + info!( + "get_account_at_index_in_block {{ pubkey: {pubkey}, slot: {slot}, tx_index_in_block: {tx_index_in_block} }}" + ); + + let query = r#" + SELECT owner, lamports, executable, rent_epoch, data, txn_signature + FROM events.update_account_distributed + WHERE pubkey = ? + AND slot = ? + AND write_version <= ? + ORDER BY write_version DESC + LIMIT 1 + "#; + + let time_start = Instant::now(); + + let account = Self::row_opt( + self.client + .query(query) + .bind(format!("{:?}", pubkey.to_bytes())) + .bind(slot) + .bind(tx_index_in_block) + .fetch_one::() + .await, + ) + .map_err(|e| { + error!("get_account_at_index_in_block error: {e}"); + ChError::Db(e) + })? + .map(|a| a.try_into()) + .transpose() + .map_err(|e| ChError::Db(clickhouse::error::Error::Custom(e)))?; + + let execution_time = Instant::now().duration_since(time_start); + info!( + "get_account_at_index_in_block {{ pubkey: {pubkey}, slot: {slot}, tx_index_in_block: {tx_index_in_block} }} sql(1) returned {account:?}, time: {} sec", + execution_time.as_secs_f64() + ); + + Ok(account) + } + async fn get_older_account_row_at( &self, pubkey: &str, @@ -470,7 +536,7 @@ impl ClickHouseDb { // If not found, get closest account state in one of previous slots if let Some(parent) = slot.parent { - self.get_account_at(pubkey, parent).await + self.get_account_at(pubkey, parent, None).await } else { Ok(None) } From 00b1466f162a43d1b843c30f680c107c86e22e24 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Tue, 17 Oct 2023 12:44:50 +0300 Subject: [PATCH 044/318] NDEV-2321: Upgrade Solana to v1.16.17 (#217) --- .github/workflows/deploy.py | 4 +- evm_loader/Cargo.lock | 152 +++++++++++++++++----------------- evm_loader/api/Cargo.toml | 4 +- evm_loader/cli/Cargo.toml | 8 +- evm_loader/lib/Cargo.toml | 12 +-- evm_loader/program/Cargo.toml | 2 +- 6 files changed, 91 insertions(+), 91 deletions(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index 85ab8d573..65edb8c3d 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -30,8 +30,8 @@ DOCKER_USER = os.environ.get("DHUBU") DOCKER_PASSWORD = os.environ.get("DHUBP") IMAGE_NAME = 'neonlabsorg/evm_loader' -SOLANA_NODE_VERSION = 'v1.16.16' -SOLANA_BPF_VERSION = 'v1.16.16' +SOLANA_NODE_VERSION = 'v1.16.17' +SOLANA_BPF_VERSION = 'v1.16.17' VERSION_BRANCH_TEMPLATE = r"[vt]{1}\d{1,2}\.\d{1,2}\.x.*" docker_client = docker.APIClient() diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 158ce6b22..6787d170d 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -2724,8 +2724,8 @@ dependencies = [ "num-traits", "shank", "solana-program", - "spl-associated-token-account 1.1.3", - "spl-token 3.5.0", + "spl-associated-token-account 2.2.0", + "spl-token 4.0.0", "thiserror", ] @@ -4266,9 +4266,9 @@ dependencies = [ [[package]] name = "solana-account-decoder" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52aec62a85932e26d1085864b0f7b99b31934aec8dd132429bfef6d7fb1d3a6" +checksum = "121e55656c2094950f374247e1303dd09517f1ed49c91bf60bf114760b286eb4" dependencies = [ "Inflector", "base64 0.21.4", @@ -4291,9 +4291,9 @@ dependencies = [ [[package]] name = "solana-address-lookup-table-program" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee0bd25f4ba0a15fc16c57b41b1e1b14f5271b83214fda158fdedb58758d394e" +checksum = "3ccb31f7f14d5876acd9ec38f5bf6097bfb4b350141d81c7ff2bf684db3ca815" dependencies = [ "bincode", "bytemuck", @@ -4312,9 +4312,9 @@ dependencies = [ [[package]] name = "solana-bpf-loader-program" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05fb3284ae3a51bd173c7f61fcd9d6c1a10cfe46b082ce3189dec9f86120c245" +checksum = "6302bcae9ca7cddffc5af54c9407abbbb14b94539300aca01d879a3f23379f42" dependencies = [ "bincode", "byteorder", @@ -4331,9 +4331,9 @@ dependencies = [ [[package]] name = "solana-clap-utils" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e963043668c640183d48472b281ebb9f713e0c36df0271961d23e6a394e09070" +checksum = "47a8150d4ff694d9587496a5976d33e6ebdb16cc61c6338bdfe3b2fc2c7c4986" dependencies = [ "chrono", "clap 2.34.0", @@ -4349,9 +4349,9 @@ dependencies = [ [[package]] name = "solana-cli" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f30e53107537d92eed3a0f933905b3d5cc4c224d29df89460f971a58de8bf0c" +checksum = "2b209b925e75e6080f019ed44d134ec9d687eede1156641e1723e808f2a62dec" dependencies = [ "bincode", "bs58", @@ -4400,9 +4400,9 @@ dependencies = [ [[package]] name = "solana-cli-config" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "febecf05517593d6da0592fc6039b069e659a1e062b114eeaf4c22d44293b2db" +checksum = "6017eea88d739fae5f6f4f3f2779a68ad16cadf2f714baccad9714400cf93460" dependencies = [ "dirs-next", "lazy_static", @@ -4416,9 +4416,9 @@ dependencies = [ [[package]] name = "solana-cli-output" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "864c328349439ea0f451d722d804392741b66a7237d05cd69dea0bb23d74f5cb" +checksum = "e049558c43fc0c9e8faf5d6aba3d4c56d0491c139f55427be4a9c5f26aec6a78" dependencies = [ "Inflector", "base64 0.21.4", @@ -4443,9 +4443,9 @@ dependencies = [ [[package]] name = "solana-client" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ccf7bb34fb81c74582a9011babaa2e0220da56c71186e77f45a6f352017fdb" +checksum = "35d7582847ab4d60652ff640ca574647789461c1630e8c7580ff770738c3d7f4" dependencies = [ "async-trait", "bincode", @@ -4476,9 +4476,9 @@ dependencies = [ [[package]] name = "solana-config-program" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fd0fc1efb91a1661aeb1ff6a691156c3b1bffdaed0aa096589499dd83f9e50b" +checksum = "94dc0f4463daf1c6155f20eac948ea4ced705e5f5520546aef4e11e746a6d95d" dependencies = [ "bincode", "chrono", @@ -4490,9 +4490,9 @@ dependencies = [ [[package]] name = "solana-connection-cache" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8759e9cb9b1e92a94c31812169ecb5e65b5e215fb70fb68691e03655de5b7b6c" +checksum = "758587d44e05a4abdf82b9514d1c8b7d35637ad65f7af7c3e3e02417aaae3c9e" dependencies = [ "async-trait", "bincode", @@ -4511,9 +4511,9 @@ dependencies = [ [[package]] name = "solana-faucet" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f24d2bd1a6f5834700d6bbef9abfebad37dd31a11156867bb5bb39b635f2a7f6" +checksum = "e0b7dfac6dd9a1cd3829fc230ed348f4972934800d754db73e2b434c16dafafd" dependencies = [ "bincode", "byteorder", @@ -4535,9 +4535,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02eb4f0ed3eade20f4abdcc0031167344237cd6e16808bd0f33945f9db7861fe" +checksum = "d266bf0311bb403d31206aa2904b8741f57c7f5e27580b6810ad5e22fc7c3282" dependencies = [ "ahash 0.8.3", "blake3", @@ -4568,9 +4568,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi-macro" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28514761a285944cbad5b3d7930546369b80a713ba37d84bcf6ed2753611765" +checksum = "6dfe18c5155015dcb494c6de84a03b725fcf90ec2006a047769018b94c2cf0de" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", @@ -4580,9 +4580,9 @@ dependencies = [ [[package]] name = "solana-logger" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c310c6749435ce1ea25a9ae3edfb2fd2c2aed2aa4d4f7e0487a8077a0b1ee30" +checksum = "4f76fe25c2d06dcf621befd1e8d5655143e8a059c7e20fcb71736bc80ed779d6" dependencies = [ "env_logger", "lazy_static", @@ -4591,9 +4591,9 @@ dependencies = [ [[package]] name = "solana-measure" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d171357580e62aa4ca19c780e25f4e74de064e2780cb8b9f6b6901d986fcd23" +checksum = "db165b8a7f5d840abef011c78a18ffe63cad9192d676b07d94f469b6b5dc6cf6" dependencies = [ "log", "solana-sdk", @@ -4601,9 +4601,9 @@ dependencies = [ [[package]] name = "solana-metrics" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "013cbb3c82588278d2be18d3317ece5286cb54a3a06d5d38fc31e2a76a6d5e2d" +checksum = "aa01731bb3952904962d49a1ea1205db54e93f3a56f4006d32e02a7c85d60546" dependencies = [ "crossbeam-channel", "gethostname", @@ -4615,9 +4615,9 @@ dependencies = [ [[package]] name = "solana-net-utils" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50d7cac0694b1fe07499de25404a0c7d6836457e359aba3b08c3983c3dc5eb6" +checksum = "fd7ab67329dcebe4a40673fd0da27373282b1359ec7945e0fb81a9c594bcd057" dependencies = [ "bincode", "clap 3.2.23", @@ -4637,9 +4637,9 @@ dependencies = [ [[package]] name = "solana-perf" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395d559e5be2c439551298e9fa95561807f24921fd9a1e08bb82a3dc05c02dea" +checksum = "f900c1015844087cd4f10ba9d2d26a9859f2f5ca07427865cc74942595abc0a7" dependencies = [ "ahash 0.8.3", "bincode", @@ -4664,9 +4664,9 @@ dependencies = [ [[package]] name = "solana-program" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff2aa5434a77413e9d43e971ceb47bdb003f2e8bbc0365a25b684aca2605c25" +checksum = "1bb16998986492de307eef503ce47e84503d35baa92dc60832b22476948b1c16" dependencies = [ "ark-bn254", "ark-ec", @@ -4719,9 +4719,9 @@ dependencies = [ [[package]] name = "solana-program-runtime" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1832fefc2187142dac169812518ec20da68b09abad86e4a78f8ae1787e4f56" +checksum = "036d6ecf67a3a7c6dc74d4f7fa6ab321e7ce8feccb7c9dff8384a41d0a12345b" dependencies = [ "base64 0.21.4", "bincode", @@ -4747,9 +4747,9 @@ dependencies = [ [[package]] name = "solana-pubsub-client" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89388addbc3192407d948634f82c95c4dbe1efbe578582abfd136720e059556e" +checksum = "70e318f46bedb39374e98f299266a155b2c81c9d920f3c90f761261267c275c1" dependencies = [ "crossbeam-channel", "futures-util", @@ -4772,9 +4772,9 @@ dependencies = [ [[package]] name = "solana-quic-client" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7897b876a6df2d97b3a5ddfd764155c0591e3497e863fd7fdf32b54de4e2644" +checksum = "61db18a804642f8eb37369e903774a85d7949a55bd204ec090ebe0742fd2fe32" dependencies = [ "async-mutex", "async-trait", @@ -4800,9 +4800,9 @@ dependencies = [ [[package]] name = "solana-rayon-threadlimit" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba17a930f9974a17a9a6c6e82e7f89b40127e9cc0f9c17cfc29fc5b149d2c38" +checksum = "805377478f2d413f6cfcba6924c81ac4988ac0f96cdb045a8a9d81c430e6622a" dependencies = [ "lazy_static", "num_cpus", @@ -4810,9 +4810,9 @@ dependencies = [ [[package]] name = "solana-remote-wallet" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80fb35e3fa78ef1d08a6a1d852e2c357e6ae388cb307d24fad359f57c34429f0" +checksum = "7a1148dcd76f76ad0399c1d9abf05cb32a0e545c5bee47ebe6d3b3e800c7fa7c" dependencies = [ "console", "dialoguer", @@ -4830,9 +4830,9 @@ dependencies = [ [[package]] name = "solana-rpc-client" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c512944689d747a87f76936c89bb59f5be6c9a3189631857f49746cfa47d5bd1" +checksum = "dc51a85c6ff03bb4a3e1fde1e36dcb553b990f2b3e66aed941a31a6a7c20fa33" dependencies = [ "async-trait", "base64 0.21.4", @@ -4856,9 +4856,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-api" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918b75f8ac4c358a6b512bf8b7dafc8166ddcb52ded5164c6235e0693ccb09" +checksum = "6756a1f89f509154644a958869c7cc6c70cc622f44faddf9b94612d8d2d8eed5" dependencies = [ "base64 0.21.4", "bs58", @@ -4878,9 +4878,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-nonce-utils" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6e360ea2f3a756bdf6256c1f6ef13f8b01b5d2a7855b4f16cafb4a4017f0557" +checksum = "4850e8db607525a36d330f073703e78e908a54ac66aa323a44cfc12c14c16699" dependencies = [ "clap 2.34.0", "solana-clap-utils", @@ -4891,9 +4891,9 @@ dependencies = [ [[package]] name = "solana-sdk" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1002048941cedbd7dd6a96fdaa3dc5238b998aaa70b81946b1e3ec108cc2be" +checksum = "4106cda3d10833ba957dbd25fb841b50aeca7480ccf8f54859294716f54bcd4b" dependencies = [ "assert_matches", "base64 0.21.4", @@ -4944,9 +4944,9 @@ dependencies = [ [[package]] name = "solana-sdk-macro" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b41b63b2da4a37ce323aba108db21f4c7bfa638dd1bf58fdc870f83bdce48ba" +checksum = "1e560806a3859717eb2220b26e2cd68bb757b63affa3e79c3f1d8d853b5ee78f" dependencies = [ "bs58", "proc-macro2 1.0.66", @@ -4957,9 +4957,9 @@ dependencies = [ [[package]] name = "solana-streamer" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f00e575f2bd5ae2776870fbd1d7379d4ad392c015e2a4e2a328953b821a9d36d" +checksum = "78f142cbb497d257e70253c158a4c34037e310d24a055fae7dbc5c396b7611aa" dependencies = [ "async-channel", "bytes", @@ -4990,9 +4990,9 @@ dependencies = [ [[package]] name = "solana-thin-client" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df328e2624cce68c9949a53eac317a264eceb997131cb9bd22175698a5f5dc74" +checksum = "e0e41ce715b34749d2c0d3181dd910d2b99fa2142a0aaf3cd44926cb02edd60d" dependencies = [ "bincode", "log", @@ -5005,9 +5005,9 @@ dependencies = [ [[package]] name = "solana-tpu-client" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8ce6fe221c0e1fd8aa3078b8fcb0cc3f4c27942f1256b57a60608d81ae5348" +checksum = "84ec99361a39e17a2bffe2a59b97b3d20ddef323f9166929783ce49f340c200d" dependencies = [ "async-trait", "bincode", @@ -5030,9 +5030,9 @@ dependencies = [ [[package]] name = "solana-transaction-status" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db0b811793e78a908119cc02edca3ff8b54d5660104ebd06cc0e2e7e2f66900b" +checksum = "236dd4e43b8a7402bce250228e04c0c68d9493a3e19c71b377ccc7c4390fd969" dependencies = [ "Inflector", "base64 0.21.4", @@ -5056,9 +5056,9 @@ dependencies = [ [[package]] name = "solana-udp-client" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897ff303a15ba956e80573dee4cf96d94d41a69adc5362898b98851e347505ad" +checksum = "16b438036719e5c1201aba2336a5dc1caa8c8eefafd7110b7a3818ae199b54da" dependencies = [ "async-trait", "solana-connection-cache", @@ -5071,9 +5071,9 @@ dependencies = [ [[package]] name = "solana-version" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9513754d3b2203a0e1045a211c5d68e72e4ed135e477344c21d096897fd2bf70" +checksum = "62847d7ef409e3b410f65e726bf7816d8f8d0330918e78537e940bdf1ca061ae" dependencies = [ "log", "rustc_version", @@ -5087,9 +5087,9 @@ dependencies = [ [[package]] name = "solana-vote-program" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b6bfc5302ce0383eb129aa3a916705a20d22c4ad448144ef684b7b028d4053f" +checksum = "fb0c3e5ee7bd03b249c6b80eead5620af62bc7ef1af8ea4f499b8054b00e9c7d" dependencies = [ "bincode", "log", @@ -5109,9 +5109,9 @@ dependencies = [ [[package]] name = "solana-zk-token-sdk" -version = "1.16.16" +version = "1.16.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d1fe77918563768a65fd5d6cd2fa06cf0aeb11e529a1ef8c230b0fe018600e3" +checksum = "278c08e13bc04b6940997602909052524a375154b00cf0bfa934359a3bb7e6f0" dependencies = [ "aes-gcm-siv", "base64 0.21.4", diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index c116aefb6..9613951de 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -8,8 +8,8 @@ edition = "2021" [dependencies] clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } -solana-sdk = "=1.16.16" -solana-client = "=1.16.16" +solana-sdk = "=1.16.17" +solana-client = "=1.16.17" serde = "1.0.186" serde_json = { version = "1.0.107", features = ["preserve_order"] } ethnum = { version = "1.4", default-features = false, features = ["serde"] } diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index 63585f473..e7b671d96 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -8,10 +8,10 @@ edition = "2021" [dependencies] clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } -solana-sdk = "=1.16.16" -solana-client = "=1.16.16" -solana-clap-utils = "=1.16.16" -solana-cli-config = "=1.16.16" +solana-sdk = "=1.16.17" +solana-client = "=1.16.17" +solana-clap-utils = "=1.16.17" +solana-cli-config = "=1.16.17" hex = "0.4.2" serde = "1.0.186" serde_json = { version = "1.0.107", features = ["preserve_order"] } diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 5dcf73d02..cb3d166e6 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -10,12 +10,12 @@ thiserror = "1.0" anyhow = "1.0" bincode = "1.3.1" evm-loader = { path = "../program", default-features = false, features = ["log", "async-trait", "serde_json"] } -solana-sdk = "=1.16.16" -solana-client = "=1.16.16" -solana-clap-utils = "=1.16.16" -solana-cli-config = "=1.16.16" -solana-cli = "=1.16.16" -solana-transaction-status = "=1.16.16" +solana-sdk = "=1.16.17" +solana-client = "=1.16.17" +solana-clap-utils = "=1.16.17" +solana-cli-config = "=1.16.17" +solana-cli = "=1.16.17" +solana-transaction-status = "=1.16.17" spl-token = { version = "~3.5", default-features = false, features = ["no-entrypoint"] } spl-associated-token-account = { version = "~1.1", default-features = false, features = ["no-entrypoint"] } bs58 = "0.4.0" diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 159ef55a6..34fea24d7 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -37,7 +37,7 @@ default = ["custom-heap"] [dependencies] linked_list_allocator = { version = "0.10", default-features = false } evm-loader-macro = { path = "../program-macro" } -solana-program = { version = "=1.16.16", default-features = false } +solana-program = { version = "=1.16.17", default-features = false } spl-token = { version = "~3.5", default-features = false, features = ["no-entrypoint"] } spl-associated-token-account = { version = "~1.1", default-features = false, features = ["no-entrypoint"] } mpl-token-metadata = { version = "1.13.2", default-features = false, features = ["no-entrypoint"] } From 63226c399763af49eb27828b7d17f51c16d432e1 Mon Sep 17 00:00:00 2001 From: Dmitry Miroshnichenko Date: Thu, 26 Oct 2023 18:22:58 +0300 Subject: [PATCH 045/318] DOPS-420 workflow change for neonevm/neon-evm repository (#224) * DOPS-420 image name variable added * DOPS-420 workflow changed - added variable with githab organisation and repo name for run link - hardcoded proxy repo url changed to variable * DOPS-420 github api script fix added os lib --- .github/workflows/deploy.py | 5 +++-- .github/workflows/github_api_client.py | 3 ++- .github/workflows/pipeline.yml | 3 +++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index 65edb8c3d..d9d5b9298 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -29,7 +29,8 @@ DOCKER_USER = os.environ.get("DHUBU") DOCKER_PASSWORD = os.environ.get("DHUBP") -IMAGE_NAME = 'neonlabsorg/evm_loader' +IMAGE_NAME = os.environ.get("IMAGE_NAME") +RUN_LINK_REPO = os.environ.get("RUN_LINK_REPO") SOLANA_NODE_VERSION = 'v1.16.17' SOLANA_BPF_VERSION = 'v1.16.17' @@ -199,7 +200,7 @@ def trigger_proxy_action(head_ref_branch, base_ref_branch, github_ref, github_sh runs_after = github.get_proxy_runs_list(proxy_branch) proxy_run_id = list(set(runs_after) - set(runs_before))[0] - link = f"https://github.com/neonlabsorg/proxy-model.py/actions/runs/{proxy_run_id}" + link = f"https://github.com/{RUN_LINK_REPO}/actions/runs/{proxy_run_id}" click.echo(f"Proxy run link: {link}") click.echo("Waiting for completed status...") wait_condition(lambda: github.get_proxy_run_info(proxy_run_id)["status"] == "completed", timeout_sec=10800, delay=5) diff --git a/.github/workflows/github_api_client.py b/.github/workflows/github_api_client.py index dc5e519b7..e29dddd29 100644 --- a/.github/workflows/github_api_client.py +++ b/.github/workflows/github_api_client.py @@ -1,9 +1,10 @@ import click import requests +import os class GithubClient(): - PROXY_ENDPOINT = "https://api.github.com/repos/neonlabsorg/proxy-model.py" + PROXY_ENDPOINT = os.environ.get("PROXY_ENDPOINT") def __init__(self, token): self.headers = {"Authorization": f"Bearer {token}", diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index 3ee1e4ae4..c46a959e0 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -13,6 +13,9 @@ on: env: DHUBU: ${{secrets.DHUBU}} DHUBP: ${{secrets.DHUBP}} + IMAGE_NAME: ${{vars.IMAGE_NAME}} + PROXY_ENDPOINT: ${{vars.PROXY_ENDPOINT}} + RUN_LINK_REPO: ${{vars.RUN_LINK_REPO}} BUILD_URL: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" concurrency: From f02f377a631c7e4b48171e585cc374604012f492 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Thu, 9 Nov 2023 11:12:16 +0200 Subject: [PATCH 046/318] Multiple bug fixes: NDEV-2330, NDEV-2343, NDEV-2344, NDEV-2345 (#220) * NDEV-2330: Fix off-by-one error in get_account_at(slot, tx_index) * NDEV-2343: Pass gas_price from tracer to neon-api * NDEV-2344: Remove unused debug methods code * NDEV-2345: Add account overrides logic to code_hash --- evm_loader/cli/src/main.rs | 3 + evm_loader/lib/src/account_storage.rs | 34 ++++----- evm_loader/lib/src/commands/emulate.rs | 4 +- evm_loader/lib/src/commands/trace.rs | 85 +--------------------- evm_loader/lib/src/types/mod.rs | 1 + evm_loader/lib/src/types/request_models.rs | 2 + evm_loader/lib/src/types/tracer_ch_db.rs | 8 +- 7 files changed, 33 insertions(+), 104 deletions(-) diff --git a/evm_loader/cli/src/main.rs b/evm_loader/cli/src/main.rs index 333ab0e73..e810915f2 100644 --- a/evm_loader/cli/src/main.rs +++ b/evm_loader/cli/src/main.rs @@ -268,6 +268,8 @@ fn parse_tx(params: &ArgMatches) -> (TxParams, TraceCallConfig) { let gas_limit = u256_of(params, "gas_limit"); + let gas_price = u256_of(params, "gas_price"); + let access_list = access_list_of(params, "access_list"); let tx_params = TxParams { @@ -277,6 +279,7 @@ fn parse_tx(params: &ArgMatches) -> (TxParams, TraceCallConfig) { data, value, gas_limit, + gas_price, access_list, }; diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index 9467cd9b9..c3cbd59a6 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -6,6 +6,7 @@ use ethnum::U256; use evm_loader::account::ether_contract; use evm_loader::account_storage::{find_slot_hash, AccountOperation, AccountsOperations}; use evm_loader::evm::tracing::{AccountOverrides, BlockOverrides}; +use evm_loader::evm::Buffer; use evm_loader::{ account::{ ether_storage::EthereumStorageAddress, EthereumAccount, EthereumStorage, @@ -479,6 +480,19 @@ impl<'a> EmulatorAccountStorage<'a> { default } } + + async fn get_code(&self, address: &Address) -> Buffer { + self.ethereum_contract_map_or(address, Buffer::empty(), |c| { + self.state_overrides + .as_ref() + .and_then(|account_overrides| account_overrides.get(address)?.code.as_ref()) + .map_or_else( + || Buffer::from_slice(&c.code()), + |code| Buffer::from_slice(&code.0), + ) + }) + .await + } } #[async_trait(?Send)] @@ -569,27 +583,13 @@ impl<'a> AccountStorage for EmulatorAccountStorage<'a> { } // return empty hash(&[]) as a default value, or code's hash if contract exists - self.ethereum_contract_map_or(address, hash(&[]).to_bytes(), |c| { - hash(&c.code()).to_bytes() - }) - .await + hash(self.get_code(address).await.as_ref()).to_bytes() } - async fn code(&self, address: &Address) -> evm_loader::evm::Buffer { - use evm_loader::evm::Buffer; - + async fn code(&self, address: &Address) -> Buffer { info!("code {address}"); - self.ethereum_contract_map_or(address, Buffer::empty(), |c| { - self.state_overrides - .as_ref() - .and_then(|account_overrides| account_overrides.get(address)?.code.as_ref()) - .map_or_else( - || Buffer::from_slice(&c.code()), - |code| Buffer::from_slice(&code.0), - ) - }) - .await + self.get_code(address).await } async fn generation(&self, address: &Address) -> u32 { diff --git a/evm_loader/lib/src/commands/emulate.rs b/evm_loader/lib/src/commands/emulate.rs index 140f0c6bf..79e2c6ffc 100644 --- a/evm_loader/lib/src/commands/emulate.rs +++ b/evm_loader/lib/src/commands/emulate.rs @@ -222,7 +222,7 @@ pub(crate) async fn emulate_trx<'a>( Some(nonce) => nonce, None => storage.nonce(&tx_params.from).await, }, - gas_price: U256::ZERO, + gas_price: tx_params.gas_price.unwrap_or_default(), gas_limit: tx_params.gas_limit.unwrap_or(U256::MAX), target: tx_params.to, value: tx_params.value.unwrap_or_default(), @@ -239,7 +239,7 @@ pub(crate) async fn emulate_trx<'a>( Some(nonce) => nonce, None => storage.nonce(&tx_params.from).await, }, - gas_price: U256::ZERO, + gas_price: tx_params.gas_price.unwrap_or_default(), gas_limit: tx_params.gas_limit.unwrap_or(U256::MAX), target: tx_params.to, value: tx_params.value.unwrap_or_default(), diff --git a/evm_loader/lib/src/commands/trace.rs b/evm_loader/lib/src/commands/trace.rs index 50a5979ad..39aa1a680 100644 --- a/evm_loader/lib/src/commands/trace.rs +++ b/evm_loader/lib/src/commands/trace.rs @@ -1,21 +1,12 @@ -use std::fmt::{Display, Formatter}; -use std::rc::Rc; - -use serde::{Deserialize, Serialize}; use serde_json::Value; use solana_sdk::{commitment_config::CommitmentConfig, pubkey::Pubkey}; +use std::rc::Rc; use evm_loader::evm::tracing::tracers::new_tracer; -use evm_loader::evm::tracing::{TraceCallConfig, TraceConfig}; +use evm_loader::evm::tracing::TraceCallConfig; use evm_loader::types::Address; -use crate::{ - account_storage::EmulatorAccountStorage, - commands::emulate::{emulate_transaction, emulate_trx, setup_syscall_stubs}, - errors::NeonError, - rpc::Rpc, - types::TxParams, -}; +use crate::{commands::emulate::emulate_transaction, errors::NeonError, rpc::Rpc, types::TxParams}; #[allow(clippy::too_many_arguments)] pub async fn trace_transaction( @@ -53,73 +44,3 @@ pub async fn trace_transaction( .into_inner() .into_traces(emulation_result)) } - -#[derive(Serialize, Deserialize)] -pub struct TraceBlockReturn(pub Vec); - -impl Display for TraceBlockReturn { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{{ traced call(s): {} }}", self.0.len()) - } -} - -#[allow(clippy::too_many_arguments)] -pub async fn trace_block( - rpc_client: &dyn Rpc, - evm_loader: Pubkey, - transactions: Vec, - token: Pubkey, - chain_id: u64, - steps: u64, - commitment: CommitmentConfig, - accounts: &[Address], - solana_accounts: &[Pubkey], - trace_config: &TraceConfig, -) -> Result { - setup_syscall_stubs(rpc_client).await?; - - let storage = EmulatorAccountStorage::with_accounts( - rpc_client, - evm_loader, - token, - chain_id, - commitment, - accounts, - solana_accounts, - &None, - None, - ) - .await?; - - let mut results = vec![]; - for tx_params in transactions { - let result = trace_trx(tx_params, &storage, chain_id, steps, trace_config).await?; - results.push(result); - } - - Ok(TraceBlockReturn(results)) -} - -async fn trace_trx<'a>( - tx_params: TxParams, - storage: &'a EmulatorAccountStorage<'a>, - chain_id: u64, - steps: u64, - trace_config: &TraceConfig, -) -> Result { - let tracer = new_tracer(trace_config)?; - - let emulation_result = emulate_trx( - tx_params, - storage, - chain_id, - steps, - Some(Rc::clone(&tracer)), - ) - .await?; - - Ok(Rc::try_unwrap(tracer) - .expect("There is must be only one reference") - .into_inner() - .into_traces(emulation_result)) -} diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index 6cc2322b3..0f8875b91 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -35,6 +35,7 @@ pub struct TxParams { pub data: Option>, pub value: Option, pub gas_limit: Option, + pub gas_price: Option, pub access_list: Option>, } diff --git a/evm_loader/lib/src/types/request_models.rs b/evm_loader/lib/src/types/request_models.rs index 54cdb2db9..31b07648f 100644 --- a/evm_loader/lib/src/types/request_models.rs +++ b/evm_loader/lib/src/types/request_models.rs @@ -29,6 +29,7 @@ pub struct TxParamsRequestModel { pub data: Option>, pub value: Option, pub gas_limit: Option, + pub gas_price: Option, pub access_list: Option>, } @@ -59,6 +60,7 @@ impl From for TxParams { data: model.data, value: model.value, gas_limit: model.gas_limit, + gas_price: model.gas_price, access_list: model.access_list, } } diff --git a/evm_loader/lib/src/types/tracer_ch_db.rs b/evm_loader/lib/src/types/tracer_ch_db.rs index 81851ac7f..e4b9ff9df 100644 --- a/evm_loader/lib/src/types/tracer_ch_db.rs +++ b/evm_loader/lib/src/types/tracer_ch_db.rs @@ -227,12 +227,14 @@ impl ClickHouseDb { tx_index_in_block: Option, ) -> ChResult> { if let Some(tx_index_in_block) = tx_index_in_block { - if let Some(account) = self + return if let Some(account) = self .get_account_at_index_in_block(pubkey, slot, tx_index_in_block) .await? { - return Ok(Some(account)); - } + Ok(Some(account)) + } else { + self.get_account_at_slot(pubkey, slot - 1).await + }; } self.get_account_at_slot(pubkey, slot).await From c8755664dd6c7c4c8f220cfe3a05ef12feb7ed5a Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 10 Nov 2023 10:19:28 +0200 Subject: [PATCH 047/318] NDEV-2366: Update Solana dependencies to 1.16.18 (#228) --- .github/workflows/deploy.py | 4 +- evm_loader/Cargo.lock | 148 +++++++++++++++++----------------- evm_loader/api/Cargo.toml | 4 +- evm_loader/cli/Cargo.toml | 8 +- evm_loader/lib/Cargo.toml | 12 +-- evm_loader/program/Cargo.toml | 2 +- 6 files changed, 89 insertions(+), 89 deletions(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index d9d5b9298..63d8d1582 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -31,8 +31,8 @@ DOCKER_PASSWORD = os.environ.get("DHUBP") IMAGE_NAME = os.environ.get("IMAGE_NAME") RUN_LINK_REPO = os.environ.get("RUN_LINK_REPO") -SOLANA_NODE_VERSION = 'v1.16.17' -SOLANA_BPF_VERSION = 'v1.16.17' +SOLANA_NODE_VERSION = 'v1.16.18' +SOLANA_BPF_VERSION = 'v1.16.18' VERSION_BRANCH_TEMPLATE = r"[vt]{1}\d{1,2}\.\d{1,2}\.x.*" docker_client = docker.APIClient() diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 6787d170d..934a9fd7f 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -4266,9 +4266,9 @@ dependencies = [ [[package]] name = "solana-account-decoder" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121e55656c2094950f374247e1303dd09517f1ed49c91bf60bf114760b286eb4" +checksum = "83da6908b4865a9680c4fcb5e77d319467fdc5ab96a6ccc8361e7110ebcd206e" dependencies = [ "Inflector", "base64 0.21.4", @@ -4291,9 +4291,9 @@ dependencies = [ [[package]] name = "solana-address-lookup-table-program" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ccb31f7f14d5876acd9ec38f5bf6097bfb4b350141d81c7ff2bf684db3ca815" +checksum = "9102429e980b8e58f05e39a2aceb799fc1fd7b81e440bc70322854e0debb21dc" dependencies = [ "bincode", "bytemuck", @@ -4312,9 +4312,9 @@ dependencies = [ [[package]] name = "solana-bpf-loader-program" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6302bcae9ca7cddffc5af54c9407abbbb14b94539300aca01d879a3f23379f42" +checksum = "009b84c1ac3f6b9cb53a8f133c43efeaa4a6e8e46f9ddfa616f9d1f04c551a76" dependencies = [ "bincode", "byteorder", @@ -4331,9 +4331,9 @@ dependencies = [ [[package]] name = "solana-clap-utils" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47a8150d4ff694d9587496a5976d33e6ebdb16cc61c6338bdfe3b2fc2c7c4986" +checksum = "fe15843171a435eed014e7180f62c0d5e7e8178f7eaf4da0077ea21354506e2a" dependencies = [ "chrono", "clap 2.34.0", @@ -4349,9 +4349,9 @@ dependencies = [ [[package]] name = "solana-cli" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b209b925e75e6080f019ed44d134ec9d687eede1156641e1723e808f2a62dec" +checksum = "15d042a7d26b5c0152dbb2ab3dbbbf62ea13e238e3344fcd7d3790a4f6abd04f" dependencies = [ "bincode", "bs58", @@ -4400,9 +4400,9 @@ dependencies = [ [[package]] name = "solana-cli-config" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6017eea88d739fae5f6f4f3f2779a68ad16cadf2f714baccad9714400cf93460" +checksum = "6430afcc4444bd3b7b16b9314f0ae533344d0cd9bbbd160fb47cb45f9689a801" dependencies = [ "dirs-next", "lazy_static", @@ -4416,9 +4416,9 @@ dependencies = [ [[package]] name = "solana-cli-output" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e049558c43fc0c9e8faf5d6aba3d4c56d0491c139f55427be4a9c5f26aec6a78" +checksum = "88e1902f40e61a873317c3f296e56333bb52258ca717813990eac1ae8ba8670c" dependencies = [ "Inflector", "base64 0.21.4", @@ -4443,9 +4443,9 @@ dependencies = [ [[package]] name = "solana-client" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35d7582847ab4d60652ff640ca574647789461c1630e8c7580ff770738c3d7f4" +checksum = "38917c4655a42881fd2998c5c7626fa4cee9f95d5877592b347b213782782145" dependencies = [ "async-trait", "bincode", @@ -4476,9 +4476,9 @@ dependencies = [ [[package]] name = "solana-config-program" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94dc0f4463daf1c6155f20eac948ea4ced705e5f5520546aef4e11e746a6d95d" +checksum = "b8c2804d121a6d87f4b0cb861dc26e677e76953f4888a43292e34c5e6c5f2852" dependencies = [ "bincode", "chrono", @@ -4490,9 +4490,9 @@ dependencies = [ [[package]] name = "solana-connection-cache" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "758587d44e05a4abdf82b9514d1c8b7d35637ad65f7af7c3e3e02417aaae3c9e" +checksum = "2fe0460a6005bb2d9ee1d4bce9379ff50c1b438f6f1c8dc867d8b74141f68349" dependencies = [ "async-trait", "bincode", @@ -4511,9 +4511,9 @@ dependencies = [ [[package]] name = "solana-faucet" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0b7dfac6dd9a1cd3829fc230ed348f4972934800d754db73e2b434c16dafafd" +checksum = "e7bfbf4c31ec25ef12ca89a93ad10e23909249a6bf91f2ad7ca9ce3d510019bb" dependencies = [ "bincode", "byteorder", @@ -4535,9 +4535,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d266bf0311bb403d31206aa2904b8741f57c7f5e27580b6810ad5e22fc7c3282" +checksum = "8a63aebf4beac713a1949216ae180355c044df9cc3db9a58ca153bb10bb5843b" dependencies = [ "ahash 0.8.3", "blake3", @@ -4568,9 +4568,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi-macro" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dfe18c5155015dcb494c6de84a03b725fcf90ec2006a047769018b94c2cf0de" +checksum = "bced1b3c0421605312fd7eae7ceb6850d3b1d2e939da349c928e6d46a945c829" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", @@ -4580,9 +4580,9 @@ dependencies = [ [[package]] name = "solana-logger" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f76fe25c2d06dcf621befd1e8d5655143e8a059c7e20fcb71736bc80ed779d6" +checksum = "c95311f23906f0fa4a6d995f3c39593db18e4d943e4d3fbf082a510d0881d7af" dependencies = [ "env_logger", "lazy_static", @@ -4591,9 +4591,9 @@ dependencies = [ [[package]] name = "solana-measure" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db165b8a7f5d840abef011c78a18ffe63cad9192d676b07d94f469b6b5dc6cf6" +checksum = "944244553c62855c57d05ac049140762f1e095188a0e5b973b859947ac1d00bf" dependencies = [ "log", "solana-sdk", @@ -4601,9 +4601,9 @@ dependencies = [ [[package]] name = "solana-metrics" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa01731bb3952904962d49a1ea1205db54e93f3a56f4006d32e02a7c85d60546" +checksum = "f02b2244ee93fd282f057146ce779987a96cdeba5615d43dc0b6347b96134772" dependencies = [ "crossbeam-channel", "gethostname", @@ -4615,9 +4615,9 @@ dependencies = [ [[package]] name = "solana-net-utils" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd7ab67329dcebe4a40673fd0da27373282b1359ec7945e0fb81a9c594bcd057" +checksum = "f1dad26635fb41e948f56e1b896eab10e84cc62e00c59109a428a95c78fd6560" dependencies = [ "bincode", "clap 3.2.23", @@ -4637,9 +4637,9 @@ dependencies = [ [[package]] name = "solana-perf" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f900c1015844087cd4f10ba9d2d26a9859f2f5ca07427865cc74942595abc0a7" +checksum = "b03a0782c2b62c476c3fafd4e002ad8d91a2e36ca952df8e965d81dbf1dc158d" dependencies = [ "ahash 0.8.3", "bincode", @@ -4664,9 +4664,9 @@ dependencies = [ [[package]] name = "solana-program" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bb16998986492de307eef503ce47e84503d35baa92dc60832b22476948b1c16" +checksum = "e1f5c12cb15108734adae20be5e922c2db09d9623099541dcc61790703c6271c" dependencies = [ "ark-bn254", "ark-ec", @@ -4719,9 +4719,9 @@ dependencies = [ [[package]] name = "solana-program-runtime" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "036d6ecf67a3a7c6dc74d4f7fa6ab321e7ce8feccb7c9dff8384a41d0a12345b" +checksum = "eb7d1b8df43a93c410456be7d41c0dca9e2c460530a075243a98f556391d2bf9" dependencies = [ "base64 0.21.4", "bincode", @@ -4747,9 +4747,9 @@ dependencies = [ [[package]] name = "solana-pubsub-client" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e318f46bedb39374e98f299266a155b2c81c9d920f3c90f761261267c275c1" +checksum = "3b06d8521ac6edf8e8080cb5411f3b831a400341274036528a6364d52f2a97a4" dependencies = [ "crossbeam-channel", "futures-util", @@ -4772,9 +4772,9 @@ dependencies = [ [[package]] name = "solana-quic-client" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61db18a804642f8eb37369e903774a85d7949a55bd204ec090ebe0742fd2fe32" +checksum = "4cba7522b79c889136f99aef825f874be07e94afef561b85a13e9ea3c012d778" dependencies = [ "async-mutex", "async-trait", @@ -4800,9 +4800,9 @@ dependencies = [ [[package]] name = "solana-rayon-threadlimit" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "805377478f2d413f6cfcba6924c81ac4988ac0f96cdb045a8a9d81c430e6622a" +checksum = "dd2081d1ed74301999e73e437c25c17dca82038e5472e104caf34b2657b3ba4a" dependencies = [ "lazy_static", "num_cpus", @@ -4810,9 +4810,9 @@ dependencies = [ [[package]] name = "solana-remote-wallet" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a1148dcd76f76ad0399c1d9abf05cb32a0e545c5bee47ebe6d3b3e800c7fa7c" +checksum = "0a08a9c833b21fe9ec6ab74ea271de236cf7fd2602f34283752bba9c25d62304" dependencies = [ "console", "dialoguer", @@ -4830,9 +4830,9 @@ dependencies = [ [[package]] name = "solana-rpc-client" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc51a85c6ff03bb4a3e1fde1e36dcb553b990f2b3e66aed941a31a6a7c20fa33" +checksum = "1301ef82a9e87afb28bfccab1b3ebf8f10d6d2ee42c5b1d793ab989d70f83e27" dependencies = [ "async-trait", "base64 0.21.4", @@ -4856,9 +4856,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-api" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6756a1f89f509154644a958869c7cc6c70cc622f44faddf9b94612d8d2d8eed5" +checksum = "9ffdfe666315851d1a5c3d426a688dccfd2af19b46667140ea59b9ddf3988038" dependencies = [ "base64 0.21.4", "bs58", @@ -4878,9 +4878,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-nonce-utils" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4850e8db607525a36d330f073703e78e908a54ac66aa323a44cfc12c14c16699" +checksum = "d45f9be345ea2d29eb2c43d4b9a4c5181513f0af3e366be8b5e478ef451177be" dependencies = [ "clap 2.34.0", "solana-clap-utils", @@ -4891,9 +4891,9 @@ dependencies = [ [[package]] name = "solana-sdk" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4106cda3d10833ba957dbd25fb841b50aeca7480ccf8f54859294716f54bcd4b" +checksum = "051b93dc7737a7fb530c1e74f135a652bb69f5554c8804b2ebf55d6fb6a30f26" dependencies = [ "assert_matches", "base64 0.21.4", @@ -4944,9 +4944,9 @@ dependencies = [ [[package]] name = "solana-sdk-macro" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e560806a3859717eb2220b26e2cd68bb757b63affa3e79c3f1d8d853b5ee78f" +checksum = "a1fae2d1f62d655f88280a39711db401973d1bbe54fec9f795be80b9d76837ae" dependencies = [ "bs58", "proc-macro2 1.0.66", @@ -4957,9 +4957,9 @@ dependencies = [ [[package]] name = "solana-streamer" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78f142cbb497d257e70253c158a4c34037e310d24a055fae7dbc5c396b7611aa" +checksum = "f9cf11ed42da5fd14f4fd197d325951d2d7890aab8e25a7782f8b7540918d3a1" dependencies = [ "async-channel", "bytes", @@ -4990,9 +4990,9 @@ dependencies = [ [[package]] name = "solana-thin-client" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0e41ce715b34749d2c0d3181dd910d2b99fa2142a0aaf3cd44926cb02edd60d" +checksum = "bffbc01cdc316ff88398afbcd3befa78919049362bfe1a8a5794c942ce34bd96" dependencies = [ "bincode", "log", @@ -5005,9 +5005,9 @@ dependencies = [ [[package]] name = "solana-tpu-client" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84ec99361a39e17a2bffe2a59b97b3d20ddef323f9166929783ce49f340c200d" +checksum = "8209c111aff1fcf3028a8ee39c7c2171012fda5b31a72b2427d2c2d989dc6d3c" dependencies = [ "async-trait", "bincode", @@ -5030,9 +5030,9 @@ dependencies = [ [[package]] name = "solana-transaction-status" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "236dd4e43b8a7402bce250228e04c0c68d9493a3e19c71b377ccc7c4390fd969" +checksum = "bdad82a1e22d7c3fc1e009eeec4e8841697f6cce1902b7a1d5b73baf2bcca2e5" dependencies = [ "Inflector", "base64 0.21.4", @@ -5056,9 +5056,9 @@ dependencies = [ [[package]] name = "solana-udp-client" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b438036719e5c1201aba2336a5dc1caa8c8eefafd7110b7a3818ae199b54da" +checksum = "a48721c6347353071589e3fbade33079e7ebade6087bb5b10edc788ad41b1ae2" dependencies = [ "async-trait", "solana-connection-cache", @@ -5071,9 +5071,9 @@ dependencies = [ [[package]] name = "solana-version" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62847d7ef409e3b410f65e726bf7816d8f8d0330918e78537e940bdf1ca061ae" +checksum = "de7e99eb16bdc91861829bf0a6e361dd87ab898673b3708ebacf4ba27ca4d242" dependencies = [ "log", "rustc_version", @@ -5087,9 +5087,9 @@ dependencies = [ [[package]] name = "solana-vote-program" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb0c3e5ee7bd03b249c6b80eead5620af62bc7ef1af8ea4f499b8054b00e9c7d" +checksum = "22b1a3a2d9807a4141f0a550fdb3fa61a4aac4b4e7ea31694739509a43b9fa23" dependencies = [ "bincode", "log", @@ -5109,9 +5109,9 @@ dependencies = [ [[package]] name = "solana-zk-token-sdk" -version = "1.16.17" +version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "278c08e13bc04b6940997602909052524a375154b00cf0bfa934359a3bb7e6f0" +checksum = "ad3cc2b931a39510b1c90dc876a93ae315b9712a8338296e4b60519d09e57be9" dependencies = [ "aes-gcm-siv", "base64 0.21.4", diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 9613951de..ad7557ec9 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -8,8 +8,8 @@ edition = "2021" [dependencies] clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } -solana-sdk = "=1.16.17" -solana-client = "=1.16.17" +solana-sdk = "=1.16.18" +solana-client = "=1.16.18" serde = "1.0.186" serde_json = { version = "1.0.107", features = ["preserve_order"] } ethnum = { version = "1.4", default-features = false, features = ["serde"] } diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index e7b671d96..36f2544d8 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -8,10 +8,10 @@ edition = "2021" [dependencies] clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } -solana-sdk = "=1.16.17" -solana-client = "=1.16.17" -solana-clap-utils = "=1.16.17" -solana-cli-config = "=1.16.17" +solana-sdk = "=1.16.18" +solana-client = "=1.16.18" +solana-clap-utils = "=1.16.18" +solana-cli-config = "=1.16.18" hex = "0.4.2" serde = "1.0.186" serde_json = { version = "1.0.107", features = ["preserve_order"] } diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index cb3d166e6..b2432d552 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -10,12 +10,12 @@ thiserror = "1.0" anyhow = "1.0" bincode = "1.3.1" evm-loader = { path = "../program", default-features = false, features = ["log", "async-trait", "serde_json"] } -solana-sdk = "=1.16.17" -solana-client = "=1.16.17" -solana-clap-utils = "=1.16.17" -solana-cli-config = "=1.16.17" -solana-cli = "=1.16.17" -solana-transaction-status = "=1.16.17" +solana-sdk = "=1.16.18" +solana-client = "=1.16.18" +solana-clap-utils = "=1.16.18" +solana-cli-config = "=1.16.18" +solana-cli = "=1.16.18" +solana-transaction-status = "=1.16.18" spl-token = { version = "~3.5", default-features = false, features = ["no-entrypoint"] } spl-associated-token-account = { version = "~1.1", default-features = false, features = ["no-entrypoint"] } bs58 = "0.4.0" diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 34fea24d7..117c7295f 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -37,7 +37,7 @@ default = ["custom-heap"] [dependencies] linked_list_allocator = { version = "0.10", default-features = false } evm-loader-macro = { path = "../program-macro" } -solana-program = { version = "=1.16.17", default-features = false } +solana-program = { version = "=1.16.18", default-features = false } spl-token = { version = "~3.5", default-features = false, features = ["no-entrypoint"] } spl-associated-token-account = { version = "~1.1", default-features = false, features = ["no-entrypoint"] } mpl-token-metadata = { version = "1.13.2", default-features = false, features = ["no-entrypoint"] } From dbbfdccdb148cc5bee8c6168d6c14b00ed8ff19b Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Tue, 14 Nov 2023 17:59:10 +0300 Subject: [PATCH 048/318] [Multi Tokens] Accounts changes --- .../program/src/account/ether_account.rs | 175 ------- .../program/src/account/ether_balance.rs | 201 ++++++++ .../program/src/account/ether_contract.rs | 237 +++++++--- .../program/src/account/ether_storage.rs | 268 ++++++----- evm_loader/program/src/account/holder.rs | 194 +++++--- .../src/account/legacy/legacy_ether.rs | 119 +++++ .../src/account/legacy/legacy_holder.rs | 70 +++ .../src/account/legacy/legacy_storage_cell.rs | 78 ++++ evm_loader/program/src/account/legacy/mod.rs | 221 +++++++++ evm_loader/program/src/account/mod.rs | 383 ++++++++-------- evm_loader/program/src/account/operator.rs | 1 + evm_loader/program/src/account/program.rs | 66 ++- evm_loader/program/src/account/state.rs | 432 ++++++++++++++---- .../program/src/account/state_finalized.rs | 55 +++ evm_loader/program/src/account/sysvar.rs | 16 - evm_loader/program/src/account/token.rs | 4 + evm_loader/program/src/account/treasury.rs | 23 +- evm_loader/program/src/state_account.rs | 325 ------------- 18 files changed, 1762 insertions(+), 1106 deletions(-) delete mode 100644 evm_loader/program/src/account/ether_account.rs create mode 100644 evm_loader/program/src/account/ether_balance.rs create mode 100644 evm_loader/program/src/account/legacy/legacy_ether.rs create mode 100644 evm_loader/program/src/account/legacy/legacy_holder.rs create mode 100644 evm_loader/program/src/account/legacy/legacy_storage_cell.rs create mode 100644 evm_loader/program/src/account/legacy/mod.rs create mode 100644 evm_loader/program/src/account/state_finalized.rs delete mode 100644 evm_loader/program/src/account/sysvar.rs delete mode 100644 evm_loader/program/src/state_account.rs diff --git a/evm_loader/program/src/account/ether_account.rs b/evm_loader/program/src/account/ether_account.rs deleted file mode 100644 index af9dea29f..000000000 --- a/evm_loader/program/src/account/ether_account.rs +++ /dev/null @@ -1,175 +0,0 @@ -#![allow(clippy::use_self)] // Can't use generic parameter from outer function - -use std::mem::size_of; - -use arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}; -use ethnum::U256; -use solana_program::account_info::AccountInfo; -use solana_program::program_error::ProgramError; -use solana_program::{entrypoint::ProgramResult, pubkey::Pubkey}; - -use crate::types::Address; - -use super::{program::System, EthereumAccount, Packable}; -use super::{Operator, ACCOUNT_SEED_VERSION}; - -/// Ethereum account data v3 -#[derive(Debug, Default)] -pub struct Data { - /// Ethereum address - pub address: Address, - /// Solana account nonce - pub bump_seed: u8, - /// Ethereum account nonce - pub trx_count: u64, - /// Neon token balance - pub balance: U256, - /// Account generation, increment on suicide - pub generation: u32, - /// Contract code size - pub code_size: u32, - /// Read-write lock - pub rw_blocked: bool, -} - -impl Data { - const ADDRESS_SIZE: usize = size_of::
(); - const BUMP_SEED_SIZE: usize = size_of::(); - const TRX_COUNT_SIZE: usize = size_of::(); - const BALANCE_SIZE: usize = size_of::(); - const GENERATION_SIZE: usize = size_of::(); - const CODE_SIZE_SIZE: usize = size_of::(); - const RW_BLOCKED_SIZE: usize = size_of::(); -} - -impl Packable for Data { - /// `AccountV3` struct tag - const TAG: u8 = super::TAG_ACCOUNT_V3; - - /// `AccountV3` struct serialized size - const SIZE: usize = Data::ADDRESS_SIZE - + Data::BUMP_SEED_SIZE - + Data::TRX_COUNT_SIZE - + Data::BALANCE_SIZE - + Data::GENERATION_SIZE - + Data::CODE_SIZE_SIZE - + Data::RW_BLOCKED_SIZE; - - /// Deserialize `AccountV3` struct from input data - #[must_use] - fn unpack(input: &[u8]) -> Self { - let data = array_ref![input, 0, Data::SIZE]; - #[allow(clippy::ptr_offset_with_cast)] - let (address, bump_seed, trx_count, balance, generation, code_size, rw_blocked) = array_refs![ - data, - Data::ADDRESS_SIZE, - Data::BUMP_SEED_SIZE, - Data::TRX_COUNT_SIZE, - Data::BALANCE_SIZE, - Data::GENERATION_SIZE, - Data::CODE_SIZE_SIZE, - Data::RW_BLOCKED_SIZE - ]; - - Self { - address: Address::from(*address), - bump_seed: bump_seed[0], - trx_count: u64::from_le_bytes(*trx_count), - balance: U256::from_le_bytes(*balance), - generation: u32::from_le_bytes(*generation), - code_size: u32::from_le_bytes(*code_size), - rw_blocked: rw_blocked[0] != 0, - } - } - - /// Serialize `AccountV3` struct into given destination - fn pack(&self, dst: &mut [u8]) { - let data = array_mut_ref![dst, 0, Data::SIZE]; - #[allow(clippy::ptr_offset_with_cast)] - let (address, bump_seed, trx_count, balance, generation, code_size, rw_blocked) = mut_array_refs![ - data, - Data::ADDRESS_SIZE, - Data::BUMP_SEED_SIZE, - Data::TRX_COUNT_SIZE, - Data::BALANCE_SIZE, - Data::GENERATION_SIZE, - Data::CODE_SIZE_SIZE, - Data::RW_BLOCKED_SIZE - ]; - - *address = self.address.into(); - bump_seed[0] = self.bump_seed; - *trx_count = self.trx_count.to_le_bytes(); - *balance = self.balance.to_le_bytes(); - *generation = self.generation.to_le_bytes(); - *code_size = self.code_size.to_le_bytes(); - rw_blocked[0] = u8::from(self.rw_blocked); - } -} - -impl<'a> EthereumAccount<'a> { - pub fn check_blocked(&self) -> ProgramResult { - if self.rw_blocked { - // error message is parsed in proxy, do not change - return Err!(ProgramError::InvalidAccountData; "trying to execute transaction on rw locked account {}", self.address); - } - - Ok(()) - } - - pub fn create_account( - system_program: &System<'a>, - program_id: &Pubkey, - operator: &Operator<'a>, - address: &Address, - info: &'a AccountInfo<'a>, - bump_seed: u8, - space: usize, - ) -> ProgramResult { - if space < EthereumAccount::SIZE { - return Err!( - ProgramError::AccountDataTooSmall; - "Account {} - account space must be not less than minimal size of {} bytes", - address, - EthereumAccount::SIZE - ); - } - - let program_seeds: &[&[u8]] = &[&[ACCOUNT_SEED_VERSION], address.as_bytes(), &[bump_seed]]; - system_program.create_pda_account(program_id, operator, info, program_seeds, space)?; - - Ok(()) - } - - pub fn create_and_init_account( - system_program: &System<'a>, - program_id: &Pubkey, - operator: &Operator<'a>, - address: Address, - info: &'a AccountInfo<'a>, - bump_seed: u8, - space: usize, - ) -> ProgramResult { - Self::create_account( - system_program, - program_id, - operator, - &address, - info, - bump_seed, - space, - )?; - - EthereumAccount::init( - program_id, - info, - Data { - address, - bump_seed, - ..Default::default() - }, - )?; - - Ok(()) - } -} diff --git a/evm_loader/program/src/account/ether_balance.rs b/evm_loader/program/src/account/ether_balance.rs new file mode 100644 index 000000000..600f1d5f3 --- /dev/null +++ b/evm_loader/program/src/account/ether_balance.rs @@ -0,0 +1,201 @@ +use std::{ + cell::{Ref, RefMut}, + mem::size_of, +}; + +use crate::{ + account::{TAG_ACCOUNT_CONTRACT, TAG_EMPTY}, + account_storage::KeysCache, + config::DEFAULT_CHAIN_ID, + error::{Error, Result}, + types::Address, +}; +use ethnum::U256; +use solana_program::{account_info::AccountInfo, pubkey::Pubkey, system_program}; + +use super::{AccountsDB, ACCOUNT_PREFIX_LEN, ACCOUNT_SEED_VERSION, TAG_ACCOUNT_BALANCE}; + +#[repr(C, packed)] +pub struct Header { + // address: Address, + pub chain_id: u64, + pub trx_count: u64, + pub balance: U256, +} + +pub struct BalanceAccount<'a> { + pub address: Option
, + account: AccountInfo<'a>, +} + +const HEADER_OFFSET: usize = ACCOUNT_PREFIX_LEN; + +impl<'a> BalanceAccount<'a> { + #[must_use] + pub fn required_account_size() -> usize { + ACCOUNT_PREFIX_LEN + size_of::
() + } + + pub fn from_account( + program_id: &Pubkey, + account: AccountInfo<'a>, + address: Option
, + ) -> Result { + super::validate_tag(program_id, &account, TAG_ACCOUNT_BALANCE)?; + + Ok(Self { address, account }) + } + + pub fn create( + address: Address, + chain_id: u64, + accounts: &AccountsDB<'a>, + keys: Option<&KeysCache>, + ) -> Result { + let (pubkey, bump_seed) = keys.map_or_else( + || address.find_balance_address(&crate::ID, chain_id), + |keys| keys.balance_with_bump_seed(&crate::ID, address, chain_id), + ); + + // Already created. Return immidiately + let account = accounts.get(&pubkey).clone(); + if !system_program::check_id(account.owner) { + return Self::from_account(&crate::ID, account, Some(address)); + } + + if chain_id == DEFAULT_CHAIN_ID { + // Make sure no legacy account exists + let legacy_pubkey = keys.map_or_else( + || address.find_solana_address(&crate::ID).0, + |keys| keys.contract(&crate::ID, address), + ); + + let legacy_account = accounts.get(&legacy_pubkey); + if crate::check_id(legacy_account.owner) { + let legacy_tag = super::tag(&crate::ID, legacy_account)?; + assert!(legacy_tag == TAG_EMPTY || legacy_tag == TAG_ACCOUNT_CONTRACT); + } + } + + // Create a new account + let program_seeds: &[&[u8]] = &[ + &[ACCOUNT_SEED_VERSION], + address.as_bytes(), + &U256::from(chain_id).to_be_bytes(), + &[bump_seed], + ]; + + let system = accounts.system(); + let operator = accounts.operator(); + + system.create_pda_account( + &crate::ID, + operator, + &account, + program_seeds, + ACCOUNT_PREFIX_LEN + size_of::
(), + )?; + + super::set_tag(&crate::ID, &account, TAG_ACCOUNT_BALANCE)?; + let mut balance_account = Self { + address: Some(address), + account, + }; + { + let mut header = balance_account.header_mut(); + header.chain_id = chain_id; + header.trx_count = 0; + header.balance = U256::ZERO; + } + + Ok(balance_account) + } + + #[must_use] + pub fn pubkey(&self) -> &'a Pubkey { + self.account.key + } + + #[inline] + fn header(&self) -> Ref
{ + super::section(&self.account, HEADER_OFFSET) + } + + #[inline] + fn header_mut(&mut self) -> RefMut
{ + super::section_mut(&self.account, HEADER_OFFSET) + } + + #[must_use] + pub fn chain_id(&self) -> u64 { + self.header().chain_id + } + + #[must_use] + pub fn nonce(&self) -> u64 { + self.header().trx_count + } + + #[must_use] + pub fn exists(&self) -> bool { + let header = self.header(); + + ({ header.trx_count } > 0) || ({ header.balance } > 0) + } + + pub fn increment_nonce(&mut self) -> Result<()> { + self.increment_nonce_by(1) + } + + pub fn increment_nonce_by(&mut self, value: u64) -> Result<()> { + let address = self.address.unwrap_or_default(); + + let mut header = self.header_mut(); + header.trx_count = header + .trx_count + .checked_add(value) + .ok_or_else(|| Error::NonceOverflow(address))?; + + Ok(()) + } + + #[must_use] + pub fn balance(&self) -> U256 { + self.header().balance + } + + pub fn transfer(&mut self, target: &mut BalanceAccount, value: U256) -> Result<()> { + if self.account.key == target.account.key { + return Ok(()); + } + + assert_eq!(self.chain_id(), target.chain_id()); + + self.burn(value)?; + target.mint(value) + } + + pub fn burn(&mut self, value: U256) -> Result<()> { + let address = self.address.unwrap_or_default(); + + let mut header = self.header_mut(); + + header.balance = header + .balance + .checked_sub(value) + .ok_or(Error::InsufficientBalance(address, header.chain_id, value))?; + + Ok(()) + } + + pub fn mint(&mut self, value: U256) -> Result<()> { + let mut header = self.header_mut(); + + header.balance = header + .balance + .checked_add(value) + .ok_or(Error::IntegerOverflow)?; + + Ok(()) + } +} diff --git a/evm_loader/program/src/account/ether_contract.rs b/evm_loader/program/src/account/ether_contract.rs index 96b20bed3..f96fd93cd 100644 --- a/evm_loader/program/src/account/ether_contract.rs +++ b/evm_loader/program/src/account/ether_contract.rs @@ -1,90 +1,223 @@ -use std::cell::RefMut; -use std::mem::size_of; -use std::ops::Range; +use crate::{ + account::TAG_EMPTY, + account_storage::KeysCache, + error::{Error, Result}, + types::Address, +}; +use solana_program::{ + account_info::AccountInfo, entrypoint::MAX_PERMITTED_DATA_INCREASE, pubkey::Pubkey, rent::Rent, + system_program, +}; +use std::{ + cell::{Ref, RefMut}, + mem::size_of, +}; -use ethnum::U256; - -use crate::account::EthereumAccount; use crate::config::STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT; -const INTERNAL_STORAGE_SIZE: usize = - size_of::() * STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT as usize; +use super::{AccountsDB, ACCOUNT_PREFIX_LEN, ACCOUNT_SEED_VERSION, TAG_ACCOUNT_CONTRACT}; + +#[derive(Eq, PartialEq)] +pub enum AllocateResult { + Ready, + NeedMore, +} + +#[repr(C, packed)] +pub struct Header { + pub chain_id: u64, + pub generation: u32, +} + +pub type Storage = [[u8; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT]; +pub type Code = [u8]; -pub struct ContractData<'this, 'acc> { - account: &'this EthereumAccount<'acc>, +pub struct ContractAccount<'a> { + account: AccountInfo<'a>, } -impl<'acc> ContractData<'_, 'acc> { +const HEADER_OFFSET: usize = ACCOUNT_PREFIX_LEN; +const STORAGE_OFFSET: usize = HEADER_OFFSET + size_of::
(); +const CODE_OFFSET: usize = STORAGE_OFFSET + size_of::(); + +impl<'a> ContractAccount<'a> { #[must_use] - pub fn code(&self) -> RefMut<'acc, [u8]> { - let offset = INTERNAL_STORAGE_SIZE; - let len = self.account.code_size as usize; + pub fn required_account_size(code: &[u8]) -> usize { + ACCOUNT_PREFIX_LEN + size_of::
() + size_of::() + code.len() + } + + pub fn from_account(program_id: &Pubkey, account: AccountInfo<'a>) -> Result { + super::validate_tag(program_id, &account, TAG_ACCOUNT_CONTRACT)?; - self.extension_part_borrow_mut(offset, len) + Ok(Self { account }) } - #[must_use] - pub fn storage(&self) -> RefMut<'acc, [u8]> { - let offset = 0; - let len = INTERNAL_STORAGE_SIZE; + pub fn allocate( + address: Address, + code: &[u8], + rent: &Rent, + accounts: &AccountsDB, + keys: Option<&KeysCache>, + ) -> Result { + let (pubkey, bump_seed) = keys.map_or_else( + || address.find_solana_address(&crate::ID), + |keys| keys.contract_with_bump_seed(&crate::ID, address), + ); + + let info = accounts.get(&pubkey); + + let required_size = Self::required_account_size(code); + if info.data_len() >= required_size { + return Ok(AllocateResult::Ready); + } - self.extension_part_borrow_mut(offset, len) + let system = accounts.system(); + let operator = accounts.operator(); + + if system_program::check_id(info.owner) { + let seeds: &[&[u8]] = &[&[ACCOUNT_SEED_VERSION], address.as_bytes(), &[bump_seed]]; + let space = required_size.min(MAX_PERMITTED_DATA_INCREASE); + system.create_pda_account(&crate::ID, operator, info, seeds, space)?; + } else if crate::check_id(info.owner) { + super::validate_tag(&crate::ID, info, TAG_EMPTY)?; + + let max_size = info.data_len() + MAX_PERMITTED_DATA_INCREASE; + let space = required_size.min(max_size); + info.realloc(space, false)?; + + let required_balance = rent.minimum_balance(space); + if info.lamports() < required_balance { + let lamports = required_balance - info.lamports(); + system.transfer(operator, info, lamports)?; + } + } else { + return Err(Error::AccountInvalidOwner(pubkey, system_program::ID)); + } + + if info.data_len() >= required_size { + Ok(AllocateResult::Ready) + } else { + Ok(AllocateResult::NeedMore) + } + } + + pub fn init( + address: Address, + chain_id: u64, + generation: u32, + code: &[u8], + accounts: &AccountsDB<'a>, + keys: Option<&KeysCache>, + ) -> Result { + let (pubkey, _) = keys.map_or_else( + || address.find_solana_address(&crate::ID), + |keys| keys.contract_with_bump_seed(&crate::ID, address), + ); + + let account = accounts.get(&pubkey).clone(); + + super::validate_tag(&crate::ID, &account, TAG_EMPTY)?; + super::set_tag(&crate::ID, &account, TAG_ACCOUNT_CONTRACT)?; + + let mut contract = Self::from_account(&crate::ID, account)?; + { + let mut header = contract.header_mut(); + header.chain_id = chain_id; + header.generation = generation; + } + { + let mut contract_code = contract.code_mut(); + contract_code.copy_from_slice(code); + } + + Ok(contract) } #[must_use] - pub fn extension_borrow_mut(&self) -> RefMut<'acc, [u8]> { - RefMut::map(self.account.info.data.borrow_mut(), |slice| { - &mut slice[EthereumAccount::SIZE..] - }) + pub fn pubkey(&self) -> &'a Pubkey { + self.account.key } + #[inline] #[must_use] - fn extension_part_borrow_mut(&self, offset: usize, len: usize) -> RefMut<'acc, [u8]> { - RefMut::map(self.extension_borrow_mut(), |slice| { - &mut slice[offset..][..len] - }) + fn header(&self) -> Ref
{ + super::section(&self.account, HEADER_OFFSET) } -} -impl<'this, 'acc> EthereumAccount<'acc> { + #[inline] #[must_use] - pub fn is_contract(&self) -> bool { - self.code_size() != 0 + fn header_mut(&mut self) -> RefMut
{ + super::section_mut(&self.account, HEADER_OFFSET) + } + + #[inline] + fn storage(&self) -> Ref { + super::section(&self.account, STORAGE_OFFSET) + } + + #[inline] + fn storage_mut(&mut self) -> RefMut { + super::section_mut(&self.account, STORAGE_OFFSET) } + #[inline] #[must_use] - pub fn code_size(&self) -> usize { - self.code_size as usize + pub fn code(&self) -> Ref { + let data = self.account.data.borrow(); + Ref::map(data, |d| &d[CODE_OFFSET..]) + } + + #[inline] + fn code_mut(&self) -> RefMut { + let data = self.account.data.borrow_mut(); + RefMut::map(data, |d| &mut d[CODE_OFFSET..]) } #[must_use] - pub fn code_location(&self) -> Range { - let begin = Self::SIZE + INTERNAL_STORAGE_SIZE; - let end = begin.saturating_add(self.code_size()); + pub fn code_buffer(&self) -> crate::evm::Buffer { + let begin = CODE_OFFSET; + let end = begin + self.code_len(); - begin..end + unsafe { crate::evm::Buffer::from_account(&self.account, begin..end) } } #[must_use] - pub fn contract_data(&'this self) -> Option> { - if !self.is_contract() { - return None; - } - Some(ContractData { account: self }) + pub fn code_len(&self) -> usize { + self.account.data_len().saturating_sub(CODE_OFFSET) } #[must_use] - pub fn space_needed(code_size: usize) -> usize { - EthereumAccount::SIZE - + if code_size > 0 { - code_size + INTERNAL_STORAGE_SIZE - } else { - 0 - } + pub fn chain_id(&self) -> u64 { + self.header().chain_id } #[must_use] - pub fn size(&self) -> usize { - Self::space_needed(self.code_size()) + pub fn generation(&self) -> u32 { + self.header().generation + } + + #[must_use] + pub fn storage_value(&self, index: usize) -> [u8; 32] { + assert!(index < STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT); + + let storage = self.storage(); + storage[index] + } + + pub fn set_storage_value(&mut self, index: usize, value: &[u8; 32]) { + assert!(index < STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT); + + let mut storage = self.storage_mut(); + + let cell: &mut [u8; 32] = &mut storage[index]; + cell.copy_from_slice(value); + } + + pub fn set_storage_multiple_values(&mut self, offset: usize, values: &[[u8; 32]]) { + let max = offset.saturating_add(values.len()); + assert!(max <= STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT); + + let mut storage = self.storage_mut(); + storage[offset..][..values.len()].copy_from_slice(values); } } diff --git a/evm_loader/program/src/account/ether_storage.rs b/evm_loader/program/src/account/ether_storage.rs index 4c28e2969..f047b4da9 100644 --- a/evm_loader/program/src/account/ether_storage.rs +++ b/evm_loader/program/src/account/ether_storage.rs @@ -1,58 +1,19 @@ -#![allow(clippy::use_self)] // Can't use generic parameter from outer function +use std::cell::{Ref, RefMut}; +use std::mem::size_of; -use super::{program, EthereumAccount, EthereumStorage, Operator, Packable}; -use crate::types::Address; -use arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}; +use super::{AccountsDB, ACCOUNT_PREFIX_LEN, TAG_STORAGE_CELL}; +use crate::error::Result; use ethnum::U256; -use solana_program::{ - account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, rent::Rent, - sysvar::Sysvar, -}; - -/// Ethereum storage data account -#[derive(Default, Debug)] -pub struct Data { - pub address: Address, - pub generation: u32, - pub index: U256, -} - -impl Packable for Data { - /// Storage struct tag - const TAG: u8 = super::TAG_CONTRACT_STORAGE; - /// Storage struct serialized size - const SIZE: usize = 20 + 4 + 32; - - /// Deserialize `Storage` struct from input data - #[must_use] - fn unpack(input: &[u8]) -> Self { - let data = array_ref![input, 0, Data::SIZE]; - let (address, generation, index) = array_refs![data, 20, 4, 32]; - - Self { - address: Address(*address), - generation: u32::from_le_bytes(*generation), - index: U256::from_le_bytes(*index), - } - } +use solana_program::{account_info::AccountInfo, pubkey::Pubkey, rent::Rent}; - /// Serialize `Storage` struct into given destination - fn pack(&self, output: &mut [u8]) { - let data = array_mut_ref![output, 0, Data::SIZE]; - let (address, generation, index) = mut_array_refs![data, 20, 4, 32]; - - *address = *self.address.as_bytes(); - *generation = self.generation.to_le_bytes(); - *index = self.index.to_le_bytes(); - } -} - -pub struct EthereumStorageAddress { +#[derive(Copy, Clone)] +pub struct StorageCellAddress { + base: Pubkey, seed: [u8; 32], pubkey: Pubkey, } -impl EthereumStorageAddress { +impl StorageCellAddress { #[must_use] fn make_seed(index: &U256) -> [u8; 32] { let mut buffer = [0_u8; 32]; @@ -89,6 +50,7 @@ impl EthereumStorageAddress { let pubkey = Pubkey::create_with_seed(base, seed, program_id).unwrap(); Self { + base: *base, seed: seed_buffer, pubkey, } @@ -105,121 +67,155 @@ impl EthereumStorageAddress { } } -impl<'a> EthereumStorage<'a> { - #[must_use] - pub fn get(&self, subindex: u8) -> [u8; 32] { - let data = self.info.data.borrow(); - let data = &data[Self::SIZE..]; +#[repr(C, packed)] +#[derive(Copy, Clone)] +pub struct Cell { + pub subindex: u8, + pub value: [u8; 32], +} - for chunk in data.chunks_exact(1 + 32) { - if chunk[0] != subindex { - continue; - } +pub struct StorageCell<'a> { + account: AccountInfo<'a>, +} - return chunk[1..].try_into().unwrap(); - } +const CELLS_OFFSET: usize = ACCOUNT_PREFIX_LEN; - [0_u8; 32] +impl<'a> StorageCell<'a> { + #[must_use] + pub fn required_account_size(cells: usize) -> usize { + ACCOUNT_PREFIX_LEN + cells * size_of::() } - pub fn set( - &mut self, - subindex: u8, - value: &[u8; 32], - required_account_transfers: &mut std::collections::HashMap, u64)>, - ) -> Result<(), ProgramError> { - { - let mut data = self.info.data.borrow_mut(); - let data = &mut data[Self::SIZE..]; + pub fn from_account(program_id: &Pubkey, account: AccountInfo<'a>) -> Result { + super::validate_tag(program_id, &account, TAG_STORAGE_CELL)?; - for chunk in data.chunks_exact_mut(1 + 32) { - if chunk[0] != subindex { - continue; - } + Ok(Self { account }) + } - chunk[1..].copy_from_slice(value); + pub fn create( + address: StorageCellAddress, + allocate_cells: usize, + accounts: &AccountsDB<'a>, + signer_seeds: &[&[u8]], + ) -> Result { + let base_account = accounts.get(&address.base); + let cell_account = accounts.get(&address.pubkey); - return Ok(()); - } - } // drop `data` + assert!(allocate_cells <= u8::MAX.into()); + let space = ACCOUNT_PREFIX_LEN + (allocate_cells * size_of::()); - let new_len = self.info.data_len() + 1 + 32; // new_len <= 8.25 kb - self.info.realloc(new_len, false)?; + let system = accounts.system(); - let minimum_balance = Rent::get()?.minimum_balance(new_len); - if self.info.lamports() < minimum_balance { - let required_lamports = minimum_balance - self.info.lamports(); + system.create_account_with_seed( + &crate::ID, + accounts.operator(), + base_account, + signer_seeds, + cell_account, + address.seed(), + space, + )?; - // Accumulate the amount of lamports we need to transfer for this account - required_account_transfers - .insert(*self.info.key, (Clone::clone(self.info), required_lamports)); - } + super::set_tag(&crate::ID, cell_account, TAG_STORAGE_CELL)?; + Ok(Self { + account: cell_account.clone(), + }) + } - let mut data = self.info.data.borrow_mut(); - let data = &mut data[1..]; // skip tag + #[must_use] + pub fn pubkey(&self) -> &'a Pubkey { + self.account.key + } - let chunk_start = data.len() - 1 - 32; - let chunk = &mut data[chunk_start..]; + #[must_use] + pub fn cells(&self) -> Ref<[Cell]> { + let data = self.account.data.borrow(); + let data = Ref::map(data, |d| &d[CELLS_OFFSET..]); + + Ref::map(data, |bytes| { + static_assertions::assert_eq_align!(Cell, u8); + assert_eq!(bytes.len() % size_of::(), 0); + + // SAFETY: Cell has the same alignment as bytes + unsafe { + let ptr = bytes.as_ptr().cast::(); + let len = bytes.len() / size_of::(); + std::slice::from_raw_parts(ptr, len) + } + }) + } - chunk[0] = subindex; - chunk[1..].copy_from_slice(value); + #[must_use] + pub fn cells_mut(&mut self) -> RefMut<[Cell]> { + let data = self.account.data.borrow_mut(); + let data = RefMut::map(data, |d| &mut d[CELLS_OFFSET..]); + + RefMut::map(data, |bytes| { + static_assertions::assert_eq_align!(Cell, u8); + assert_eq!(bytes.len() % size_of::(), 0); + + // SAFETY: Cell has the same alignment as bytes + unsafe { + let ptr = bytes.as_mut_ptr().cast::(); + let len = bytes.len() / size_of::(); + std::slice::from_raw_parts_mut(ptr, len) + } + }) + } - Ok(()) + #[must_use] + pub fn get(&self, subindex: u8) -> [u8; 32] { + for cell in self.cells().iter() { + if cell.subindex != subindex { + continue; + } + + return cell.value; + } + + [0_u8; 32] } - #[allow(clippy::too_many_arguments)] - pub fn create( - contract: &EthereumAccount<'a>, - storage_account: &'a AccountInfo<'a>, - storage_address: &EthereumStorageAddress, - index: U256, - subindex: u8, - value: &[u8; 32], - operator: &Operator<'a>, - system: &program::System<'a>, - ) -> Result { - let space = Self::SIZE + 1 + 32; + pub fn update(&mut self, subindex: u8, value: &[u8; 32]) -> Result<()> { + // todo: if value is zero - destroy cell - system.create_account_with_seed( - operator, - contract, - contract.info.owner, - storage_account, - storage_address.seed(), - space, - )?; + for cell in self.cells_mut().iter_mut() { + if cell.subindex != subindex { + continue; + } - let storage = Self::init( - contract.info.owner, - storage_account, - Data { - address: contract.address, - generation: contract.generation, - index, - }, - )?; + cell.value.copy_from_slice(value); + return Ok(()); + } - let mut data = storage_account.data.borrow_mut(); - let data = &mut data[Self::SIZE..]; + let new_len = self.account.data_len() + std::mem::size_of::(); // new_len <= 8.25 kb + self.account.realloc(new_len, false)?; - data[0] = subindex; - data[1..].copy_from_slice(value); + let mut cells = self.cells_mut(); - Ok(storage) + let last_cell = cells.last_mut().unwrap(); + last_cell.subindex = subindex; + last_cell.value.copy_from_slice(value); + + Ok(()) } - pub fn clear(&mut self, generation: u32, operator: &Operator<'a>) -> Result<(), ProgramError> { - self.generation = generation; + pub fn sync_lamports(&mut self, rent: Rent, accounts: &AccountsDB<'a>) -> Result<()> { + let original_data_len = unsafe { self.account.original_data_len() }; + if original_data_len == self.account.data_len() { + return Ok(()); + } - self.info.realloc(Self::SIZE, false)?; + let minimum_balance = rent.minimum_balance(self.account.data_len()); + if self.account.lamports() >= minimum_balance { + return Ok(()); + } - let minimum_balance = Rent::get()?.minimum_balance(Self::SIZE); - let excessive_lamports = self.info.lamports().saturating_sub(minimum_balance); + let system = accounts.system(); + let operator = accounts.operator(); - if excessive_lamports > 0 { - **self.info.lamports.borrow_mut() -= excessive_lamports; - **operator.lamports.borrow_mut() += excessive_lamports; - } + let lamports = minimum_balance - self.account.lamports(); + system.transfer(operator, &self.account, lamports)?; Ok(()) } diff --git a/evm_loader/program/src/account/holder.rs b/evm_loader/program/src/account/holder.rs index 55c8218e9..cb12fc852 100644 --- a/evm_loader/program/src/account/holder.rs +++ b/evm_loader/program/src/account/holder.rs @@ -1,102 +1,184 @@ -#![allow(clippy::use_self)] // Can't use generic parameter from outer function - -use std::cell::Ref; - -use arrayref::{array_mut_ref, array_ref}; -use arrayref::{array_refs, mut_array_refs}; +use solana_program::account_info::AccountInfo; use solana_program::pubkey::Pubkey; +use std::cell::{Ref, RefMut}; +use std::mem::size_of; +use crate::account::TAG_STATE_FINALIZED; use crate::error::{Error, Result}; use crate::types::Transaction; -use super::Holder; -use super::Operator; -use super::Packable; +use super::{Operator, ACCOUNT_PREFIX_LEN, TAG_EMPTY, TAG_HOLDER}; /// Ethereum holder data account -#[derive(Default, Debug)] -pub struct Data { +#[repr(C, packed)] +pub struct Header { pub owner: Pubkey, pub transaction_hash: [u8; 32], pub transaction_len: usize, } -impl Packable for Data { - /// Holder struct tag - const TAG: u8 = super::TAG_HOLDER; - /// Holder struct serialized size - const SIZE: usize = 32 + 32 + 8; +pub struct Holder<'a> { + account: AccountInfo<'a>, +} + +const HEADER_OFFSET: usize = ACCOUNT_PREFIX_LEN; +const BUFFER_OFFSET: usize = HEADER_OFFSET + size_of::
(); - /// Deserialize `Holder` struct from input data - #[must_use] - fn unpack(src: &[u8]) -> Self { - let data = array_ref![src, 0, Data::SIZE]; - let (owner, hash, len) = array_refs![data, 32, 32, 8]; - - Self { - owner: Pubkey::new_from_array(*owner), - transaction_hash: *hash, - transaction_len: usize::from_le_bytes(*len), +impl<'a> Holder<'a> { + pub fn from_account(program_id: &Pubkey, account: AccountInfo<'a>) -> Result { + match super::tag(program_id, &account)? { + TAG_STATE_FINALIZED => { + super::set_tag(program_id, &account, TAG_HOLDER)?; + + let mut holder = Self { account }; + holder.clear(); + + Ok(holder) + } + TAG_HOLDER => Ok(Self { account }), + _ => Err(Error::AccountInvalidTag(*account.key, TAG_HOLDER)), } } - /// Serialize `Holder` struct into given destination - fn pack(&self, dst: &mut [u8]) { - let data = array_mut_ref![dst, 0, Data::SIZE]; - let (owner, hash, len) = mut_array_refs![data, 32, 32, 8]; + pub fn create( + program_id: &Pubkey, + account: AccountInfo<'a>, + seed: &str, + operator: &Operator, + ) -> Result { + if account.owner != program_id { + return Err(Error::AccountInvalidOwner(*account.key, *program_id)); + } + + let key = Pubkey::create_with_seed(operator.key, seed, program_id)?; + if &key != account.key { + return Err(Error::AccountInvalidKey(*account.key, key)); + } - owner.copy_from_slice(self.owner.as_ref()); - hash.copy_from_slice(&self.transaction_hash); - *len = self.transaction_len.to_le_bytes(); + super::validate_tag(program_id, &account, TAG_EMPTY)?; + super::set_tag(&crate::ID, &account, TAG_HOLDER)?; + + let mut holder = Self::from_account(program_id, account)?; + holder.header_mut().owner = *operator.key; + holder.clear(); + + Ok(holder) } -} -impl<'a> Holder<'a> { - pub fn clear(&mut self) -> Result<()> { - self.transaction_hash.fill(0); - self.transaction_len = 0; + pub fn update(&mut self, f: F) + where + F: FnOnce(&mut Header), + { + let mut header = self.header_mut(); + f(&mut header); + } - let mut data = self.info.try_borrow_mut_data()?; - data[Self::SIZE..].fill(0); + fn header(&self) -> Ref
{ + super::section(&self.account, HEADER_OFFSET) + } - Ok(()) + fn header_mut(&mut self) -> RefMut
{ + super::section_mut(&self.account, HEADER_OFFSET) } - pub fn write(&mut self, offset: usize, bytes: &[u8]) -> Result<()> { - let mut data = self.info.try_borrow_mut_data()?; + fn buffer(&self) -> Ref<[u8]> { + let data = self.account.data.borrow(); + Ref::map(data, |d| &d[BUFFER_OFFSET..]) + } - let begin = Self::SIZE - .checked_add(offset) - .ok_or(Error::IntegerOverflow)?; - let end = begin + fn buffer_mut(&mut self) -> RefMut<[u8]> { + let data = self.account.data.borrow_mut(); + RefMut::map(data, |d| &mut d[BUFFER_OFFSET..]) + } + + pub fn clear(&mut self) { + { + let mut header = self.header_mut(); + header.transaction_hash.fill(0); + header.transaction_len = 0; + } + { + let mut buffer = self.buffer_mut(); + buffer.fill(0); + } + } + + pub fn write(&mut self, offset: usize, bytes: &[u8]) -> Result<()> { + let begin = offset; + let end = offset .checked_add(bytes.len()) .ok_or(Error::IntegerOverflow)?; - data[begin..end].copy_from_slice(bytes); - self.transaction_len = std::cmp::max(self.transaction_len, offset + bytes.len()); + { + let mut header = self.header_mut(); + header.transaction_len = std::cmp::max(header.transaction_len, end); + } + { + let mut buffer = self.buffer_mut(); + let Some(buffer) = buffer.get_mut(begin..end) else { + return Err(Error::HolderInsufficientSize(buffer.len(), end)) + }; + + buffer.copy_from_slice(bytes); + } Ok(()) } #[must_use] - pub fn transaction(&self) -> Ref<'a, [u8]> { - let data = Ref::map(self.info.data.borrow(), |d| *d); - Ref::map(data, |d| &d[Self::SIZE..][..self.transaction_len]) + pub fn transaction_len(&self) -> usize { + self.header().transaction_len + } + + #[must_use] + pub fn transaction(&self) -> Ref<[u8]> { + let len = self.transaction_len(); + + let buffer = self.buffer(); + Ref::map(buffer, |b| &b[..len]) + } + + #[must_use] + pub fn transaction_hash(&self) -> [u8; 32] { + self.header().transaction_hash + } + + pub fn update_transaction_hash(&mut self, hash: [u8; 32]) { + if self.transaction_hash() == hash { + return; + } + + self.clear(); + self.header_mut().transaction_hash = hash; + } + + #[must_use] + pub fn owner(&self) -> Pubkey { + self.header().owner } pub fn validate_owner(&self, operator: &Operator) -> Result<()> { - if &self.owner != operator.key { - return Err(Error::HolderInvalidOwner(self.owner, *operator.key)); + if &self.owner() != operator.key { + return Err(Error::HolderInvalidOwner(self.owner(), *operator.key)); } Ok(()) } pub fn validate_transaction(&self, trx: &Transaction) -> Result<()> { - if self.transaction_hash != trx.hash() { - return Err(Error::HolderInvalidHash(self.transaction_hash, trx.hash())); + if self.transaction_hash() != trx.hash() { + return Err(Error::HolderInvalidHash( + self.transaction_hash(), + trx.hash(), + )); } Ok(()) } + + /// # Safety + /// Permanently deletes Holder account and all data in it + pub unsafe fn suicide(self, operator: &Operator) { + crate::account::delete(&self.account, operator); + } } diff --git a/evm_loader/program/src/account/legacy/legacy_ether.rs b/evm_loader/program/src/account/legacy/legacy_ether.rs new file mode 100644 index 000000000..ea42bfff6 --- /dev/null +++ b/evm_loader/program/src/account/legacy/legacy_ether.rs @@ -0,0 +1,119 @@ +use std::mem::size_of; + +use ethnum::U256; +use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; + +use crate::{config::STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT, error::Result, types::Address}; + +pub struct LegacyEtherData { + /// Ethereum address + pub address: Address, + /// Solana account nonce + pub bump_seed: u8, + /// Ethereum account nonce + pub trx_count: u64, + /// Neon token balance + pub balance: U256, + /// Account generation, increment on suicide + pub generation: u32, + /// Contract code size + pub code_size: u32, + /// Read-write lock + pub rw_blocked: bool, +} + +impl LegacyEtherData { + const ADDRESS_SIZE: usize = size_of::
(); + const BUMP_SEED_SIZE: usize = size_of::(); + const TRX_COUNT_SIZE: usize = size_of::(); + const BALANCE_SIZE: usize = size_of::(); + const GENERATION_SIZE: usize = size_of::(); + const CODE_SIZE_SIZE: usize = size_of::(); + const RW_BLOCKED_SIZE: usize = size_of::(); + + /// `AccountV3` struct tag + pub const TAG: u8 = super::TAG_ACCOUNT_CONTRACT_DEPRECATED; + + /// `AccountV3` struct serialized size + pub const SIZE: usize = Self::ADDRESS_SIZE + + Self::BUMP_SEED_SIZE + + Self::TRX_COUNT_SIZE + + Self::BALANCE_SIZE + + Self::GENERATION_SIZE + + Self::CODE_SIZE_SIZE + + Self::RW_BLOCKED_SIZE; + + #[must_use] + pub fn unpack(input: &[u8]) -> Self { + let data = arrayref::array_ref![input, 0, LegacyEtherData::SIZE]; + #[allow(clippy::ptr_offset_with_cast)] + let (address, bump_seed, trx_count, balance, generation, code_size, rw_blocked) = arrayref::array_refs![ + data, + LegacyEtherData::ADDRESS_SIZE, + LegacyEtherData::BUMP_SEED_SIZE, + LegacyEtherData::TRX_COUNT_SIZE, + LegacyEtherData::BALANCE_SIZE, + LegacyEtherData::GENERATION_SIZE, + LegacyEtherData::CODE_SIZE_SIZE, + LegacyEtherData::RW_BLOCKED_SIZE + ]; + + Self { + address: Address::from(*address), + bump_seed: bump_seed[0], + trx_count: u64::from_le_bytes(*trx_count), + balance: U256::from_le_bytes(*balance), + generation: u32::from_le_bytes(*generation), + code_size: u32::from_le_bytes(*code_size), + rw_blocked: rw_blocked[0] != 0, + } + } + + pub fn from_account(program_id: &Pubkey, account: &AccountInfo) -> Result { + crate::account::validate_tag(program_id, account, Self::TAG)?; + + let data = account.try_borrow_data()?; + Ok(Self::unpack(&data[1..])) + } + + #[allow(clippy::unused_self)] + #[must_use] + pub fn read_storage(&self, account: &AccountInfo) -> Vec<[u8; 32]> { + if self.code_size == 0 { + return vec![[0; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT]; + } + + let data = account.data.borrow(); + + let storage_offset = 1 + Self::SIZE; + let storage_len = 32 * STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT; + + let storage = &data[storage_offset..][..storage_len]; + let storage = unsafe { + // storage_len is multiple of STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT + // [u8; 32] has the same alignment as u8 + let ptr: *const [u8; 32] = storage.as_ptr().cast(); + std::slice::from_raw_parts(ptr, STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT) + }; + + storage.to_vec() + } + + #[must_use] + pub fn read_code(&self, account: &AccountInfo) -> Vec { + if self.code_size == 0 { + return Vec::new(); + } + + let data = account.data.borrow(); + + let storage_offset = 1 + Self::SIZE; + let storage_len = 32 * STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT; + + let code_offset = storage_offset + storage_len; + let code_len = self.code_size as usize; + + let code = &data[code_offset..][..code_len]; + code.to_vec() + } +} diff --git a/evm_loader/program/src/account/legacy/legacy_holder.rs b/evm_loader/program/src/account/legacy/legacy_holder.rs new file mode 100644 index 000000000..ee7e01524 --- /dev/null +++ b/evm_loader/program/src/account/legacy/legacy_holder.rs @@ -0,0 +1,70 @@ +use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; + +use crate::error::Result; + +#[derive(Debug)] +pub struct LegacyHolderData { + pub owner: Pubkey, + pub transaction_hash: [u8; 32], + pub transaction_len: usize, +} + +#[derive(Debug)] +pub struct LegacyFinalizedData { + pub owner: Pubkey, + pub transaction_hash: [u8; 32], +} + +impl LegacyHolderData { + /// Holder struct tag + const TAG: u8 = super::TAG_HOLDER_DEPRECATED; + /// Holder struct serialized size + const SIZE: usize = 32 + 32 + 8; + + /// Deserialize `Holder` struct from input data + #[must_use] + fn unpack(src: &[u8]) -> Self { + let data = arrayref::array_ref![src, 0, LegacyHolderData::SIZE]; + let (owner, hash, len) = arrayref::array_refs![data, 32, 32, 8]; + + Self { + owner: Pubkey::new_from_array(*owner), + transaction_hash: *hash, + transaction_len: usize::from_le_bytes(*len), + } + } + + pub fn from_account(program_id: &Pubkey, account: &AccountInfo) -> Result { + crate::account::validate_tag(program_id, account, Self::TAG)?; + + let data = account.try_borrow_data()?; + Ok(Self::unpack(&data[1..])) + } +} + +impl LegacyFinalizedData { + /// Finalized storage struct tag + const TAG: u8 = super::TAG_STATE_FINALIZED_DEPRECATED; + /// Finalized storage struct serialized size + const SIZE: usize = 32 + 32; + + /// Deserialize `FinalizedState` struct from input data + #[must_use] + fn unpack(src: &[u8]) -> Self { + #[allow(clippy::use_self)] + let data = arrayref::array_ref![src, 0, LegacyFinalizedData::SIZE]; + let (owner, hash) = arrayref::array_refs![data, 32, 32]; + + Self { + owner: Pubkey::new_from_array(*owner), + transaction_hash: *hash, + } + } + + pub fn from_account(program_id: &Pubkey, account: &AccountInfo) -> Result { + crate::account::validate_tag(program_id, account, Self::TAG)?; + + let data = account.try_borrow_data()?; + Ok(Self::unpack(&data[1..])) + } +} diff --git a/evm_loader/program/src/account/legacy/legacy_storage_cell.rs b/evm_loader/program/src/account/legacy/legacy_storage_cell.rs new file mode 100644 index 000000000..7ca5e9a67 --- /dev/null +++ b/evm_loader/program/src/account/legacy/legacy_storage_cell.rs @@ -0,0 +1,78 @@ +use std::mem::size_of; + +use ethnum::U256; +use solana_program::account_info::AccountInfo; +use solana_program::pubkey::Pubkey; + +use crate::account::ether_storage::Cell; +use crate::error::Result; +use crate::types::Address; + +pub struct LegacyStorageData { + pub address: Address, + pub generation: u32, + pub index: U256, +} + +impl LegacyStorageData { + /// Storage struct tag + pub const TAG: u8 = super::TAG_STORAGE_CELL_DEPRECATED; + /// Storage struct serialized size + pub const SIZE: usize = 20 + 4 + 32; + + #[must_use] + pub fn unpack(input: &[u8]) -> Self { + let data = arrayref::array_ref![input, 0, LegacyStorageData::SIZE]; + let (address, generation, index) = arrayref::array_refs![data, 20, 4, 32]; + + Self { + address: Address(*address), + generation: u32::from_le_bytes(*generation), + index: U256::from_le_bytes(*index), + } + } + + pub fn from_account(program_id: &Pubkey, account: &AccountInfo) -> Result { + crate::account::validate_tag(program_id, account, Self::TAG)?; + + let data = account.try_borrow_data()?; + Ok(Self::unpack(&data[1..])) + } + + #[allow(clippy::unused_self)] + #[must_use] + pub fn read_cells(&self, account: &AccountInfo) -> Vec { + let cells_offset = 1 + Self::SIZE; + + let data = account.data.borrow(); + let data = &data[cells_offset..]; + + static_assertions::assert_eq_align!(Cell, u8); + assert_eq!(data.len() % size_of::(), 0); + + // SAFETY: Cell has the same alignment as data + let cells = unsafe { + let ptr = data.as_ptr().cast::(); + let len = data.len() / size_of::(); + std::slice::from_raw_parts(ptr, len) + }; + + cells.to_vec() + } + + #[allow(dead_code)] + #[must_use] + pub fn read_value(&self, subindex: u8, account: &AccountInfo) -> [u8; 32] { + let cells = self.read_cells(account); + + for cell in cells { + if cell.subindex != subindex { + continue; + } + + return cell.value; + } + + [0_u8; 32] + } +} diff --git a/evm_loader/program/src/account/legacy/mod.rs b/evm_loader/program/src/account/legacy/mod.rs new file mode 100644 index 000000000..2c5784a80 --- /dev/null +++ b/evm_loader/program/src/account/legacy/mod.rs @@ -0,0 +1,221 @@ +mod legacy_ether; +mod legacy_holder; +mod legacy_storage_cell; + +pub use legacy_ether::LegacyEtherData; +pub use legacy_holder::LegacyFinalizedData; +pub use legacy_holder::LegacyHolderData; +pub use legacy_storage_cell::LegacyStorageData; + +use solana_program::system_program; +use solana_program::{account_info::AccountInfo, rent::Rent, sysvar::Sysvar}; + +use super::Holder; +use super::StateFinalizedAccount; +use super::TAG_HOLDER; +use super::TAG_STATE_FINALIZED; +use super::{AccountsDB, ContractAccount, TAG_STORAGE_CELL}; +use crate::{ + account::{BalanceAccount, StorageCell}, + account_storage::KeysCache, + error::Result, +}; + +pub const TAG_STATE_DEPRECATED: u8 = 22; +pub const TAG_STATE_FINALIZED_DEPRECATED: u8 = 31; +pub const TAG_HOLDER_DEPRECATED: u8 = 51; +pub const TAG_ACCOUNT_CONTRACT_DEPRECATED: u8 = 12; +pub const TAG_STORAGE_CELL_DEPRECATED: u8 = 42; + +fn reduce_account_size(account: &AccountInfo, required_len: usize) -> Result { + assert!(account.data_len() > required_len); + + account.realloc(required_len, false)?; + + // Return excessive lamports to the operator + let rent = Rent::get()?; + let minimum_balance = rent.minimum_balance(account.data_len()); + if account.lamports() > minimum_balance { + let value = account.lamports() - minimum_balance; + **account.lamports.borrow_mut() -= value; + + Ok(value) + } else { + Ok(0) + } +} + +fn kill_account(account: &AccountInfo) -> Result { + let value = account.lamports(); + + **account.try_borrow_mut_lamports()? = 0; + account.realloc(0, false)?; + account.assign(&system_program::ID); + + Ok(value) +} + +fn update_ether_account( + legacy_data: &LegacyEtherData, + db: &AccountsDB, + keys: &KeysCache, +) -> Result { + let pubkey = keys.contract(&crate::ID, legacy_data.address); + let account = db.get(&pubkey); + + let mut lamports_collected = 0_u64; + + if (legacy_data.generation > 0) || (legacy_data.code_size > 0) { + // This is contract account. Convert it to new format + super::validate_tag(&crate::ID, account, TAG_ACCOUNT_CONTRACT_DEPRECATED)?; + + // Read existing data + let storage = legacy_data.read_storage(account); + let code = legacy_data.read_code(account); + + // Make account smaller + let required_len = ContractAccount::required_account_size(&code); + lamports_collected += reduce_account_size(account, required_len)?; + + // Fill it with new data + account.try_borrow_mut_data()?.fill(0); + + let mut contract = ContractAccount::init( + legacy_data.address, + crate::config::DEFAULT_CHAIN_ID, + legacy_data.generation, + &code, + db, + Some(keys), + )?; + contract.set_storage_multiple_values(0, &storage); + + super::set_block(&crate::ID, account, legacy_data.rw_blocked)?; + } else { + // This is not contract. Just kill it. + lamports_collected += kill_account(account)?; + } + + if (legacy_data.balance > 0) || (legacy_data.trx_count > 0) { + // Has balance data. Create a new account + let mut balance = BalanceAccount::create( + legacy_data.address, + crate::config::DEFAULT_CHAIN_ID, + db, + Some(keys), + )?; + balance.mint(legacy_data.balance)?; + balance.increment_nonce_by(legacy_data.trx_count)?; + + super::set_block(&crate::ID, db.get(balance.pubkey()), legacy_data.rw_blocked)?; + } + + Ok(lamports_collected) +} + +fn update_storage_account( + legacy_data: &LegacyStorageData, + db: &AccountsDB, + keys: &KeysCache, +) -> Result { + let mut lamports_collected = 0_u64; + + let cell_pubkey = keys.storage_cell(&crate::ID, legacy_data.address, legacy_data.index); + let cell_account = db.get(&cell_pubkey).clone(); + + let contract_pubkey = keys.contract(&crate::ID, legacy_data.address); + let contract_account = db.get(&contract_pubkey).clone(); + let contract = ContractAccount::from_account(&crate::ID, contract_account)?; + + if contract.generation() != legacy_data.generation { + // Cell is out of date. Kill it. + lamports_collected += kill_account(&cell_account)?; + return Ok(lamports_collected); + } + + let cells = legacy_data.read_cells(&cell_account); + + // Make account smaller + let required_len = StorageCell::required_account_size(cells.len()); + lamports_collected += reduce_account_size(&cell_account, required_len)?; + + // Fill it with new data + cell_account.try_borrow_mut_data()?.fill(0); + super::set_tag(&crate::ID, &cell_account, TAG_STORAGE_CELL)?; + + let mut storage = StorageCell::from_account(&crate::ID, cell_account)?; + storage.cells_mut().copy_from_slice(&cells); + + Ok(lamports_collected) +} + +pub fn update_holder_account(account: &AccountInfo) -> Result { + match super::tag(&crate::ID, account)? { + TAG_HOLDER_DEPRECATED => { + let legacy_data = LegacyHolderData::from_account(&crate::ID, account)?; + + super::set_tag(&crate::ID, account, TAG_HOLDER)?; + super::set_block(&crate::ID, account, false)?; + + let mut holder = Holder::from_account(&crate::ID, account.clone())?; + holder.update(|data| { + data.owner = legacy_data.owner; + data.transaction_hash.fill(0); + data.transaction_len = 0; + }); + + Ok(TAG_HOLDER) + } + TAG_STATE_FINALIZED_DEPRECATED => { + let legacy_data = LegacyFinalizedData::from_account(&crate::ID, account)?; + + super::set_tag(&crate::ID, account, TAG_STATE_FINALIZED)?; + super::set_block(&crate::ID, account, false)?; + + let mut state = StateFinalizedAccount::from_account(&crate::ID, account.clone())?; + state.update(|data| { + data.owner = legacy_data.owner; + data.transaction_hash = legacy_data.transaction_hash; + }); + + Ok(TAG_STATE_FINALIZED) + } + tag => Ok(tag), + } +} + +pub fn update_legacy_accounts(accounts: &AccountsDB) -> Result { + let keys = KeysCache::new(); + + let mut lamports_collected = 0_u64; + let mut legacy_storage = Vec::with_capacity(accounts.accounts_len()); + + for account in accounts { + if !crate::check_id(account.owner) { + continue; + } + + if account.data_is_empty() { + continue; + } + + let tag = account.try_borrow_data()?[0]; + match tag { + LegacyEtherData::TAG => { + let legacy_data = LegacyEtherData::from_account(&crate::ID, account)?; + lamports_collected += update_ether_account(&legacy_data, accounts, &keys)?; + } + LegacyStorageData::TAG => { + let legacy_data = LegacyStorageData::from_account(&crate::ID, account)?; + legacy_storage.push(legacy_data); + } + _ => {} + } + } + + for data in legacy_storage { + lamports_collected += update_storage_account(&data, accounts, &keys)?; + } + + Ok(lamports_collected) +} diff --git a/evm_loader/program/src/account/mod.rs b/evm_loader/program/src/account/mod.rs index 317e61002..77863afb2 100644 --- a/evm_loader/program/src/account/mod.rs +++ b/evm_loader/program/src/account/mod.rs @@ -1,263 +1,256 @@ -use std::cell::RefMut; -use std::fmt::Debug; -use std::ops::{Deref, DerefMut}; - -use crate::error::{Error, Result}; +use crate::{ + account::legacy::{TAG_ACCOUNT_CONTRACT_DEPRECATED, TAG_STORAGE_CELL_DEPRECATED}, + error::{Error, Result}, +}; use solana_program::account_info::AccountInfo; use solana_program::pubkey::Pubkey; -use solana_program::rent::Rent; -use solana_program::sysvar::Sysvar; +use std::cell::{Ref, RefMut}; pub use crate::config::ACCOUNT_SEED_VERSION; +pub use ether_balance::BalanceAccount; +pub use ether_contract::{AllocateResult, ContractAccount}; +pub use ether_storage::{StorageCell, StorageCellAddress}; +pub use holder::Holder; pub use incinerator::Incinerator; pub use operator::Operator; +pub use state::StateAccount; +pub use state_finalized::StateFinalizedAccount; pub use treasury::{MainTreasury, Treasury}; -pub mod ether_account; -pub mod ether_contract; -pub mod ether_storage; -pub mod holder; +use self::program::System; + +mod ether_balance; +mod ether_contract; +mod ether_storage; +mod holder; mod incinerator; +pub mod legacy; mod operator; pub mod program; -pub mod state; -pub mod sysvar; +mod state; +mod state_finalized; pub mod token; mod treasury; -/* -Deprecated tags: - -const TAG_ACCOUNT_V1: u8 = 1; -const TAG_ACCOUNT_V2: u8 = 10; -const TAG_CONTRACT_V1: u8 = 2; -const TAG_CONTRACT_V2: u8 = 20; -const TAG_CONTRACT_STORAGE: u8 = 6; -const TAG_STATE_V1: u8 = 3; -const TAG_STATE_V2: u8 = 30; -const TAG_STATE_V3: u8 = 21; -const TAG_ERC20_ALLOWANCE: u8 = 4; -const TAG_FINALIZED_STATE: u8 = 5; -const TAG_HOLDER: u8 = 6; -*/ - pub const TAG_EMPTY: u8 = 0; -const TAG_ACCOUNT_V3: u8 = 12; -const TAG_STATE: u8 = 22; -const TAG_FINALIZED_STATE: u8 = 31; -const TAG_CONTRACT_STORAGE: u8 = 42; -const TAG_HOLDER: u8 = 51; - -pub type EthereumAccount<'a> = AccountData<'a, ether_account::Data>; -pub type EthereumStorage<'a> = AccountData<'a, ether_storage::Data>; -pub type State<'a> = AccountData<'a, state::Data>; -pub type FinalizedState<'a> = AccountData<'a, state::FinalizedData>; -pub type Holder<'a> = AccountData<'a, holder::Data>; - -pub trait Packable { - const TAG: u8; - const SIZE: usize; - - fn unpack(data: &[u8]) -> Self; - fn pack(&self, data: &mut [u8]); -} +pub const TAG_STATE: u8 = 23; +pub const TAG_STATE_FINALIZED: u8 = 32; +pub const TAG_HOLDER: u8 = 52; -struct AccountParts<'a> { - tag: RefMut<'a, u8>, - data: RefMut<'a, [u8]>, - remaining: RefMut<'a, [u8]>, -} +pub const TAG_ACCOUNT_BALANCE: u8 = 60; +pub const TAG_ACCOUNT_CONTRACT: u8 = 70; +pub const TAG_STORAGE_CELL: u8 = 43; -#[derive(Debug)] -pub struct AccountData<'a, T> -where - T: Packable + Debug, -{ - dirty: bool, - data: T, - pub info: &'a AccountInfo<'a>, -} +const ACCOUNT_PREFIX_LEN: usize = 2; -fn split_account_data<'a>(info: &'a AccountInfo<'a>, data_len: usize) -> Result { - if info.data_len() < 1 + data_len { - return Err(Error::AccountInvalidData(*info.key)); - } +#[inline] +fn section<'r, T>(account: &'r AccountInfo<'_>, offset: usize) -> Ref<'r, T> { + let begin = offset; + let end = begin + std::mem::size_of::(); - let account_data = info.try_borrow_mut_data()?; - let (tag, bytes) = RefMut::map_split(account_data, |d| { - d.split_first_mut().expect("data is not empty") - }); - let (data, remaining) = RefMut::map_split(bytes, |d| d.split_at_mut(data_len)); + let data = account.data.borrow(); + Ref::map(data, |d| { + let bytes = &d[begin..end]; - Ok(AccountParts { - tag, - data, - remaining, + assert_eq!(std::mem::align_of::(), 1); + assert_eq!(std::mem::size_of::(), bytes.len()); + unsafe { &*(bytes.as_ptr().cast()) } }) } -impl<'a, T> AccountData<'a, T> -where - T: Packable + Debug, -{ - pub const SIZE: usize = 1 + T::SIZE; - pub const TAG: u8 = T::TAG; +#[inline] +fn section_mut<'r, T>(account: &'r AccountInfo<'_>, offset: usize) -> RefMut<'r, T> { + let begin = offset; + let end = begin + std::mem::size_of::(); - pub fn from_account(program_id: &Pubkey, info: &'a AccountInfo<'a>) -> Result { - if info.owner != program_id { - return Err(Error::AccountInvalidOwner(*info.key, *program_id)); - } + let data = account.data.borrow_mut(); + RefMut::map(data, |d| { + let bytes = &mut d[begin..end]; - let parts = split_account_data(info, T::SIZE)?; - if *parts.tag != T::TAG { - return Err(Error::AccountInvalidTag(*info.key, T::TAG)); - } + assert_eq!(std::mem::align_of::(), 1); + assert_eq!(std::mem::size_of::(), bytes.len()); + unsafe { &mut *(bytes.as_mut_ptr().cast()) } + }) +} - let data = T::unpack(&parts.data); +pub fn tag(program_id: &Pubkey, info: &AccountInfo) -> Result { + if info.owner != program_id { + return Err(Error::AccountInvalidOwner(*info.key, *program_id)); + } - Ok(Self { - dirty: false, - data, - info, - }) + let data = info.try_borrow_data()?; + if data.len() < ACCOUNT_PREFIX_LEN { + return Err(Error::AccountInvalidData(*info.key)); } - pub fn init(program_id: &Pubkey, info: &'a AccountInfo<'a>, data: T) -> Result { - if info.owner != program_id { - return Err(Error::AccountInvalidOwner(*info.key, *program_id)); - } + Ok(data[0]) +} - if !info.is_writable { - return Err(Error::AccountNotWritable(*info.key)); - } +pub fn set_tag(program_id: &Pubkey, info: &AccountInfo, tag: u8) -> Result<()> { + assert_eq!(info.owner, program_id); - let rent = Rent::get()?; - if !rent.is_exempt(info.lamports(), info.data_len()) { - return Err(Error::AccountNotRentExempt(*info.key)); - } + let mut data = info.try_borrow_mut_data()?; + assert!(data.len() >= ACCOUNT_PREFIX_LEN); - let mut parts = split_account_data(info, T::SIZE)?; - if *parts.tag != TAG_EMPTY { - return Err(Error::AccountAlreadyInitialized(*info.key)); - } + data[0] = tag; + + Ok(()) +} - *parts.tag = T::TAG; - data.pack(&mut parts.data); +pub fn validate_tag(program_id: &Pubkey, info: &AccountInfo, tag: u8) -> Result<()> { + let account_tag = crate::account::tag(program_id, info)?; - parts.remaining.fill(0); + if account_tag == tag { + Ok(()) + } else { + Err(Error::AccountInvalidTag(*info.key, tag)) + } +} + +pub fn is_blocked(program_id: &Pubkey, info: &AccountInfo) -> Result { + if info.owner != program_id { + return Err(Error::AccountInvalidOwner(*info.key, *program_id)); + } - Ok(Self { - dirty: false, - data, - info, - }) + let data = info.try_borrow_data()?; + if data.len() < ACCOUNT_PREFIX_LEN { + return Err(Error::AccountInvalidData(*info.key)); } - /// # Safety - /// *Delete account*. Transfer lamports to the operator. - /// All data stored in the account will be lost - pub unsafe fn suicide(mut self, operator: &Operator<'a>) { - let info = self.info; + Ok(data[1] == 1) +} + +#[inline] +fn set_block(program_id: &Pubkey, info: &AccountInfo, block: bool) -> Result<()> { + assert_eq!(info.owner, program_id); - self.dirty = false; // Do not save data into solana account - core::mem::drop(self); // Release borrowed account data + let mut data = info.try_borrow_mut_data()?; + assert!(data.len() >= ACCOUNT_PREFIX_LEN); + assert!(data[0] != TAG_ACCOUNT_CONTRACT_DEPRECATED && data[0] != TAG_STORAGE_CELL_DEPRECATED); - crate::account::delete(info, operator); + if block && (data[1] != 0) { + return Err(Error::AccountBlocked(*info.key)); } - /// # Safety - /// Should be used with care. Can corrupt account data - pub unsafe fn replace(mut self, data: U) -> Result> - where - U: Packable + Debug, - { - debug_print!("replace account data from {:?} to {:?}", &self.data, &data); - let info = self.info; - - if !info.is_writable { - return Err(Error::AccountNotWritable(*info.key)); - } + data[1] = block.into(); - self.dirty = false; // Do not save data into solana account - core::mem::drop(self); // Release borrowed account data + Ok(()) +} - let mut parts = split_account_data(info, U::SIZE)?; +pub fn block(program_id: &Pubkey, info: &AccountInfo) -> Result<()> { + set_block(program_id, info, true) +} - *parts.tag = U::TAG; - data.pack(&mut parts.data); +pub fn unblock(program_id: &Pubkey, info: &AccountInfo) -> Result<()> { + set_block(program_id, info, false) +} - parts.remaining.fill(0); +/// # Safety +/// *Permanently delete all data* in the account. Transfer lamports to the operator. +pub unsafe fn delete(account: &AccountInfo, operator: &Operator) { + debug_print!("DELETE ACCOUNT {}", account.key); - Ok(AccountData { - dirty: false, - data, - info, - }) - } + **operator.lamports.borrow_mut() += account.lamports(); + **account.lamports.borrow_mut() = 0; + + let mut data = account.data.borrow_mut(); + data.fill(0); } -impl<'a, T> Deref for AccountData<'a, T> -where - T: Packable + Debug, -{ - type Target = T; +pub struct AccountsDB<'a> { + sorted_accounts: Vec>, + operator: Operator<'a>, + operator_balance: Option>, + system: Option>, + treasury: Option>, +} - fn deref(&self) -> &Self::Target { - &self.data +impl<'a> AccountsDB<'a> { + #[must_use] + pub fn new( + accounts: &[AccountInfo<'a>], + operator: Operator<'a>, + operator_balance: Option>, + system: Option>, + treasury: Option>, + ) -> Self { + let mut sorted_accounts = accounts.to_vec(); + sorted_accounts.sort_unstable_by_key(|a| a.key); + sorted_accounts.dedup_by_key(|a| a.key); + + Self { + sorted_accounts, + operator, + operator_balance, + system, + treasury, + } } -} -impl<'a, T> DerefMut for AccountData<'a, T> -where - T: Packable + Debug, -{ - fn deref_mut(&mut self) -> &mut Self::Target { - self.dirty = true; - &mut self.data + #[must_use] + pub fn accounts_len(&self) -> usize { + self.sorted_accounts.len() } -} -impl<'a, T> Drop for AccountData<'a, T> -where - T: Packable + Debug, -{ - fn drop(&mut self) { - if !self.dirty { - return; + #[must_use] + pub fn system(&self) -> &System<'a> { + if let Some(system) = &self.system { + return system; } - debug_print!("Save into solana account {:?}", self.data); - assert!(self.info.is_writable); + panic!("System Account must be present in the transaction"); + } - let mut parts = - split_account_data(self.info, T::SIZE).expect("Account have incorrect size"); + #[must_use] + pub fn treasury(&self) -> &Treasury<'a> { + if let Some(treasury) = &self.treasury { + return treasury; + } - self.data.pack(&mut parts.data); + panic!("Treasury Account must be present in the transaction"); } -} -pub fn tag(program_id: &Pubkey, info: &AccountInfo) -> Result { - if info.owner != program_id { - return Err(Error::AccountInvalidOwner(*info.key, *program_id)); + #[must_use] + pub fn operator(&self) -> &Operator<'a> { + &self.operator } - let data = info.try_borrow_data()?; - if data.is_empty() { - return Err(Error::AccountInvalidData(*info.key)); + #[must_use] + pub fn operator_balance(&mut self) -> &mut BalanceAccount<'a> { + if let Some(operator_balance) = &mut self.operator_balance { + return operator_balance; + } + + panic!("Operator Balance Account must be present in the transaction"); } - Ok(data[0]) -} + #[must_use] + pub fn operator_key(&self) -> Pubkey { + *self.operator.key + } -/// # Safety -/// *Permanently delete all data* in the account. Transfer lamports to the operator. -pub unsafe fn delete(account: &AccountInfo, operator: &Operator) { - debug_print!("DELETE ACCOUNT {}", account.key); + #[must_use] + pub fn operator_info(&self) -> &AccountInfo<'a> { + &self.operator + } - **operator.lamports.borrow_mut() += account.lamports(); - **account.lamports.borrow_mut() = 0; + #[must_use] + pub fn get(&self, pubkey: &Pubkey) -> &AccountInfo<'a> { + let Ok(index) = self.sorted_accounts.binary_search_by_key(&pubkey, |a| a.key) else { + panic!("address {pubkey} must be present in the transaction"); + }; - let mut data = account.data.borrow_mut(); - data.fill(0); + // We just got an 'index' from the binary_search over this vector. + unsafe { self.sorted_accounts.get_unchecked(index) } + } +} + +impl<'a, 'r> IntoIterator for &'r AccountsDB<'a> { + type Item = &'r AccountInfo<'a>; + type IntoIter = std::slice::Iter<'r, AccountInfo<'a>>; + + fn into_iter(self) -> Self::IntoIter { + self.sorted_accounts.iter() + } } diff --git a/evm_loader/program/src/account/operator.rs b/evm_loader/program/src/account/operator.rs index aa9318b70..82581df26 100644 --- a/evm_loader/program/src/account/operator.rs +++ b/evm_loader/program/src/account/operator.rs @@ -3,6 +3,7 @@ use solana_program::account_info::AccountInfo; use solana_program::program_error::ProgramError; use std::ops::Deref; +#[derive(Clone)] pub struct Operator<'a> { pub info: &'a AccountInfo<'a>, } diff --git a/evm_loader/program/src/account/program.rs b/evm_loader/program/src/account/program.rs index 509585630..2edb49a9d 100644 --- a/evm_loader/program/src/account/program.rs +++ b/evm_loader/program/src/account/program.rs @@ -1,14 +1,9 @@ -use super::{EthereumAccount, Operator, ACCOUNT_SEED_VERSION}; +use super::Operator; use solana_program::account_info::AccountInfo; use solana_program::program::{invoke_signed_unchecked, invoke_unchecked}; use solana_program::program_error::ProgramError; use solana_program::pubkey::Pubkey; -use solana_program::{ - program::{invoke, invoke_signed}, - rent::Rent, - system_instruction, - sysvar::Sysvar, -}; +use solana_program::{rent::Rent, system_instruction, sysvar::Sysvar}; use std::convert::From; use std::ops::Deref; @@ -37,12 +32,6 @@ impl<'a> Deref for Neon<'a> { pub struct System<'a>(&'a AccountInfo<'a>); -impl<'a> From<&'a AccountInfo<'a>> for System<'a> { - fn from(info: &'a AccountInfo<'a>) -> Self { - Self(info) - } -} - impl<'a> From<&System<'a>> for &'a AccountInfo<'a> { fn from(f: &System<'a>) -> Self { f.0 @@ -60,7 +49,7 @@ impl<'a> System<'a> { pub fn create_pda_account( &self, - program_id: &Pubkey, + owner: &Pubkey, payer: &Operator<'a>, new_account: &AccountInfo<'a>, new_account_seeds: &[&[u8]], @@ -73,53 +62,50 @@ impl<'a> System<'a> { let required_lamports = minimum_balance.saturating_sub(new_account.lamports()); if required_lamports > 0 { - invoke( + invoke_unchecked( &system_instruction::transfer(payer.key, new_account.key, required_lamports), - &[(*payer).clone(), new_account.clone(), self.0.clone()], + &[payer.info.clone(), new_account.clone(), self.0.clone()], )?; } - invoke_signed( + invoke_signed_unchecked( &system_instruction::allocate(new_account.key, space as u64), &[new_account.clone(), self.0.clone()], &[new_account_seeds], )?; - invoke_signed( - &system_instruction::assign(new_account.key, program_id), + invoke_signed_unchecked( + &system_instruction::assign(new_account.key, owner), &[new_account.clone(), self.0.clone()], &[new_account_seeds], ) } else { - invoke_signed( + invoke_signed_unchecked( &system_instruction::create_account( payer.key, new_account.key, minimum_balance, space as u64, - program_id, + owner, ), - &[(*payer).clone(), new_account.clone(), self.0.clone()], + &[payer.info.clone(), new_account.clone(), self.0.clone()], &[new_account_seeds], ) } } + #[allow(clippy::too_many_arguments)] pub fn create_account_with_seed( &self, - payer: &Operator<'a>, - base: &EthereumAccount<'a>, owner: &Pubkey, + payer: &Operator<'a>, + base: &AccountInfo<'a>, + signer_seeds: &[&[u8]], new_account: &AccountInfo<'a>, seed: &str, space: usize, ) -> Result<(), ProgramError> { let minimum_balance = Rent::get()?.minimum_balance(space).max(1); - let signer_seeds: &[&[u8]] = &[ - &[ACCOUNT_SEED_VERSION], - base.address.as_bytes(), - &[base.bump_seed], - ]; if new_account.lamports() > 0 { let required_lamports = minimum_balance.saturating_sub(new_account.lamports()); @@ -127,25 +113,25 @@ impl<'a> System<'a> { if required_lamports > 0 { invoke_unchecked( &system_instruction::transfer(payer.key, new_account.key, required_lamports), - &[(*payer).clone(), new_account.clone(), self.0.clone()], + &[payer.info.clone(), new_account.clone(), self.0.clone()], )?; } invoke_signed_unchecked( &system_instruction::allocate_with_seed( new_account.key, - base.info.key, + base.key, seed, space as u64, owner, ), - &[new_account.clone(), base.info.clone(), self.0.clone()], + &[new_account.clone(), base.clone(), self.0.clone()], &[signer_seeds], )?; invoke_signed_unchecked( - &system_instruction::assign_with_seed(new_account.key, base.info.key, seed, owner), - &[new_account.clone(), base.info.clone(), self.0.clone()], + &system_instruction::assign_with_seed(new_account.key, base.key, seed, owner), + &[new_account.clone(), base.clone(), self.0.clone()], &[signer_seeds], ) } else { @@ -153,16 +139,16 @@ impl<'a> System<'a> { &system_instruction::create_account_with_seed( payer.key, new_account.key, - base.info.key, + base.key, seed, minimum_balance, space as u64, owner, ), &[ - (*payer).clone(), + payer.info.clone(), new_account.clone(), - base.info.clone(), + base.clone(), self.0.clone(), ], &[signer_seeds], @@ -183,9 +169,9 @@ impl<'a> System<'a> { target.key ); - invoke( + invoke_unchecked( &system_instruction::transfer(source.key, target.key, lamports), - &[(*source).clone(), target.clone(), self.0.clone()], + &[source.info.clone(), target.clone(), self.0.clone()], ) } } @@ -215,7 +201,7 @@ impl<'a> Token<'a> { mint: &AccountInfo<'a>, owner: &AccountInfo<'a>, ) -> Result<(), ProgramError> { - invoke( + invoke_unchecked( &spl_token::instruction::initialize_account3( self.0.key, account.key, diff --git a/evm_loader/program/src/account/state.rs b/evm_loader/program/src/account/state.rs index 8a02559f7..64e772ac3 100644 --- a/evm_loader/program/src/account/state.rs +++ b/evm_loader/program/src/account/state.rs @@ -1,16 +1,29 @@ -use super::Packable; -use crate::types::Address; -use arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs}; +use std::cell::{Ref, RefMut}; +use std::mem::size_of; + +use crate::config::{GAS_LIMIT_MULTIPLIER_NO_CHAINID, OPERATOR_PRIORITY_SLOTS}; +use crate::error::{Error, Result}; +use crate::types::{Address, Transaction}; use ethnum::U256; -use solana_program::pubkey::Pubkey; +use solana_program::clock::Clock; +use solana_program::program_error::ProgramError; +use solana_program::sysvar::Sysvar; +use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; + +use super::{ + AccountsDB, BalanceAccount, Operator, ACCOUNT_PREFIX_LEN, TAG_EMPTY, TAG_HOLDER, TAG_STATE, + TAG_STATE_FINALIZED, +}; /// Storage data account to store execution metainfo between steps for iterative execution -#[derive(Debug)] -pub struct Data { +#[repr(C, packed)] +pub struct Header { pub owner: Pubkey, pub transaction_hash: [u8; 32], /// Ethereum transaction caller address - pub caller: Address, + pub origin: Address, + /// Ethereum transaction chain_id + pub chain_id: u64, /// Ethereum transaction gas limit pub gas_limit: U256, /// Ethereum transaction gas price @@ -29,111 +42,332 @@ pub struct Data { pub evm_machine_len: usize, } -/// Storage account data for the finalized transaction state -#[derive(Debug)] -pub struct FinalizedData { - pub owner: Pubkey, - pub transaction_hash: [u8; 32], +#[repr(C, packed)] +pub struct BlockedAccount { + pub is_writable: bool, + pub blocked: bool, + pub key: Pubkey, } -impl Packable for Data { - /// Storage struct tag - const TAG: u8 = super::TAG_STATE; - /// Storage struct serialized size - const SIZE: usize = 32 + 32 + 20 + 32 + 32 + 32 + 32 + 8 + 8 + 8 + 8; - - /// Deserialize `Storage` struct from input data - #[must_use] - fn unpack(src: &[u8]) -> Self { - #[allow(clippy::use_self)] - let data = array_ref![src, 0, Data::SIZE]; - let ( - owner, - hash, - caller, - gas_limit, - gas_price, - gas_used, - operator, - slot, - accounts_len, - evm_state_len, - evm_machine_len, - ) = array_refs![data, 32, 32, 20, 32, 32, 32, 32, 8, 8, 8, 8]; - - Self { - owner: Pubkey::new_from_array(*owner), - transaction_hash: *hash, - caller: Address::from(*caller), - gas_limit: U256::from_le_bytes(*gas_limit), - gas_price: U256::from_le_bytes(*gas_price), - gas_used: U256::from_le_bytes(*gas_used), - operator: Pubkey::new_from_array(*operator), - slot: u64::from_le_bytes(*slot), - accounts_len: usize::from_le_bytes(*accounts_len), - evm_state_len: usize::from_le_bytes(*evm_state_len), - evm_machine_len: usize::from_le_bytes(*evm_machine_len), +pub struct StateAccount<'a> { + account: AccountInfo<'a>, +} + +const HEADER_OFFSET: usize = ACCOUNT_PREFIX_LEN; +const BLOCKED_ACCOUNTS_OFFSET: usize = HEADER_OFFSET + size_of::
(); + +impl<'a> StateAccount<'a> { + pub fn from_account(program_id: &Pubkey, account: AccountInfo<'a>) -> Result { + super::validate_tag(program_id, &account, TAG_STATE)?; + + Ok(Self { account }) + } + + pub fn new( + program_id: &Pubkey, + info: AccountInfo<'a>, + accounts: &AccountsDB<'a>, + origin: Address, + trx: &Transaction, + ) -> Result { + let tag = super::tag(program_id, &info)?; + if matches!(tag, TAG_HOLDER | TAG_STATE_FINALIZED) { + super::set_tag(program_id, &info, TAG_STATE)?; + } + + let mut state = Self::from_account(program_id, info)?; + state.validate_owner(accounts.operator())?; + + if (tag == TAG_STATE_FINALIZED) && (state.trx_hash() == trx.hash) { + return Err(Error::StorageAccountFinalized); + } + + // Set header + { + let mut header = state.header_mut(); + header.transaction_hash = trx.hash(); + header.origin = origin; + header.chain_id = trx.chain_id().unwrap_or(crate::config::DEFAULT_CHAIN_ID); + header.gas_limit = trx.gas_limit(); + header.gas_price = trx.gas_price(); + header.gas_used = U256::ZERO; + header.operator = accounts.operator_key(); + header.slot = Clock::get()?.slot; + header.accounts_len = accounts.accounts_len(); + header.evm_machine_len = 0; + header.evm_state_len = 0; + } + // Block accounts + for (block, account) in state.blocked_accounts_mut().iter_mut().zip(accounts) { + block.is_writable = account.is_writable; + block.key = *account.key; + if (account.owner == program_id) && !account.data_is_empty() { + super::block(program_id, account)?; + block.blocked = true; + } else { + block.blocked = false; + } } + + Ok(state) } - /// Serialize `Storage` struct into given destination - fn pack(&self, dst: &mut [u8]) { - #[allow(clippy::use_self)] - let data = array_mut_ref![dst, 0, Data::SIZE]; - let ( - owner, - hash, - caller, - gas_limit, - gas_price, - gas_used, - operator, - slot, - accounts_len, - evm_state_len, - evm_machine_len, - ) = mut_array_refs![data, 32, 32, 20, 32, 32, 32, 32, 8, 8, 8, 8]; - - owner.copy_from_slice(self.owner.as_ref()); - hash.copy_from_slice(&self.transaction_hash); - *caller = self.caller.into(); - *gas_limit = self.gas_limit.to_le_bytes(); - *gas_price = self.gas_price.to_le_bytes(); - *gas_used = self.gas_used.to_le_bytes(); - operator.copy_from_slice(self.operator.as_ref()); - *slot = self.slot.to_le_bytes(); - *accounts_len = self.accounts_len.to_le_bytes(); - *evm_state_len = self.evm_state_len.to_le_bytes(); - *evm_machine_len = self.evm_machine_len.to_le_bytes(); + pub fn restore( + program_id: &Pubkey, + info: AccountInfo<'a>, + accounts: &AccountsDB, + is_canceling: bool, + ) -> Result { + let mut state = Self::from_account(program_id, info)?; + + if state.blocked_accounts_len() != accounts.accounts_len() { + return Err(ProgramError::NotEnoughAccountKeys.into()); + } + + // Check blocked accounts + for (block, account) in state.blocked_accounts().iter().zip(accounts) { + if &block.key != account.key { + return Err(Error::AccountInvalidKey(*account.key, block.key)); + } + + if block.is_writable && !account.is_writable { + return Err(Error::AccountNotWritable(*account.key)); + } + + if !is_canceling && (account.owner == program_id) && !block.blocked { + if super::is_blocked(program_id, account)? { + return Err(Error::AccountCreatedByAnotherTransaction(*account.key)); + } + + super::validate_tag(program_id, account, TAG_EMPTY) + .map_err(|_| Error::AccountCreatedByAnotherTransaction(*account.key))?; + } + } + + state.update_priority_operator(&accounts.operator)?; + + Ok(state) } -} -impl Packable for FinalizedData { - /// Finalized storage struct tag - const TAG: u8 = super::TAG_FINALIZED_STATE; - /// Finalized storage struct serialized size - const SIZE: usize = 32 + 32; + pub fn finalize(self, program_id: &Pubkey, accounts: &AccountsDB) -> Result<()> { + debug_print!("Finalize Storage {}", self.account.key); + + // Unblock accounts + for (block, account) in self.blocked_accounts().iter().zip(accounts) { + if &block.key != account.key { + return Err(Error::AccountInvalidKey(*account.key, block.key)); + } + + if !block.blocked { + continue; + } + + super::unblock(program_id, account)?; + } + + // Change tag to finalized + let account = self.account.clone(); + std::mem::drop(self); + + super::set_tag(account.owner, &account, TAG_STATE_FINALIZED) + } + + #[inline] + #[must_use] + fn header(&self) -> Ref
{ + super::section(&self.account, HEADER_OFFSET) + } + + #[inline] + #[must_use] + fn header_mut(&mut self) -> RefMut
{ + super::section_mut(&self.account, HEADER_OFFSET) + } + + #[inline] + #[must_use] + fn blocked_accounts_len(&self) -> usize { + self.header().accounts_len + } + + #[inline] + #[must_use] + pub fn blocked_accounts(&self) -> Ref<[BlockedAccount]> { + let accounts_len = self.blocked_accounts_len(); + let accounts_len_bytes = accounts_len * size_of::(); + + let data = self.account.data.borrow(); + Ref::map(data, |d| { + let bytes = &d[BLOCKED_ACCOUNTS_OFFSET..][..accounts_len_bytes]; + + unsafe { + let ptr = bytes.as_ptr().cast(); + std::slice::from_raw_parts(ptr, accounts_len) + } + }) + } + + #[inline] + #[must_use] + fn blocked_accounts_mut(&mut self) -> RefMut<[BlockedAccount]> { + let accounts_len = self.blocked_accounts_len(); + let accounts_len_bytes = accounts_len * size_of::(); + + let data = self.account.data.borrow_mut(); + RefMut::map(data, |d| { + let bytes: &mut [u8] = &mut d[BLOCKED_ACCOUNTS_OFFSET..][..accounts_len_bytes]; + + unsafe { + let ptr = bytes.as_mut_ptr().cast(); + std::slice::from_raw_parts_mut(ptr, accounts_len) + } + }) + } + + #[must_use] + pub fn buffer(&self) -> Ref<[u8]> { + let accounts_len_bytes = self.blocked_accounts_len() * size_of::(); + let buffer_offset = BLOCKED_ACCOUNTS_OFFSET + accounts_len_bytes; + + let data = self.account.data.borrow(); + Ref::map(data, |d| &d[buffer_offset..]) + } + + #[must_use] + pub fn buffer_mut(&mut self) -> RefMut<[u8]> { + let accounts_len_bytes = self.blocked_accounts_len() * size_of::(); + let buffer_offset = BLOCKED_ACCOUNTS_OFFSET + accounts_len_bytes; + + let data = self.account.data.borrow_mut(); + RefMut::map(data, |d| &mut d[buffer_offset..]) + } + + #[must_use] + pub fn buffer_variables(&self) -> (usize, usize) { + let header = self.header(); + (header.evm_state_len, header.evm_machine_len) + } + + pub fn set_buffer_variables(&mut self, evm_state_len: usize, evm_machine_len: usize) { + let mut header = self.header_mut(); + header.evm_state_len = evm_state_len; + header.evm_machine_len = evm_machine_len; + } + + #[must_use] + pub fn owner(&self) -> Pubkey { + self.header().owner + } + + fn validate_owner(&self, operator: &Operator) -> Result<()> { + let owner = self.owner(); + let operator = *operator.key; + + if owner != operator { + return Err(Error::HolderInvalidOwner(owner, operator)); + } + + Ok(()) + } + + fn update_priority_operator(&mut self, operator: &Operator) -> Result<()> { + let mut header = self.header_mut(); + + if operator.key != &header.operator { + let clock = Clock::get()?; + if (clock.slot - header.slot) <= OPERATOR_PRIORITY_SLOTS { + return Err(Error::HolderInvalidOwner(header.owner, *operator.key)); + } + + header.operator = *operator.key; + header.slot = clock.slot; + } + + Ok(()) + } + + #[must_use] + pub fn trx_hash(&self) -> [u8; 32] { + self.header().transaction_hash + } + + #[must_use] + pub fn trx_origin(&self) -> Address { + self.header().origin + } + + #[must_use] + pub fn trx_chain_id(&self) -> u64 { + self.header().chain_id + } + + #[must_use] + pub fn trx_gas_price(&self) -> U256 { + self.header().gas_price + } + + #[must_use] + pub fn trx_gas_limit(&self) -> U256 { + self.header().gas_limit + } + + pub fn gas_limit_in_tokens(&self) -> Result { + let header = self.header(); + header + .gas_limit + .checked_mul(header.gas_price) + .ok_or(Error::IntegerOverflow) + } + + #[must_use] + pub fn gas_used(&self) -> U256 { + self.header().gas_used + } - /// Deserialize `FinalizedState` struct from input data #[must_use] - fn unpack(src: &[u8]) -> Self { - #[allow(clippy::use_self)] - let data = array_ref![src, 0, FinalizedData::SIZE]; - let (owner, hash) = array_refs![data, 32, 32]; + pub fn gas_available(&self) -> U256 { + let header = self.header(); + header.gas_limit.saturating_sub(header.gas_used) + } + + pub fn consume_gas(&mut self, amount: U256, receiver: &mut BalanceAccount) -> Result<()> { + if amount == U256::ZERO { + return Ok(()); + } + + let mut header = self.header_mut(); + + if receiver.chain_id() != header.chain_id { + return Err(Error::GasReceiverInvalidChainId); + } + + let total_gas_used = header.gas_used.saturating_add(amount); + let gas_limit = header.gas_limit; - Self { - owner: Pubkey::new_from_array(*owner), - transaction_hash: *hash, + if total_gas_used > gas_limit { + return Err(Error::OutOfGas(gas_limit, total_gas_used)); } + + header.gas_used = total_gas_used; + + let tokens = amount + .checked_mul(header.gas_price) + .ok_or(Error::IntegerOverflow)?; + receiver.mint(tokens) + } + + pub fn refund_unused_gas(&mut self, origin: &mut BalanceAccount) -> Result<()> { + assert!(origin.chain_id() == self.trx_chain_id()); + assert!(origin.address == Some(self.trx_origin())); + + let unused_gas = self.gas_available(); + self.consume_gas(unused_gas, origin) } - /// Serialize `FinalizedState` struct into given destination - fn pack(&self, dst: &mut [u8]) { - #[allow(clippy::use_self)] - let data = array_mut_ref![dst, 0, FinalizedData::SIZE]; - let (owner, hash) = mut_array_refs![data, 32, 32]; + pub fn use_gas_limit_multiplier(&mut self) { + let mut header = self.header_mut(); - owner.copy_from_slice(self.owner.as_ref()); - hash.copy_from_slice(&self.transaction_hash); + let gas_multiplier = U256::from(GAS_LIMIT_MULTIPLIER_NO_CHAINID); + header.gas_limit = header.gas_limit.saturating_mul(gas_multiplier); } } diff --git a/evm_loader/program/src/account/state_finalized.rs b/evm_loader/program/src/account/state_finalized.rs new file mode 100644 index 000000000..5e73c9801 --- /dev/null +++ b/evm_loader/program/src/account/state_finalized.rs @@ -0,0 +1,55 @@ +use std::cell::{Ref, RefMut}; + +use super::{ACCOUNT_PREFIX_LEN, TAG_STATE_FINALIZED}; +use crate::error::Result; +use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; + +/// Storage data account to store execution metainfo between steps for iterative execution +#[repr(C, packed)] +pub struct Header { + pub owner: Pubkey, + pub transaction_hash: [u8; 32], +} + +pub struct StateFinalizedAccount<'a> { + account: AccountInfo<'a>, +} + +const HEADER_OFFSET: usize = ACCOUNT_PREFIX_LEN; + +impl<'a> StateFinalizedAccount<'a> { + pub fn from_account(program_id: &Pubkey, account: AccountInfo<'a>) -> Result { + super::validate_tag(program_id, &account, TAG_STATE_FINALIZED)?; + Ok(Self { account }) + } + + #[inline] + #[must_use] + fn header(&self) -> Ref
{ + super::section(&self.account, HEADER_OFFSET) + } + + #[inline] + #[must_use] + fn header_mut(&mut self) -> RefMut
{ + super::section_mut(&self.account, HEADER_OFFSET) + } + + pub fn update(&mut self, f: F) + where + F: FnOnce(&mut Header), + { + let mut header = self.header_mut(); + f(&mut header); + } + + #[must_use] + pub fn owner(&self) -> Pubkey { + self.header().owner + } + + #[must_use] + pub fn trx_hash(&self) -> [u8; 32] { + self.header().transaction_hash + } +} diff --git a/evm_loader/program/src/account/sysvar.rs b/evm_loader/program/src/account/sysvar.rs deleted file mode 100644 index 414ba48f9..000000000 --- a/evm_loader/program/src/account/sysvar.rs +++ /dev/null @@ -1,16 +0,0 @@ -use solana_program::account_info::AccountInfo; -use solana_program::program_error::ProgramError; - -pub struct Instructions<'a> { - pub info: &'a AccountInfo<'a>, -} - -impl<'a> Instructions<'a> { - pub fn from_account(info: &'a AccountInfo<'a>) -> Result { - if !solana_program::sysvar::instructions::check_id(info.key) { - return Err!(ProgramError::InvalidArgument; "Account {} - is not sysvar instructions", info.key); - } - - Ok(Self { info }) - } -} diff --git a/evm_loader/program/src/account/token.rs b/evm_loader/program/src/account/token.rs index 9ba6ec152..dc7553de0 100644 --- a/evm_loader/program/src/account/token.rs +++ b/evm_loader/program/src/account/token.rs @@ -19,6 +19,10 @@ impl<'a, T: Pack + IsInitialized> Account<'a, T> { Ok(Self { info, data }) } + + pub fn into_data(self) -> T { + self.data + } } impl<'a, T: Pack + IsInitialized> Deref for Account<'a, T> { diff --git a/evm_loader/program/src/account/treasury.rs b/evm_loader/program/src/account/treasury.rs index fcecc5354..9f090e7bc 100644 --- a/evm_loader/program/src/account/treasury.rs +++ b/evm_loader/program/src/account/treasury.rs @@ -1,7 +1,6 @@ use crate::config::TREASURY_POOL_SEED; -use solana_program::{ - account_info::AccountInfo, program_error::ProgramError, program_pack::Pack, pubkey::Pubkey, -}; +use crate::error::{Error, Result}; +use solana_program::{account_info::AccountInfo, program_pack::Pack, pubkey::Pubkey}; use std::ops::Deref; pub struct Treasury<'a> { @@ -19,10 +18,10 @@ impl<'a> Treasury<'a> { program_id: &Pubkey, index: u32, info: &'a AccountInfo<'a>, - ) -> Result { + ) -> Result { let (expected_key, bump_seed) = Treasury::address(program_id, index); if *info.key != expected_key { - return Err!(ProgramError::InvalidArgument; "Account {} - invalid treasure account", info.key); + return Err(Error::AccountInvalidKey(*info.key, expected_key)); } Ok(Self { info, bump_seed }) @@ -51,22 +50,22 @@ impl<'a> Deref for Treasury<'a> { } impl<'a> MainTreasury<'a> { - pub fn from_account( - program_id: &Pubkey, - info: &'a AccountInfo<'a>, - ) -> Result { + pub fn from_account(program_id: &Pubkey, info: &'a AccountInfo<'a>) -> Result { let (expected_key, bump_seed) = MainTreasury::address(program_id); if *info.key != expected_key { - return Err!(ProgramError::InvalidArgument; "Account {} - invalid main treasure account", info.key); + return Err(Error::AccountInvalidKey(*info.key, expected_key)); } if *info.owner != spl_token::id() { - return Err!(ProgramError::InvalidArgument; "Account {} - invalid owner", info.key); + return Err(Error::AccountInvalidOwner(*info.key, spl_token::id())); } let account = spl_token::state::Account::unpack(&info.data.borrow())?; if account.mint != spl_token::native_mint::id() { - return Err!(ProgramError::InvalidArgument; "Account {} - not wrapped SOL spl_token account", info.key); + return Err(Error::Custom(format!( + "Account {} - not wrapped SOL spl_token account", + info.key + ))); } Ok(Self { info, bump_seed }) diff --git a/evm_loader/program/src/state_account.rs b/evm_loader/program/src/state_account.rs deleted file mode 100644 index 7e4c520c7..000000000 --- a/evm_loader/program/src/state_account.rs +++ /dev/null @@ -1,325 +0,0 @@ -#[cfg(target_os = "solana")] -use { - crate::account::program, - crate::types::{Address, Transaction}, - ethnum::U256, -}; - -use { - crate::account::EthereumAccount, - crate::account::Holder, - crate::config::OPERATOR_PRIORITY_SLOTS, - crate::error::Error, - solana_program::account_info::AccountInfo, - solana_program::clock::Clock, - solana_program::sysvar::Sysvar, - std::cell::{Ref, RefMut}, -}; - -use crate::account::{FinalizedState, Incinerator, Operator, State}; -use solana_program::{program_error::ProgramError, pubkey::Pubkey}; - -const ACCOUNT_CHUNK_LEN: usize = 1 + 1 + 32; - -pub enum Deposit<'a> { - ReturnToOperator(Operator<'a>), - Burn(Incinerator<'a>), -} - -pub struct BlockedAccountMeta { - pub key: Pubkey, - pub exists: bool, - pub is_writable: bool, -} - -pub type BlockedAccounts = Vec; - -impl<'a> FinalizedState<'a> { - #[must_use] - pub fn is_outdated(&self, transaction_hash: &[u8; 32]) -> bool { - self.transaction_hash.ne(transaction_hash) - } -} - -impl<'a> State<'a> { - #[cfg(target_os = "solana")] - pub fn new( - program_id: &'a Pubkey, - info: &'a AccountInfo<'a>, - accounts: &crate::instruction::transaction_step::Accounts<'a>, - caller: Address, - trx: &Transaction, - ) -> Result { - let owner = match crate::account::tag(program_id, info)? { - Holder::TAG => { - let holder = Holder::from_account(program_id, info)?; - holder.owner - } - FinalizedState::TAG => { - let finalized_storage = FinalizedState::from_account(program_id, info)?; - if !finalized_storage.is_outdated(&trx.hash()) { - return Err!(Error::StorageAccountFinalized.into(); "Transaction already finalized"); - } - - finalized_storage.owner - } - _ => { - return Err!(ProgramError::InvalidAccountData; "Account {} - expected finalized storage or holder", info.key) - } - }; - - if &owner != accounts.operator.key { - return Err!(ProgramError::InvalidAccountData; "Account {} - invalid state account owner", info.key); - } - - let data = crate::account::state::Data { - owner, - transaction_hash: trx.hash(), - caller, - gas_limit: trx.gas_limit(), - gas_price: trx.gas_price(), - gas_used: U256::ZERO, - operator: *accounts.operator.key, - slot: Clock::get()?.slot, - accounts_len: accounts.remaining_accounts.len(), - evm_state_len: 0, - evm_machine_len: 0, - }; - - info.data.borrow_mut()[0] = 0_u8; - let mut storage = State::init(program_id, info, data)?; - - storage.make_deposit(&accounts.system_program, &accounts.operator)?; - storage.write_blocked_accounts(program_id, accounts.remaining_accounts)?; - Ok(storage) - } - - pub fn restore( - program_id: &Pubkey, - info: &'a AccountInfo<'a>, - operator: &Operator, - remaining_accounts: &[AccountInfo], - is_cancelling: bool, - ) -> Result<(Self, BlockedAccounts), ProgramError> { - let account_tag = crate::account::tag(program_id, info)?; - if account_tag == FinalizedState::TAG { - return Err!(Error::StorageAccountFinalized.into(); "Account {} - Storage Finalized", info.key); - } - if account_tag == Holder::TAG { - return Err!(Error::StorageAccountUninitialized.into(); "Account {} - Storage Uninitialized", info.key); - } - - let mut storage = State::from_account(program_id, info)?; - let blocked_accounts = - storage.check_blocked_accounts(program_id, remaining_accounts, is_cancelling)?; - - let clock = Clock::get()?; - if (*operator.key != storage.operator) - && ((clock.slot - storage.slot) <= OPERATOR_PRIORITY_SLOTS) - { - return Err!(ProgramError::InvalidAccountData; "operator.key != storage.operator"); - } - - if storage.operator != *operator.key { - storage.operator = *operator.key; - storage.slot = clock.slot; - } - - Ok((storage, blocked_accounts)) - } - - pub fn finalize(self, deposit: Deposit<'a>) -> Result, ProgramError> { - debug_print!("Finalize Storage {}", self.info.key); - - match deposit { - Deposit::ReturnToOperator(operator) => self.withdraw_deposit(&operator), - Deposit::Burn(incinerator) => self.withdraw_deposit(&incinerator), - }?; - - let finalized_data = crate::account::state::FinalizedData { - owner: self.owner, - transaction_hash: self.transaction_hash, - }; - - let finalized = unsafe { self.replace(finalized_data) }?; - Ok(finalized) - } - - #[cfg(target_os = "solana")] - fn make_deposit( - &self, - system_program: &program::System<'a>, - source: &Operator<'a>, - ) -> Result<(), ProgramError> { - system_program.transfer(source, self.info, crate::config::PAYMENT_TO_DEPOSIT) - } - - fn withdraw_deposit(&self, target: &AccountInfo<'a>) -> Result<(), ProgramError> { - let source_lamports = self - .info - .lamports() - .checked_sub(crate::config::PAYMENT_TO_DEPOSIT) - .ok_or_else( - || E!(ProgramError::InvalidArgument; "Deposit source lamports underflow"), - )?; - - let target_lamports = target - .lamports() - .checked_add(crate::config::PAYMENT_TO_DEPOSIT) - .ok_or_else(|| E!(ProgramError::InvalidArgument; "Deposit target lamports overflow"))?; - - **self.info.lamports.borrow_mut() = source_lamports; - **target.lamports.borrow_mut() = target_lamports; - - Ok(()) - } - - pub fn read_blocked_accounts(&self) -> Result { - let (begin, end) = self.blocked_accounts_region(); - - let account_data = self.info.try_borrow_data()?; - if account_data.len() < end { - return Err!(ProgramError::AccountDataTooSmall; "Account {} - data too small, required: {}", self.info.key, end); - } - - let keys_storage = &account_data[begin..end]; - let chunks = keys_storage.chunks_exact(ACCOUNT_CHUNK_LEN); - let accounts = chunks - .map(|c| c.split_at(2)) - .map(|(meta, key)| BlockedAccountMeta { - key: Pubkey::try_from(key).expect("key is 32 bytes"), - exists: meta[1] != 0, - is_writable: meta[0] != 0, - }) - .collect(); - - Ok(accounts) - } - - #[cfg(target_os = "solana")] - fn write_blocked_accounts( - &mut self, - program_id: &Pubkey, - accounts: &[AccountInfo], - ) -> Result<(), ProgramError> { - assert_eq!(self.accounts_len, accounts.len()); // should be always true - - let (begin, end) = self.blocked_accounts_region(); - - let mut account_data = self.info.try_borrow_mut_data()?; - if account_data.len() < end { - return Err!(ProgramError::AccountDataTooSmall; "Account {} - data too small, required: {}", self.info.key, end); - } - - let accounts_storage = &mut account_data[begin..end]; - let accounts_storage = accounts_storage.chunks_exact_mut(ACCOUNT_CHUNK_LEN); - for (info, account_storage) in accounts.iter().zip(accounts_storage) { - account_storage[0] = u8::from(info.is_writable); - account_storage[1] = u8::from(Self::account_exists(program_id, info)); - account_storage[2..].copy_from_slice(info.key.as_ref()); - } - - Ok(()) - } - - pub fn update_blocked_accounts(&mut self, accounts: I) -> Result<(), Error> - where - I: ExactSizeIterator, - { - let evm_data_len = self.evm_state_len + self.evm_machine_len; - let (evm_data_offset, _) = self.evm_data_region(); - let evm_data_range = evm_data_offset..evm_data_offset + evm_data_len; - - self.accounts_len = accounts.len(); - let (accounts_begin, accounts_end) = self.blocked_accounts_region(); - - let mut data = self.info.try_borrow_mut_data()?; - // Move EVM data - data.copy_within(evm_data_range, accounts_end); - - // Write accounts - let accounts_storage = &mut data[accounts_begin..accounts_end]; - let accounts_storage = accounts_storage.chunks_exact_mut(ACCOUNT_CHUNK_LEN); - for (meta, account_storage) in accounts.zip(accounts_storage) { - account_storage[0] = u8::from(meta.is_writable); - account_storage[1] = u8::from(meta.exists); - account_storage[2..].copy_from_slice(meta.key.as_ref()); - } - - Ok(()) - } - - fn check_blocked_accounts( - &self, - program_id: &Pubkey, - remaining_accounts: &[AccountInfo], - is_cancelling: bool, - ) -> Result { - let blocked_accounts = self.read_blocked_accounts()?; - if blocked_accounts.len() != remaining_accounts.len() { - return Err!(ProgramError::NotEnoughAccountKeys; "Invalid number of accounts"); - } - - for (blocked, info) in blocked_accounts.iter().zip(remaining_accounts) { - if blocked.key != *info.key { - return Err!(ProgramError::InvalidAccountData; "Expected account {}, found {}", blocked.key, info.key); - } - - if blocked.is_writable && !info.is_writable { - return Err!(ProgramError::InvalidAccountData; "Expected account {} is_writable: {}", info.key, blocked.is_writable); - } - - if !is_cancelling && !blocked.exists && Self::account_exists(program_id, info) { - return Err!( - ProgramError::AccountAlreadyInitialized; - "Blocked nonexistent account {} was created/initialized outside current transaction. \ - Transaction is being cancelled in order to prevent possible data corruption.", - info.key - ); - } - } - - Ok(blocked_accounts) - } - - #[must_use] - pub fn evm_data(&self) -> Ref<[u8]> { - let (begin, end) = self.evm_data_region(); - - let data = self.info.data.borrow(); - Ref::map(data, |d| &d[begin..end]) - } - - #[must_use] - pub fn evm_data_mut(&mut self) -> RefMut<[u8]> { - let (begin, end) = self.evm_data_region(); - - let data = self.info.data.borrow_mut(); - RefMut::map(data, |d| &mut d[begin..end]) - } - - #[must_use] - fn evm_data_region(&self) -> (usize, usize) { - let (_, accounts_region_end) = self.blocked_accounts_region(); - - let begin = accounts_region_end; - let end = self.info.data_len(); - - (begin, end) - } - - #[must_use] - fn blocked_accounts_region(&self) -> (usize, usize) { - let begin = Self::SIZE; - let end = begin + self.accounts_len * ACCOUNT_CHUNK_LEN; - - (begin, end) - } - - #[must_use] - fn account_exists(program_id: &Pubkey, info: &AccountInfo) -> bool { - (info.owner == program_id) - && !info.data_is_empty() - && (info.data.borrow()[0] == EthereumAccount::TAG) - } -} From 1e79af763a22ea19fc582b3868c34d94457d815e Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Tue, 14 Nov 2023 18:03:22 +0300 Subject: [PATCH 049/318] [Multi Tokens] Account Storage changes --- evm_loader/lib/src/account_storage.rs | 964 +++++++++--------- .../program/src/account_storage/apply.rs | 493 +++------ .../program/src/account_storage/backend.rs | 170 ++- .../program/src/account_storage/base.rs | 175 ++-- .../program/src/account_storage/block_hash.rs | 69 ++ .../program/src/account_storage/keys_cache.rs | 96 ++ evm_loader/program/src/account_storage/mod.rs | 194 +--- 7 files changed, 939 insertions(+), 1222 deletions(-) create mode 100644 evm_loader/program/src/account_storage/block_hash.rs create mode 100644 evm_loader/program/src/account_storage/keys_cache.rs diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index c3cbd59a6..afa98cc4a 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -1,346 +1,247 @@ use async_trait::async_trait; +use evm_loader::account::legacy::{ + LegacyEtherData, LegacyStorageData, TAG_ACCOUNT_CONTRACT_DEPRECATED, + TAG_STORAGE_CELL_DEPRECATED, +}; +use evm_loader::account::{TAG_ACCOUNT_CONTRACT, TAG_STORAGE_CELL}; +use evm_loader::account_storage::find_slot_hash; +use evm_loader::types::Address; +use solana_sdk::rent::Rent; +use solana_sdk::system_program; +use solana_sdk::sysvar::{slot_hashes, Sysvar}; +use std::collections::HashSet; use std::{cell::RefCell, collections::HashMap, convert::TryInto, rc::Rc}; use crate::{rpc::Rpc, NeonError}; use ethnum::U256; -use evm_loader::account::ether_contract; -use evm_loader::account_storage::{find_slot_hash, AccountOperation, AccountsOperations}; -use evm_loader::evm::tracing::{AccountOverrides, BlockOverrides}; -use evm_loader::evm::Buffer; +use evm_loader::evm::tracing::{AccountOverride, AccountOverrides, BlockOverrides}; use evm_loader::{ - account::{ - ether_storage::EthereumStorageAddress, EthereumAccount, EthereumStorage, - ACCOUNT_SEED_VERSION, - }, + account::{BalanceAccount, ContractAccount, StorageCell, StorageCellAddress}, account_storage::AccountStorage, config::STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT, executor::{Action, OwnedAccountInfo}, - gasometer::LAMPORTS_PER_SIGNATURE, - types::Address, }; -use log::{debug, error, info, trace, warn}; +use log::{debug, info, trace}; use serde::{Deserialize, Serialize}; use solana_client::client_error; -use solana_sdk::entrypoint::MAX_PERMITTED_DATA_INCREASE; -use solana_sdk::{ - account::Account, - account_info::AccountInfo, - commitment_config::CommitmentConfig, - pubkey, - pubkey::Pubkey, - rent::Rent, - sysvar::{slot_hashes, Sysvar}, -}; +use solana_sdk::{account::Account, account_info::AccountInfo, pubkey, pubkey::Pubkey}; -use crate::types::PubkeyBase58; +use crate::commands::get_config::ChainInfo; +use serde_with::{serde_as, DisplayFromStr}; const FAKE_OPERATOR: Pubkey = pubkey!("neonoperator1111111111111111111111111111111"); -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct NeonAccount { - address: Address, - account: PubkeyBase58, - writable: bool, - new: bool, - size: usize, - size_current: usize, - additional_resize_steps: usize, - #[serde(skip)] - data: Option, -} - -impl NeonAccount { - fn new(address: Address, pubkey: Pubkey, account: Option, writable: bool) -> Self { - if let Some(account) = account { - trace!("Account found {}", address); - - Self { - address, - account: pubkey.into(), - writable, - new: false, - size: account.data.len(), - size_current: account.data.len(), - additional_resize_steps: 0, - data: Some(account), - } - } else { - trace!("Account not found {}", address); - - Self { - address, - account: pubkey.into(), - writable, - new: true, - size: 0, - size_current: 0, - additional_resize_steps: 0, - data: None, - } - } - } - - pub async fn rpc_load( - rpc_client: &dyn Rpc, - evm_loader: &Pubkey, - address: Address, - writable: bool, - ) -> Self { - let (key, _) = make_solana_program_address(&address, evm_loader); - info!("get_account_from_solana {address} => {key}"); - - let account = match rpc_client.get_account(&key).await { - Ok(account) => Some(account), - Err(err) => { - error!("rpc_client.get_account {key} error: {err:?}"); - None - } - }; - Self::new(address, key, account, writable) - } -} - +#[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SolanaAccount { - pubkey: PubkeyBase58, + #[serde_as(as = "DisplayFromStr")] + pubkey: Pubkey, is_writable: bool, + is_legacy: bool, #[serde(skip)] data: Option, } #[allow(clippy::module_name_repetitions)] -pub struct EmulatorAccountStorage<'a> { - pub accounts: RefCell>, - pub solana_accounts: RefCell>, - rpc_client: &'a dyn Rpc, - evm_loader: Pubkey, +pub struct EmulatorAccountStorage<'rpc> { + pub accounts: RefCell>, + pub gas: u64, + rpc_client: &'rpc dyn Rpc, + program_id: Pubkey, + chains: Vec, block_number: u64, block_timestamp: i64, - neon_token_mint: Pubkey, - chain_id: u64, - commitment: CommitmentConfig, state_overrides: Option, } -impl<'a> EmulatorAccountStorage<'a> { +impl<'rpc> EmulatorAccountStorage<'rpc> { pub async fn new( - rpc_client: &'a dyn Rpc, - evm_loader: Pubkey, - token_mint: Pubkey, - chain_id: u64, - commitment: CommitmentConfig, - block_overrides: &Option, + rpc_client: &'rpc dyn Rpc, + program_id: Pubkey, + chains: Option>, + block_overrides: Option, state_overrides: Option, - ) -> Result, NeonError> { + ) -> Result, NeonError> { trace!("backend::new"); - let block_number = match block_overrides - .as_ref() - .and_then(|overrides| overrides.number) - { + let block_number = match block_overrides.as_ref().and_then(|o| o.number) { None => rpc_client.get_slot().await?, Some(number) => number, }; - let block_timestamp = match block_overrides - .as_ref() - .and_then(|overrides| overrides.time) - { + let block_timestamp = match block_overrides.as_ref().and_then(|o| o.time) { None => rpc_client.get_block_time(block_number).await?, Some(time) => time, }; + let chains = match chains { + None => crate::commands::get_config::read_chains(rpc_client, program_id).await?, + Some(chains) => chains, + }; + Ok(Self { accounts: RefCell::new(HashMap::new()), - solana_accounts: RefCell::new(HashMap::new()), + program_id, + chains, + gas: 0, rpc_client, - evm_loader, block_number, block_timestamp, - neon_token_mint: token_mint, - chain_id, - commitment, state_overrides, }) } - #[allow(clippy::too_many_arguments)] pub async fn with_accounts( - rpc_client: &'a dyn Rpc, - evm_loader: Pubkey, - token_mint: Pubkey, - chain_id: u64, - commitment: CommitmentConfig, - accounts: &[Address], - solana_accounts: &[Pubkey], - block_overrides: &Option, + rpc_client: &'rpc dyn Rpc, + program_id: Pubkey, + accounts: &[Pubkey], + chains: Option>, + block_overrides: Option, state_overrides: Option, - ) -> Result, NeonError> { + ) -> Result, NeonError> { let storage = Self::new( rpc_client, - evm_loader, - token_mint, - chain_id, - commitment, + program_id, + chains, block_overrides, state_overrides, ) .await?; - storage - .initialize_cached_accounts(accounts, solana_accounts) - .await; + + storage.download_accounts(accounts).await?; Ok(storage) } - pub async fn initialize_cached_accounts( - &self, - addresses: &[Address], - solana_accounts: &[Pubkey], - ) { - let pubkeys: Vec<_> = addresses - .iter() - .map(|address| make_solana_program_address(address, &self.evm_loader).0) - .chain(solana_accounts.iter().copied()) - .collect(); - - if let Ok(accounts) = self.rpc_client.get_multiple_accounts(&pubkeys).await { - let entries = addresses - .iter() - .zip(accounts.iter().take(addresses.len())) - .zip(pubkeys.iter().take(addresses.len())); - for ((&address, account), &pubkey) in entries { - self.accounts.borrow_mut().insert( - address, - NeonAccount::new(address, pubkey, account.clone(), false), - ); - } + async fn download_accounts(&self, pubkeys: &[Pubkey]) -> Result<(), NeonError> { + let accounts = self.rpc_client.get_multiple_accounts(pubkeys).await?; - let entries = accounts.iter().skip(addresses.len()).zip(solana_accounts); - let mut solana_accounts_storage = self.solana_accounts.borrow_mut(); - for (account, &pubkey) in entries { - solana_accounts_storage.insert( - pubkey, - SolanaAccount { - pubkey: pubkey.into(), - is_writable: false, - data: account.clone(), - }, - ); - } + let mut cache = self.accounts.borrow_mut(); + + for (key, account) in pubkeys.iter().zip(accounts) { + let account = SolanaAccount { + pubkey: *key, + is_writable: false, + is_legacy: false, + data: account.clone(), + }; + + cache.insert(*key, account); } + + Ok(()) } - pub async fn get_account(&self, pubkey: &Pubkey) -> client_error::Result> { - if let Some(account) = self.solana_accounts.borrow().get(pubkey) { - if let Some(ref data) = account.data { - return Ok(Some(data.clone())); - } + pub async fn use_account( + &self, + pubkey: Pubkey, + is_writable: bool, + ) -> client_error::Result> { + if pubkey == FAKE_OPERATOR { + return Ok(None); } - let result = self - .rpc_client - .get_account_with_commitment(pubkey, self.commitment) - .await?; - - self.solana_accounts - .borrow_mut() - .entry(*pubkey) - .and_modify(|a| a.data = result.value.clone()) - .or_insert(SolanaAccount { - pubkey: pubkey.into(), - is_writable: false, - data: result.value.clone(), - }); + if let Some(account) = self.accounts.borrow_mut().get_mut(&pubkey) { + account.is_writable |= is_writable; + return Ok(account.data.clone()); + } - Ok(result.value) - } + let response = self.rpc_client.get_account(&pubkey).await?; + let account = response.value; - pub async fn get_account_from_solana( - rpc_client: &'a dyn Rpc, - evm_loader: &'a Pubkey, - address: &Address, - ) -> (Pubkey, Option) { - let (solana_address, _solana_nonce) = make_solana_program_address(address, evm_loader); - info!("get_account_from_solana {} => {}", address, solana_address); + self.accounts.borrow_mut().insert( + pubkey, + SolanaAccount { + pubkey, + is_writable, + is_legacy: false, + data: account.clone(), + }, + ); - if let Ok(acc) = rpc_client.get_account(&solana_address).await { - trace!("Account found"); - trace!("Account data len {}", acc.data.len()); - trace!("Account owner {}", acc.owner); + Ok(account) + } - (solana_address, Some(acc)) + pub async fn use_balance_account( + &self, + address: Address, + chain_id: u64, + is_writable: bool, + ) -> client_error::Result<(Pubkey, Option, Option)> { + let (pubkey, _) = address.find_balance_address(self.program_id(), chain_id); + let account = self.use_account(pubkey, is_writable).await?; + + let legacy_account = if account.is_none() && (chain_id == self.default_chain_id()) { + let (legacy_pubkey, _) = address.find_solana_address(self.program_id()); + self.use_account(legacy_pubkey, is_writable).await? } else { - warn!("Account not found {}", address); + None + }; - (solana_address, None) - } + Ok((pubkey, account, legacy_account)) } - async fn add_ethereum_account(&self, address: &Address, writable: bool) -> bool { - if let Some(ref mut account) = self.accounts.borrow_mut().get_mut(address) { - account.writable |= writable; - - return true; - } - - let account = - NeonAccount::rpc_load(self.rpc_client, &self.evm_loader, *address, writable).await; - self.accounts.borrow_mut().insert(*address, account); + pub async fn use_contract_account( + &self, + address: Address, + is_writable: bool, + ) -> client_error::Result<(Pubkey, Option)> { + let (pubkey, _) = address.find_solana_address(self.program_id()); + let account = self.use_account(pubkey, is_writable).await?; - false + Ok((pubkey, account)) } - async fn add_solana_account(&self, pubkey: Pubkey, is_writable: bool) { - if solana_sdk::system_program::check_id(&pubkey) { - return; - } - - if pubkey == FAKE_OPERATOR { - return; - } - - let mut solana_accounts = self.solana_accounts.borrow_mut(); + pub async fn use_storage_cell( + &self, + address: Address, + index: U256, + is_writable: bool, + ) -> client_error::Result<(Pubkey, Option)> { + let (base, _) = address.find_solana_address(self.program_id()); + let cell_address = StorageCellAddress::new(self.program_id(), &base, &index); + + let account = self + .use_account(*cell_address.pubkey(), is_writable) + .await?; - let account = SolanaAccount { - pubkey: pubkey.into(), - is_writable, - data: None, - }; - if is_writable { - solana_accounts - .entry(pubkey) - // If account is present in cache ensure the data is not lost - .and_modify(|a| a.is_writable = true) - .or_insert(account); - } else { - solana_accounts.entry(pubkey).or_insert(account); - } + Ok((*cell_address.pubkey(), account)) } - pub async fn apply_actions(&self, actions: &[Action]) -> u64 { + pub async fn apply_actions(&mut self, actions: Vec) -> Result<(), NeonError> { info!("apply_actions"); - let mut gas = 0_u64; - let rent = Rent::get().expect("Rent get error"); + let rent = Rent::get()?; + + let mut new_balance_accounts = HashSet::new(); for action in actions { #[allow(clippy::match_same_arms)] match action { - Action::NeonTransfer { + Action::Transfer { source, target, + chain_id, value, } => { info!("neon transfer {value} from {source} to {target}"); - self.add_ethereum_account(source, true).await; - self.add_ethereum_account(target, true).await; + self.use_balance_account(source, chain_id, true).await?; + + let (key, target, legacy) = + self.use_balance_account(target, chain_id, true).await?; + if target.is_none() && legacy.is_none() { + new_balance_accounts.insert(key); + } } - Action::NeonWithdraw { source, value } => { + Action::Burn { + source, + value, + chain_id, + } => { info!("neon withdraw {value} from {source}"); - self.add_ethereum_account(source, true).await; + self.use_balance_account(source, chain_id, true).await?; } Action::EvmSetStorage { address, @@ -349,38 +250,52 @@ impl<'a> EmulatorAccountStorage<'a> { } => { info!("set storage {address} -> {index} = {}", hex::encode(value)); - if *index < U256::from(STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT) { - self.add_ethereum_account(address, true).await; + if index < U256::from(STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT as u64) { + self.use_contract_account(address, true).await?; } else { - let (base, _) = address.find_solana_address(self.program_id()); - let storage_account = - EthereumStorageAddress::new(self.program_id(), &base, index); - self.add_solana_account(*storage_account.pubkey(), true) - .await; - - if self.storage(address, index).await == [0_u8; 32] { - let metadata_size = EthereumStorage::SIZE; - let element_size = 1 + std::mem::size_of_val(value); - - let cost = rent.minimum_balance(metadata_size + element_size); - gas = gas.saturating_add(cost); - } + let index = index & !U256::new(0xFF); + let (_, account) = self.use_storage_cell(address, index, true).await?; + + let cell_size = StorageCell::required_account_size(1); + let empty_size = StorageCell::required_account_size(0); + + let gas = if account.is_none() { + rent.minimum_balance(cell_size) + } else { + let existing_value = self.storage(address, index).await; + if existing_value == [0_u8; 32] { + rent.minimum_balance(cell_size) + .saturating_sub(rent.minimum_balance(empty_size)) + } else { + 0 + } + }; + + self.gas = self.gas.saturating_add(gas); } } - Action::EvmIncrementNonce { address } => { + Action::EvmIncrementNonce { address, chain_id } => { info!("nonce increment {address}"); - self.add_ethereum_account(address, true).await; + let (key, account, legacy) = + self.use_balance_account(address, chain_id, true).await?; + if account.is_none() && legacy.is_none() { + new_balance_accounts.insert(key); + } } - Action::EvmSetCode { address, code } => { + Action::EvmSetCode { + address, + code, + chain_id: _, + } => { info!("set code {address} -> {} bytes", code.len()); + self.use_contract_account(address, true).await?; - self.add_ethereum_account(address, true).await; + let space = ContractAccount::required_account_size(&code); + self.gas = self.gas.saturating_add(rent.minimum_balance(space)); } Action::EvmSelfDestruct { address } => { info!("selfdestruct {address}"); - - self.add_ethereum_account(address, true).await; } Action::ExternalInstruction { program_id, @@ -390,126 +305,220 @@ impl<'a> EmulatorAccountStorage<'a> { } => { info!("external call {program_id}"); - self.add_solana_account(*program_id, false).await; + self.use_account(program_id, false).await?; for account in accounts { - self.add_solana_account(account.pubkey, account.is_writable) - .await; + self.use_account(account.pubkey, account.is_writable) + .await?; } - gas = gas.saturating_add(*fee); + self.gas = self.gas.saturating_add(fee); } } } - gas + self.gas = self.gas.saturating_add( + rent.minimum_balance(BalanceAccount::required_account_size()) + .saturating_mul(new_balance_accounts.len() as u64), + ); + + Ok(()) } - pub async fn apply_accounts_operations(&self, operations: AccountsOperations) -> u64 { - let mut gas = 0_u64; - let rent = Rent::get().expect("Rent get error"); + pub async fn mark_legacy_accounts(&mut self) -> Result<(), NeonError> { + let mut accounts = self.accounts.borrow_mut(); + let mut additional_balances = Vec::new(); - let mut iterations = 0_usize; + let rent = Rent::get()?; - let mut accounts = self.accounts.borrow_mut(); - for (address, operation) in operations { - let new_size = match operation { - AccountOperation::Create { space } => space, - AccountOperation::Resize { to, .. } => to, + for (key, account) in accounts.iter_mut() { + let Some(account_data) = account.data.as_mut() else { + continue; + }; + + let info = account_info(key, account_data); + if info.owner != self.program_id() { + continue; + } + + let Ok(tag) = evm_loader::account::tag(self.program_id(), &info) else { + continue; }; - accounts.entry(address).and_modify(|a| { - a.size = new_size; - a.additional_resize_steps = - new_size.saturating_sub(a.size_current).saturating_sub(1) - / MAX_PERMITTED_DATA_INCREASE; - iterations = iterations.max(a.additional_resize_steps); - }); - - let allocate_cost = rent.minimum_balance(new_size); - gas = gas.saturating_add(allocate_cost); + + if tag == TAG_STORAGE_CELL_DEPRECATED { + account.is_writable = true; + account.is_legacy = true; + } + + if tag == TAG_ACCOUNT_CONTRACT_DEPRECATED { + account.is_writable = true; + account.is_legacy = true; + + let legacy_data = LegacyEtherData::from_account(self.program_id(), &info)?; + additional_balances.push(legacy_data.address); + + if (legacy_data.code_size > 0) || (legacy_data.generation > 0) { + // This is a contract, we need additional gas for conversion + let lamports = rent.minimum_balance(BalanceAccount::required_account_size()); + self.gas = self.gas.saturating_add(lamports); + } + } } - let iterations_cost = (iterations as u64) * LAMPORTS_PER_SIGNATURE; + for a in additional_balances { + let (pubkey, _) = a.find_balance_address(self.program_id(), self.default_chain_id()); + let account = SolanaAccount { + pubkey, + is_writable: true, + is_legacy: false, + data: None, + }; - gas.saturating_add(iterations_cost) + accounts.insert(pubkey, account); + } + + Ok(()) } - async fn ethereum_account_map_or(&self, address: &Address, default: R, f: F) -> R + pub async fn ethereum_balance_map_or( + &self, + address: Address, + chain_id: u64, + default: R, + legacy_action: L, + action: F, + ) -> R where - F: FnOnce(&EthereumAccount) -> R, + L: FnOnce(LegacyEtherData) -> R, + F: FnOnce(BalanceAccount) -> R, { - self.add_ethereum_account(address, false).await; + let (pubkey, mut account, mut legacy) = self + .use_balance_account(address, chain_id, false) + .await + .unwrap(); - let mut accounts = self.accounts.borrow_mut(); - let solana_account = accounts.get_mut(address).expect("get account error"); - - if let Some(account_data) = &mut solana_account.data { - let info = account_info(solana_account.account.as_ref(), account_data); - EthereumAccount::from_account(&self.evm_loader, &info) - .map(|mut ether_account| { - if let Some(account_overrides) = &self.state_overrides { - if let Some(account_override) = account_overrides.get(address) { - account_override.apply(&mut ether_account); - } - } - ether_account - }) - .map_or(default, |a| f(&a)) - } else { - default + if let Some(account_data) = &mut account { + let info = account_info(&pubkey, account_data); + if let Ok(a) = BalanceAccount::from_account(self.program_id(), info, Some(address)) { + return action(a); + } + } + + if chain_id != self.default_chain_id() { + return default; + } + + if let Some(legacy_data) = &mut legacy { + let info = account_info(&pubkey, legacy_data); + if let Ok(a) = LegacyEtherData::from_account(self.program_id(), &info) { + return legacy_action(a); + } } + + default } - async fn ethereum_contract_map_or(&self, address: &Address, default: R, f: F) -> R + pub async fn ethereum_contract_map_or( + &self, + address: Address, + default: R, + legacy_action: L, + action: F, + ) -> R where - F: FnOnce(ether_contract::ContractData) -> R, + L: FnOnce(LegacyEtherData, &AccountInfo) -> R, + F: FnOnce(ContractAccount) -> R, { - self.add_ethereum_account(address, false).await; + let (pubkey, mut account) = self.use_contract_account(address, false).await.unwrap(); - let mut accounts = self.accounts.borrow_mut(); - let solana_account = accounts.get_mut(address).expect("get account error"); - - if let Some(account_data) = &mut solana_account.data { - let info = account_info(solana_account.account.as_ref(), account_data); - let account = EthereumAccount::from_account(&self.evm_loader, &info); - match &account { - Ok(a) => a.contract_data().map_or(default, f), - Err(_) => default, + let Some(account_data) = &mut account else { + return default; + }; + + if system_program::check_id(&account_data.owner) { + return default; + } + + let info = account_info(&pubkey, account_data); + let Ok(tag) = evm_loader::account::tag(self.program_id(), &info) else { + return default; + }; + + match tag { + TAG_ACCOUNT_CONTRACT => { + let contract = ContractAccount::from_account(self.program_id(), info).unwrap(); + action(contract) } - } else { - default + TAG_ACCOUNT_CONTRACT_DEPRECATED => { + let legacy_data = LegacyEtherData::from_account(self.program_id(), &info).unwrap(); + legacy_action(legacy_data, &info) + } + _ => default, } } - async fn get_code(&self, address: &Address) -> Buffer { - self.ethereum_contract_map_or(address, Buffer::empty(), |c| { - self.state_overrides - .as_ref() - .and_then(|account_overrides| account_overrides.get(address)?.code.as_ref()) - .map_or_else( - || Buffer::from_slice(&c.code()), - |code| Buffer::from_slice(&code.0), - ) - }) - .await - } -} + pub async fn ethereum_storage_map_or( + &self, + address: Address, + index: U256, + default: R, + legacy_action: L, + action: F, + ) -> R + where + L: FnOnce(LegacyStorageData, &AccountInfo) -> R, + F: FnOnce(StorageCell) -> R, + { + let (pubkey, mut account) = self.use_storage_cell(address, index, false).await.unwrap(); -#[async_trait(?Send)] -impl<'a> AccountStorage for EmulatorAccountStorage<'a> { - fn neon_token_mint(&self) -> &Pubkey { - info!("neon_token_mint"); - &self.neon_token_mint + let Some(account_data) = &mut account else { + return default; + }; + + if system_program::check_id(&account_data.owner) { + return default; + } + + let info = account_info(&pubkey, account_data); + let Ok(tag) = evm_loader::account::tag(self.program_id(), &info) else { + return default; + }; + + match tag { + TAG_STORAGE_CELL => { + let contract = StorageCell::from_account(self.program_id(), info).unwrap(); + action(contract) + } + TAG_STORAGE_CELL_DEPRECATED => { + let legacy_data = + LegacyStorageData::from_account(self.program_id(), &info).unwrap(); + legacy_action(legacy_data, &info) + } + _ => default, + } } - fn operator(&self) -> &Pubkey { - info!("operator"); - &FAKE_OPERATOR + fn account_override(&self, address: Address, f: F) -> Option + where + F: FnOnce(&AccountOverride) -> Option, + { + self.state_overrides + .as_ref() + .and_then(|a| a.get(&address)) + .and_then(f) } +} +#[async_trait(? Send)] +impl<'a> AccountStorage for EmulatorAccountStorage<'a> { fn program_id(&self) -> &Pubkey { debug!("program_id"); - &self.evm_loader + &self.program_id + } + + fn operator(&self) -> Pubkey { + info!("operator"); + FAKE_OPERATOR } fn block_number(&self) -> U256 { @@ -525,9 +534,7 @@ impl<'a> AccountStorage for EmulatorAccountStorage<'a> { async fn block_hash(&self, slot: u64) -> [u8; 32] { info!("block_hash {slot}"); - self.add_solana_account(slot_hashes::ID, false).await; - - if let Ok(Some(slot_hashes_account)) = self.get_account(&slot_hashes::ID).await { + if let Ok(Some(slot_hashes_account)) = self.use_account(slot_hashes::ID, false).await { let slot_hashes_data = slot_hashes_account.data.as_slice(); find_slot_hash(slot, slot_hashes_data) } else { @@ -535,137 +542,168 @@ impl<'a> AccountStorage for EmulatorAccountStorage<'a> { } } - async fn exists(&self, address: &Address) -> bool { - info!("exists {address}"); + async fn nonce(&self, address: Address, chain_id: u64) -> u64 { + info!("nonce {address} {chain_id}"); - self.add_ethereum_account(address, false).await; + let nonce_override = self.account_override(address, |a| a.nonce); + if let Some(nonce_override) = nonce_override { + return nonce_override; + } - let accounts = self.accounts.borrow(); - accounts.contains_key(address) + self.ethereum_balance_map_or( + address, + chain_id, + u64::default(), + |legacy| legacy.trx_count, + |account| account.nonce(), + ) + .await } - async fn nonce(&self, address: &Address) -> u64 { - info!("nonce {address}"); + async fn balance(&self, address: Address, chain_id: u64) -> U256 { + info!("balance {address} {chain_id}"); - self.ethereum_account_map_or(address, 0_u64, |a| a.trx_count) - .await + let balance_override = self.account_override(address, |a| a.balance); + if let Some(balance_override) = balance_override { + return balance_override; + } + + self.ethereum_balance_map_or( + address, + chain_id, + U256::default(), + |legacy| legacy.balance, + |account| account.balance(), + ) + .await } - async fn balance(&self, address: &Address) -> U256 { - info!("balance {address}"); + fn is_valid_chain_id(&self, chain_id: u64) -> bool { + for chain in &self.chains { + if chain.id == chain_id { + return true; + } + } - self.ethereum_account_map_or(address, U256::ZERO, |a| a.balance) - .await + false } - async fn code_size(&self, address: &Address) -> usize { - info!("code_size {address}"); + fn chain_id_to_token(&self, chain_id: u64) -> Pubkey { + for chain in &self.chains { + if chain.id == chain_id { + return chain.token; + } + } - self.ethereum_account_map_or(address, 0, |a| a.code_size as usize) - .await + unreachable!(); + } + + fn default_chain_id(&self) -> u64 { + for chain in &self.chains { + if chain.name == "neon" { + return chain.id; + } + } + + unreachable!(); } - async fn code_hash(&self, address: &Address) -> [u8; 32] { + async fn contract_chain_id(&self, address: Address) -> evm_loader::error::Result { + use evm_loader::error::Error; + + let default_value = Err(Error::Custom(std::format!( + "Account {address} - invalid tag" + ))); + + self.ethereum_contract_map_or( + address, + default_value, + |_legacy, _| Ok(self.default_chain_id()), + |a| Ok(a.chain_id()), + ) + .await + } + + fn contract_pubkey(&self, address: Address) -> (Pubkey, u8) { + address.find_solana_address(self.program_id()) + } + + async fn code_hash(&self, address: Address, chain_id: u64) -> [u8; 32] { use solana_sdk::keccak::hash; - info!("code_hash {address}"); + info!("code_hash {address} {chain_id}"); + + let code = self.code(address).await.to_vec(); + if !code.is_empty() { + return hash(&code).to_bytes(); + } // https://eips.ethereum.org/EIPS/eip-1052 // https://eips.ethereum.org/EIPS/eip-161 - let is_non_existent_account = self - .ethereum_account_map_or(address, true, |a| { - a.trx_count == 0 && a.balance == 0 && a.code_size == 0 - }) - .await; - - if is_non_existent_account { + if (self.balance(address, chain_id).await == 0) + && (self.nonce(address, chain_id).await == 0) + { return <[u8; 32]>::default(); } - // return empty hash(&[]) as a default value, or code's hash if contract exists - hash(self.get_code(address).await.as_ref()).to_bytes() + hash(&[]).to_bytes() } - async fn code(&self, address: &Address) -> Buffer { - info!("code {address}"); + async fn code_size(&self, address: Address) -> usize { + info!("code_size {address}"); - self.get_code(address).await + self.code(address).await.len() } - async fn generation(&self, address: &Address) -> u32 { - let value = self - .ethereum_account_map_or(address, 0_u32, |c| c.generation) + async fn code(&self, address: Address) -> evm_loader::evm::Buffer { + use evm_loader::evm::Buffer; + + info!("code {address}"); + + let code_override = self.account_override(address, |a| a.code.clone()); + if let Some(code_override) = code_override { + return Buffer::from_vec(code_override.into()); + } + + let code = self + .ethereum_contract_map_or( + address, + Vec::default(), + |legacy, info| legacy.read_code(info), + |c| c.code().to_vec(), + ) .await; - info!("account generation {address} - {value}"); - value + Buffer::from_vec(code) } - async fn storage(&self, address: &Address, index: &U256) -> [u8; 32] { - if let Some(account_overrides) = &self.state_overrides { - if let Some(account_override) = account_overrides.get(address) { - match (&account_override.state, &account_override.state_diff) { - (None, None) => (), - (Some(_), Some(_)) => { - panic!("Account {address} has both `state` and `stateDiff` overrides") - } - (Some(state), None) => { - return state - .get(index) - .map(|value| value.to_be_bytes()) - .unwrap_or_default() - } - (None, Some(state_diff)) => { - if let Some(value) = state_diff.get(index) { - return value.to_be_bytes(); - } - } - } - } + async fn storage(&self, address: Address, index: U256) -> [u8; 32] { + let storage_override = self.account_override(address, |a| a.storage(index)); + if let Some(storage_override) = storage_override { + return storage_override; } - let value = if *index < U256::from(STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT) { - let index: usize = index.as_usize() * 32; - self.ethereum_contract_map_or(address, <[u8; 32]>::default(), |c| { - c.storage()[index..index + 32].try_into().unwrap() - }) + + let value = if index < U256::from(STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT as u64) { + let index: usize = index.as_usize(); + self.ethereum_contract_map_or( + address, + [0_u8; 32], + |legacy, info| legacy.read_storage(info)[index], + |c| c.storage_value(index), + ) .await } else { let subindex = (index & 0xFF).as_u8(); let index = index & !U256::new(0xFF); - let (base, _) = address.find_solana_address(self.program_id()); - let storage_address = EthereumStorageAddress::new(self.program_id(), &base, &index); - - self.add_solana_account(*storage_address.pubkey(), false) - .await; - - let rpc_response = self - .get_account(storage_address.pubkey()) - .await - .expect("Error querying account from Solana"); - - if let Some(mut account) = rpc_response { - if solana_sdk::system_program::check_id(&account.owner) { - debug!("read storage system owned"); - <[u8; 32]>::default() - } else { - let account_info = account_info(storage_address.pubkey(), &mut account); - let storage = EthereumStorage::from_account(&self.evm_loader, &account_info) - .expect("EthereumAccount ctor error"); - if (storage.address != *address) - || (storage.index != index) - || (storage.generation != self.generation(address).await) - { - debug!("storage collision"); - <[u8; 32]>::default() - } else { - storage.get(subindex) - } - } - } else { - debug!("storage account doesn't exist"); - <[u8; 32]>::default() - } + self.ethereum_storage_map_or( + address, + index, + <[u8; 32]>::default(), + |legacy, info| legacy.read_value(subindex, info), + |cell| cell.get(subindex), + ) + .await }; info!("storage {address} -> {index} = {}", hex::encode(value)); @@ -673,17 +711,6 @@ impl<'a> AccountStorage for EmulatorAccountStorage<'a> { value } - async fn solana_account_space(&self, address: &Address) -> Option { - self.ethereum_account_map_or(address, None, |account| Some(account.info.data_len())) - .await - } - - fn chain_id(&self) -> u64 { - info!("chain_id"); - - self.chain_id - } - async fn clone_solana_account(&self, address: &Pubkey) -> OwnedAccountInfo { info!("clone_solana_account {}", address); @@ -694,20 +721,18 @@ impl<'a> AccountStorage for EmulatorAccountStorage<'a> { is_writable: false, lamports: 100 * 1_000_000_000, data: vec![], - owner: solana_sdk::system_program::ID, + owner: system_program::ID, executable: false, rent_epoch: 0, } } else { - self.add_solana_account(*address, false).await; - let mut account = self - .get_account(address) + .use_account(*address, false) .await .unwrap_or_default() .unwrap_or_default(); - let info = account_info(address, &mut account); + let info = account_info(address, &mut account); OwnedAccountInfo::from_account_info(self.program_id(), &info) } } @@ -716,15 +741,13 @@ impl<'a> AccountStorage for EmulatorAccountStorage<'a> { where F: FnOnce(&AccountInfo) -> R, { - self.add_solana_account(*address, false).await; - let mut account = self - .get_account(address) + .use_account(*address, false) .await .unwrap_or_default() .unwrap_or_default(); - let info = account_info(address, &mut account); + let info = account_info(address, &mut account); action(&info) } } @@ -742,10 +765,3 @@ pub fn account_info<'a>(key: &'a Pubkey, account: &'a mut Account) -> AccountInf rent_epoch: account.rent_epoch, } } - -pub fn make_solana_program_address(ether_address: &Address, program_id: &Pubkey) -> (Pubkey, u8) { - Pubkey::find_program_address( - &[&[ACCOUNT_SEED_VERSION], ether_address.as_bytes()], - program_id, - ) -} diff --git a/evm_loader/program/src/account_storage/apply.rs b/evm_loader/program/src/account_storage/apply.rs index ba74df13b..ee020ee4d 100644 --- a/evm_loader/program/src/account_storage/apply.rs +++ b/evm_loader/program/src/account_storage/apply.rs @@ -1,110 +1,98 @@ -use std::collections::hash_map::Entry; use std::collections::HashMap; -use std::convert::TryInto; use ethnum::U256; -use solana_program::entrypoint::{ProgramResult, MAX_PERMITTED_DATA_INCREASE}; +use solana_program::account_info::AccountInfo; use solana_program::instruction::Instruction; -use solana_program::program::{invoke, invoke_signed_unchecked}; -use solana_program::program_error::ProgramError; +use solana_program::program::invoke_signed_unchecked; use solana_program::rent::Rent; -use solana_program::system_instruction; +use solana_program::system_program; use solana_program::sysvar::Sysvar; -use crate::account::ether_storage::EthereumStorageAddress; -use crate::account::{ether_account, program, EthereumAccount, EthereumStorage, Operator}; -use crate::account_storage::{ - AccountOperation, AccountStorage, AccountsOperations, AccountsReadiness, ProgramAccountStorage, +use crate::account::BalanceAccount; +use crate::account::{AllocateResult, ContractAccount, StorageCell}; +use crate::account_storage::ProgramAccountStorage; +use crate::config::{ + ACCOUNT_SEED_VERSION, PAYMENT_TO_TREASURE, STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT, }; -use crate::config::STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT; +use crate::error::Result; use crate::executor::Action; use crate::types::Address; impl<'a> ProgramAccountStorage<'a> { + pub fn transfer_treasury_payment(&mut self) -> Result<()> { + let system = self.accounts.system(); + let treasury = self.accounts.treasury(); + let operator = self.accounts.operator(); + + system.transfer(operator, treasury, PAYMENT_TO_TREASURE)?; + + Ok(()) + } + pub fn transfer_gas_payment( &mut self, origin: Address, - mut operator: EthereumAccount<'a>, + chain_id: u64, value: U256, - ) -> ProgramResult { - let origin_balance = self.balance(&origin); - if origin_balance < value { - return Err!(ProgramError::InsufficientFunds; "Account {} - insufficient funds", origin); - } + ) -> Result<()> { + let (pubkey, _) = origin.find_balance_address(&crate::ID, chain_id); - if operator.address == origin { - return Ok(()); - } - - if self.ethereum_accounts.contains_key(&operator.address) { - self.transfer_neon_tokens(&origin, &operator.address, value)?; - core::mem::drop(operator); - } else { - let origin_account = self.ethereum_account_mut(&origin); - // balance checked above + let source = self.accounts.get(&pubkey).clone(); + let mut source = BalanceAccount::from_account(&crate::ID, source, Some(origin))?; - origin_account.balance -= value; - operator.balance += value; - } + let target = self.accounts.operator_balance(); - Ok(()) + source.transfer(target, value) } - pub fn apply_state_change( - &mut self, - neon_program: &program::Neon<'a>, - system_program: &program::System<'a>, - operator: &Operator<'a>, - actions: Vec, - ) -> Result { - debug_print!("Applies begin"); + pub fn allocate(&mut self, actions: &[Action]) -> Result { + let mut total_result = AllocateResult::Ready; - let actions = Self::rearrange_actions(actions); - - let accounts_operations = self.calc_accounts_operations(&actions); - if self.process_accounts_operations( - system_program, - neon_program, - operator, - accounts_operations, - )? == AccountsReadiness::NeedMoreReallocations - { - debug_print!( - "Applies postponed: need to reallocate accounts in the next transaction(s)" - ); - return Ok(AccountsReadiness::NeedMoreReallocations); - } + let rent = Rent::get()?; - for action in &actions { - let address = match action { - Action::NeonTransfer { target, .. } => target, - Action::EvmSelfDestruct { address, .. } | Action::EvmSetCode { address, .. } => { - address + for action in actions { + if let Action::EvmSetCode { address, code, .. } = action { + let result = ContractAccount::allocate( + *address, + code, + &rent, + &self.accounts, + Some(&self.keys), + )?; + + if result == AllocateResult::NeedMore { + total_result = AllocateResult::NeedMore; } - _ => continue, - }; - self.create_account_if_not_exists(address)?; + } } - let mut storage: HashMap> = - HashMap::with_capacity(actions.len()); + Ok(total_result) + } + + pub fn apply_state_change(&mut self, actions: Vec) -> Result<()> { + debug_print!("Applies begin"); + + let mut storage = HashMap::with_capacity(16); for action in actions { match action { - Action::NeonTransfer { + Action::Transfer { source, target, + chain_id, value, } => { - self.transfer_neon_tokens(&source, &target, value)?; + let mut source = self.balance_account(source, chain_id)?; + let mut target = self.create_balance_account(target, chain_id)?; + source.transfer(&mut target, value)?; } - Action::NeonWithdraw { source, value } => { - let account = self.ethereum_account_mut(&source); - if account.balance < value { - return Err!(ProgramError::InsufficientFunds; "Account {} - insufficient funds, required = {}", source, value)?; - } - - account.balance -= value; + Action::Burn { + source, + chain_id, + value, + } => { + let mut account = self.create_balance_account(source, chain_id)?; + account.burn(value)?; } Action::EvmSetStorage { address, @@ -113,24 +101,30 @@ impl<'a> ProgramAccountStorage<'a> { } => { storage .entry(address) - .or_insert_with(|| Vec::with_capacity(64)) - .push((index, value)); + .or_insert_with(|| HashMap::with_capacity(64)) + .insert(index, value); } - Action::EvmIncrementNonce { address } => { - let account = self.ethereum_account_mut(&address); - if account.trx_count == u64::MAX { - return Err!(ProgramError::InvalidAccountData; "Account {} - nonce overflow", account.address); - } - - account.trx_count += 1; + Action::EvmIncrementNonce { address, chain_id } => { + let mut account = self.create_balance_account(address, chain_id)?; + account.increment_nonce()?; } - Action::EvmSetCode { address, code } => { - self.deploy_contract(address, &code)?; + Action::EvmSetCode { + address, + chain_id, + code, + } => { + ContractAccount::init( + address, + chain_id, + 0, + &code, + &self.accounts, + Some(&self.keys), + )?; } - Action::EvmSelfDestruct { address } => { - storage.remove(&address); - - self.delete_account(address)?; + Action::EvmSelfDestruct { address: _ } => { + // EIP-6780: SELFDESTRUCT only in the same transaction + // do nothing, balance was already transfered } Action::ExternalInstruction { program_id, @@ -143,9 +137,17 @@ impl<'a> ProgramAccountStorage<'a> { let mut accounts_info = Vec::with_capacity(accounts.len() + 1); - accounts_info.push(self.solana_accounts[&program_id].clone()); + let program = self.accounts.get(&program_id).clone(); + accounts_info.push(program); + for meta in &accounts { - accounts_info.push(self.solana_accounts[&meta.pubkey].clone()); + let account: AccountInfo<'a> = + if meta.pubkey == self.accounts.operator_key() { + self.accounts.operator_info().clone() + } else { + self.accounts.get(&meta.pubkey).clone() + }; + accounts_info.push(account); } let instruction = Instruction { @@ -158,311 +160,68 @@ impl<'a> ProgramAccountStorage<'a> { } } - self.apply_storage(system_program, operator, storage)?; + self.apply_storage(storage)?; debug_print!("Applies done"); - Ok(AccountsReadiness::Ready) - } - - fn rearrange_actions(actions: Vec) -> Vec { - // Find all the account addresses which are scheduled to EvmSelfDestruct - let accounts_to_destroy: std::collections::HashSet<_> = actions - .iter() - .filter_map(|action| match action { - Action::EvmSelfDestruct { address } => Some(*address), - _ => None, - }) - .collect(); - - // For accounts scheduled to Self Destroy only leave NeonTransfer and NeonWithdraw actions - let mut rearranged_actions = Vec::with_capacity(actions.len()); - let mut evm_self_destruct_actions = Vec::new(); - for action in actions { - match action { - // We always apply ExternalInstruction for Solana accounts - // and NeonTransfer + NeonWithdraw - Action::ExternalInstruction { .. } - | Action::NeonTransfer { .. } - | Action::NeonWithdraw { .. } => { - rearranged_actions.push(action); - } - // We remove EvmSetStorage|EvmIncrementNonce|EvmSetCode - // if account is scheduled for destroy - Action::EvmSetStorage { address, .. } - | Action::EvmSetCode { address, .. } - | Action::EvmIncrementNonce { address } => { - if !accounts_to_destroy.contains(&address) { - rearranged_actions.push(action); - } - } - // Move EvmSelfDestruct to a separate Vec - Action::EvmSelfDestruct { .. } => { - evm_self_destruct_actions.push(action); - } - } - } - - // Constructing compound list of actions, - // first: we execute everything except SelfDestruct, - // second: execute all SelfDestructs - rearranged_actions.append(&mut evm_self_destruct_actions); - rearranged_actions + Ok(()) } - fn apply_storage( - &mut self, - system_program: &program::System<'a>, - operator: &Operator<'a>, - storage: HashMap>, - ) -> Result<(), ProgramError> { + fn apply_storage(&mut self, storage: HashMap>) -> Result<()> { const STATIC_STORAGE_LIMIT: U256 = U256::new(STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT as u128); - let mut required_account_transfers = std::collections::HashMap::new(); + let rent = Rent::get()?; for (address, storage) in storage { - let contract: &EthereumAccount<'a> = &self.ethereum_accounts[&address]; - let contract_data = contract.contract_data().expect("Contract expected"); + let mut contract = self.contract_account(address)?; + + let mut infinite_values: HashMap> = + HashMap::with_capacity(storage.len()); for (index, value) in storage { if index < STATIC_STORAGE_LIMIT { // Static Storage - Write into contract account - let index: usize = index.as_usize() * 32; - contract_data.storage()[index..index + 32].copy_from_slice(&value); + let index: usize = index.as_usize(); + contract.set_storage_value(index, &value); } else { // Infinite Storage - Write into separate account let subindex = (index & 0xFF).as_u8(); let index = index & !U256::new(0xFF); - match self.storage_accounts.entry((contract.address, index)) { - Entry::Vacant(entry) => { - let storage_address = EthereumStorageAddress::new( - self.program_id, - contract.info.key, - &index, - ); - let storage_account = self.solana_accounts.get(&storage_address.pubkey()) - .ok_or_else(|| E!(ProgramError::InvalidArgument; "Account {} - storage account not found", storage_address.pubkey()))?; - - if !solana_program::system_program::check_id(storage_account.owner) { - return Err!(ProgramError::InvalidAccountData; "Account {} - expected system or program owned", storage_address.pubkey()); - } - - if value == [0_u8; 32] { - continue; - } - - let storage = EthereumStorage::create( - contract, - storage_account, - &storage_address, - index, - subindex, - &value, - operator, - system_program, - )?; - - entry.insert(storage); - } - Entry::Occupied(mut entry) => { - let storage = entry.get_mut(); - storage.set(subindex, &value, &mut required_account_transfers)?; - } - } + infinite_values + .entry(index) + .or_insert_with(|| HashMap::with_capacity(32)) + .insert(subindex, value); } } - } - - for (_key, (info, required_lamports)) in required_account_transfers { - system_program.transfer(operator, &info, required_lamports)?; - } - Ok(()) - } + for (index, values) in infinite_values { + let cell_address = self.keys.storage_cell_address(&crate::ID, address, index); - fn process_accounts_operations( - &mut self, - system_program: &program::System<'a>, - neon_program: &program::Neon<'a>, - operator: &Operator<'a>, - accounts_operations: AccountsOperations, - ) -> Result { - let mut accounts_readiness = AccountsReadiness::Ready; - for (address, operation) in accounts_operations { - let (solana_address, bump_seed) = address.find_solana_address(self.program_id); - let solana_account = self.solana_account(&solana_address).ok_or_else(|| { - E!( - ProgramError::UninitializedAccount; - "Account {} - corresponding Solana account was not provided", - address - ) - })?; - match operation { - AccountOperation::Create { space } => { - debug_print!("Creating account (space = {})", space); - EthereumAccount::create_account( - system_program, - neon_program.key, - operator, - &address, - solana_account, - bump_seed, - MAX_PERMITTED_DATA_INCREASE.min(space), - )?; + let account = self.accounts.get(cell_address.pubkey()); + if system_program::check_id(account.owner) { + let (_, bump) = self.keys.contract_with_bump_seed(&crate::ID, address); + let sign: &[&[u8]] = &[&[ACCOUNT_SEED_VERSION], address.as_bytes(), &[bump]]; - if space > MAX_PERMITTED_DATA_INCREASE { - accounts_readiness = AccountsReadiness::NeedMoreReallocations; - } - } + let len = values.len(); + let mut storage = StorageCell::create(cell_address, len, &self.accounts, sign)?; + let mut cells = storage.cells_mut(); - AccountOperation::Resize { from, to } => { - debug_print!("Resizing account (from = {}, to = {})", from, to); - - assert_eq!(solana_account.owner, self.program_id); - - let rent = Rent::get()?; - let lamports_needed = rent - .minimum_balance(to.min(from.saturating_add(MAX_PERMITTED_DATA_INCREASE))); - let lamports_current = solana_account.lamports(); - if lamports_current < lamports_needed { - invoke( - &system_instruction::transfer( - operator.key, - solana_account.key, - lamports_needed.saturating_sub(lamports_current), - ), - &[ - (*operator.info).clone(), - solana_account.clone(), - (*system_program).clone(), - ], - )?; + assert_eq!(cells.len(), len); + for (cell, (subindex, value)) in cells.iter_mut().zip(values) { + cell.subindex = subindex; + cell.value = value; } - - let max_possible_space_per_instruction = - to.min(from + MAX_PERMITTED_DATA_INCREASE); - solana_account.realloc(max_possible_space_per_instruction, false)?; - - if max_possible_space_per_instruction < to { - accounts_readiness = AccountsReadiness::NeedMoreReallocations; + } else { + let mut storage = StorageCell::from_account(&crate::ID, account.clone())?; + for (subindex, value) in values { + storage.update(subindex, &value)?; } - } - }; - } - - Ok(accounts_readiness) - } - - /// Delete all data in the account. - fn delete_account(&mut self, address: Address) -> ProgramResult { - let account = self.ethereum_account_mut(&address); - account.trx_count = 0; - account.generation = account.generation.checked_add(1) - .ok_or_else(|| E!(ProgramError::InvalidInstructionData; "Account {} - generation overflow", address))?; - - if let Some(contract) = account.contract_data() { - contract.extension_borrow_mut().fill(0); - } - - account.code_size = 0; - - Ok(()) - } - - fn deploy_contract(&mut self, address: Address, code: &[u8]) -> ProgramResult { - let account = self.ethereum_accounts.get_mut(&address).ok_or_else( - || E!(ProgramError::UninitializedAccount; "Account {} - is not initialized", address), - )?; - - assert_eq!( - account.code_size, 0, - "Contract already deployed to address {} (code_size = {})!", - account.address, account.code_size, - ); - - let space_needed = EthereumAccount::space_needed(code.len()); - let space_actual = account.info.data_len(); - assert!( - space_actual >= space_needed, - "Not enough space for account deployment at address {} \ - (code size: {}, space needed: {}, actual space: {})", - account.address, - code.len(), - space_needed, - space_actual, - ); - - account.code_size = code - .len() - .try_into() - .expect("code.len() never exceeds u32::max"); - - let contract = account - .contract_data() - .expect("Contract data must be available at this point"); - - contract.code().copy_from_slice(code); - - Ok(()) - } - - fn transfer_neon_tokens( - &mut self, - source: &Address, - target: &Address, - value: U256, - ) -> ProgramResult { - debug_print!("Transfer {} NEONs from {} to {}", value, source, target); - - if source == target { - return Ok(()); - } - - if !self.ethereum_accounts.contains_key(source) { - return Err!(ProgramError::InvalidArgument; "Account {} - expect initialized", source); - } - if !self.ethereum_accounts.contains_key(target) { - return Err!(ProgramError::InvalidArgument; "Account {} - expect initialized", source); - } - - if self.balance(source) < value { - return Err!(ProgramError::InsufficientFunds; "Account {} - insufficient funds, required = {}", source, value); - } - - self.ethereum_account_mut(source).balance -= value; - self.ethereum_account_mut(target).balance += value; - - Ok(()) - } - - fn create_account_if_not_exists(&mut self, address: &Address) -> ProgramResult { - if self.ethereum_accounts.contains_key(address) { - return Ok(()); + storage.sync_lamports(rent, &self.accounts)?; + }; + } } - let (solana_address, bump_seed) = address.find_solana_address(self.program_id); - let info = self.solana_account(&solana_address).ok_or_else(|| { - E!( - ProgramError::InvalidArgument; - "Account {} not found in the list of Solana accounts", - solana_address - ) - })?; - - let ether_account = EthereumAccount::init( - self.program_id, - info, - ether_account::Data { - address: *address, - bump_seed, - ..Default::default() - }, - )?; - - self.ethereum_accounts - .insert(ether_account.address, ether_account); - Ok(()) } } diff --git a/evm_loader/program/src/account_storage/backend.rs b/evm_loader/program/src/account_storage/backend.rs index 2b93c0976..c38deb846 100644 --- a/evm_loader/program/src/account_storage/backend.rs +++ b/evm_loader/program/src/account_storage/backend.rs @@ -1,6 +1,6 @@ -use crate::account::EthereumAccount; use crate::account_storage::{AccountStorage, ProgramAccountStorage}; use crate::config::STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT; +use crate::error::Result; use crate::executor::OwnedAccountInfo; use crate::types::Address; use ethnum::U256; @@ -8,19 +8,13 @@ use solana_program::account_info::AccountInfo; use solana_program::{pubkey::Pubkey, sysvar::slot_hashes}; use std::convert::TryInto; -use super::find_slot_hash; - impl<'a> AccountStorage for ProgramAccountStorage<'a> { - fn neon_token_mint(&self) -> &Pubkey { - &crate::config::token_mint::ID - } - fn program_id(&self) -> &Pubkey { - self.program_id + &crate::ID } - fn operator(&self) -> &Pubkey { - self.operator + fn operator(&self) -> Pubkey { + self.accounts.operator_key() } fn block_number(&self) -> U256 { @@ -35,130 +29,116 @@ impl<'a> AccountStorage for ProgramAccountStorage<'a> { } fn block_hash(&self, slot: u64) -> [u8; 32] { - let slot_hashes_account = self - .solana_accounts - .get(&slot_hashes::ID) - .unwrap_or_else(|| { - panic!( - "Trying to get slot hash info without providing sysvar account: {}", - slot_hashes::ID - ) - }); - + let slot_hashes_account = self.accounts.get(&slot_hashes::ID); let slot_hashes_data = slot_hashes_account.data.borrow(); - find_slot_hash(slot, &slot_hashes_data[..]) - } - fn exists(&self, address: &Address) -> bool { - self.ethereum_accounts.contains_key(address) + super::block_hash::find_slot_hash(slot, &slot_hashes_data[..]) } - fn nonce(&self, address: &Address) -> u64 { - self.ethereum_account(address) - .map_or(0_u64, |a| a.trx_count) + fn nonce(&self, address: Address, chain_id: u64) -> u64 { + self.balance_account(address, chain_id) + .map_or(0_u64, |a| a.nonce()) } - fn balance(&self, address: &Address) -> U256 { - self.ethereum_account(address) - .map_or(U256::ZERO, |a| a.balance) + fn balance(&self, address: Address, chain_id: u64) -> U256 { + self.balance_account(address, chain_id) + .map_or(U256::ZERO, |a| a.balance()) } - fn code_size(&self, address: &Address) -> usize { - self.ethereum_account(address) - .map_or(0, |a| a.code_size as usize) + fn is_valid_chain_id(&self, chain_id: u64) -> bool { + crate::config::CHAIN_ID_LIST + .binary_search_by_key(&chain_id, |c| c.0) + .is_ok() } - fn code_hash(&self, address: &Address) -> [u8; 32] { - use solana_program::keccak::hash; + fn chain_id_to_token(&self, chain_id: u64) -> Pubkey { + let index = crate::config::CHAIN_ID_LIST + .binary_search_by_key(&chain_id, |c| c.0) + .unwrap(); - // https://eips.ethereum.org/EIPS/eip-1052 - // https://eips.ethereum.org/EIPS/eip-161 - if self.code_size(address) == 0 { - if self.nonce(address) == 0 && self.balance(address) == 0 { - // non-existent account - return <[u8; 32]>::default(); - } + crate::config::CHAIN_ID_LIST[index].2 + } - // account without code - return hash(&[]).to_bytes(); - } + fn default_chain_id(&self) -> u64 { + crate::config::DEFAULT_CHAIN_ID + } - self.ethereum_account(address) - .and_then(EthereumAccount::contract_data) - .map(|contract| hash(&contract.code())) - .unwrap_or_default() - .to_bytes() + fn contract_chain_id(&self, address: Address) -> Result { + let contract = self.contract_account(address)?; + Ok(contract.chain_id()) } - fn code(&self, address: &Address) -> crate::evm::Buffer { - use crate::evm::Buffer; + fn contract_pubkey(&self, address: Address) -> (Pubkey, u8) { + self.keys + .contract_with_bump_seed(self.program_id(), address) + } - if let Some(account) = self.ethereum_account(address) { - if account.code_size() == 0 { - return Buffer::empty(); - } + fn code_hash(&self, address: Address, chain_id: u64) -> [u8; 32] { + use solana_program::keccak; - unsafe { Buffer::from_account(account.info, account.code_location()) } + if let Ok(contract) = self.contract_account(address) { + keccak::hash(&contract.code()).to_bytes() } else { - Buffer::empty() + // https://eips.ethereum.org/EIPS/eip-1052 + // https://eips.ethereum.org/EIPS/eip-161 + if let Ok(account) = self.balance_account(address, chain_id) { + if account.nonce() > 0 || account.balance() > 0 { + // account without code + keccak::hash(&[]).to_bytes() + } else { + // non-existent account + <[u8; 32]>::default() + } + } else { + // non-existent account + <[u8; 32]>::default() + } } } - fn generation(&self, address: &Address) -> u32 { - self.ethereum_account(address) - .map_or(0_u32, |c| c.generation) + fn code_size(&self, address: Address) -> usize { + self.contract_account(address).map_or(0, |a| a.code_len()) } - fn storage(&self, address: &Address, index: &U256) -> [u8; 32] { - if *index < U256::from(STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT) { - let index: usize = index.as_usize() * 32; + fn code(&self, address: Address) -> crate::evm::Buffer { + self.contract_account(address) + .map_or_else(|_| crate::evm::Buffer::empty(), |a| a.code_buffer()) + } + + fn storage(&self, address: Address, index: U256) -> [u8; 32] { + if index < U256::from(STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT as u64) { + let index: usize = index.as_usize(); return self - .ethereum_account(address) - .and_then(EthereumAccount::contract_data) - .map(|c| c.storage()[index..index + 32].try_into().unwrap()) + .contract_account(address) + .map(|c| c.storage_value(index)) .unwrap_or_default(); } let subindex = (index & 0xFF).as_u8(); let index = index & !U256::new(0xFF); - self.ethereum_storage(*address, index) - .map_or_else(<[u8; 32]>::default, |a| a.get(subindex)) + self.storage_cell(address, index) + .map(|a| a.get(subindex)) + .unwrap_or_default() } fn clone_solana_account(&self, address: &Pubkey) -> OwnedAccountInfo { - let info = self.solana_accounts[address]; - OwnedAccountInfo::from_account_info(self.program_id, info) + // This is used to emulate external instruction + // One of instruction accounts can be operator + let info = if address == &self.accounts.operator_key() { + self.accounts.operator_info() + } else { + self.accounts.get(address) + }; + + OwnedAccountInfo::from_account_info(self.program_id(), info) } fn map_solana_account(&self, address: &Pubkey, action: F) -> R where F: FnOnce(&AccountInfo) -> R, { - let info = self.solana_accounts[address]; + let info = self.accounts.get(address); action(info) } - - fn solana_account_space(&self, address: &Address) -> Option { - let (pubkey, _) = self.solana_address(address); - let info = self.solana_accounts[&pubkey]; - - if solana_program::system_program::check_id(info.owner) { - return None; - } - - assert_eq!(info.owner, self.program_id); - Some(info.data_len()) - } - - fn solana_address(&self, address: &Address) -> (Pubkey, u8) { - self.ethereum_accounts.get(address).map_or_else( - || address.find_solana_address(self.program_id), - |a| (*a.info.key, a.bump_seed), - ) - } - - fn chain_id(&self) -> u64 { - crate::config::CHAIN_ID - } } diff --git a/evm_loader/program/src/account_storage/base.rs b/evm_loader/program/src/account_storage/base.rs index 1b364c27a..f160487b9 100644 --- a/evm_loader/program/src/account_storage/base.rs +++ b/evm_loader/program/src/account_storage/base.rs @@ -1,154 +1,93 @@ -use crate::account::ether_storage::EthereumStorageAddress; -use crate::account::{program, EthereumAccount, EthereumStorage, Operator, TAG_EMPTY}; -use crate::account_storage::{AccountStorage, ProgramAccountStorage}; +use crate::account::{ + AccountsDB, BalanceAccount, ContractAccount, Operator, StorageCell, Treasury, +}; +use crate::account_storage::ProgramAccountStorage; +use crate::config::DEFAULT_CHAIN_ID; +use crate::error::Result; use crate::types::Address; use ethnum::U256; -use solana_program::account_info::AccountInfo; use solana_program::clock::Clock; -use solana_program::program_error::ProgramError; -use solana_program::pubkey::Pubkey; use solana_program::system_program; use solana_program::sysvar::Sysvar; -use std::cell::RefCell; -use std::collections::{HashMap, HashSet}; -impl<'a> ProgramAccountStorage<'a> { - pub fn new( - program_id: &'a Pubkey, - operator: &Operator<'a>, - system_program: Option<&program::System<'a>>, - accounts: &'a [AccountInfo<'a>], - ) -> Result { - debug_print!("ProgramAccountStorage::new"); - - let mut solana_accounts = accounts - .iter() - .map(|a| (a.key, a)) - .collect::>(); - - solana_accounts.insert(operator.key, operator.info); - if let Some(system) = system_program { - solana_accounts.insert(system.key, system.into()); - } - - let mut ethereum_accounts = HashMap::with_capacity(accounts.len()); - let mut storage_accounts = HashMap::with_capacity(accounts.len()); - - for &account_info in solana_accounts.values() { - if account_info.owner != program_id { - continue; - } - - match crate::account::tag(program_id, account_info) { - Ok(EthereumAccount::TAG) => { - let account = EthereumAccount::from_account(program_id, account_info)?; - ethereum_accounts.insert(account.address, account); - } - Ok(EthereumStorage::TAG) => { - let account = EthereumStorage::from_account(program_id, account_info)?; - storage_accounts.insert((account.address, account.index), account); - } - Ok(_) | Err(_) => continue, - } - } - - for storage in storage_accounts.values_mut() { - let owner = ðereum_accounts[&storage.address]; - if storage.generation != owner.generation { - storage.clear(owner.generation, operator)?; - } - } +use super::keys_cache::KeysCache; +impl<'a> ProgramAccountStorage<'a> { + pub fn new(accounts: AccountsDB<'a>) -> Result { Ok(Self { - program_id, - operator: operator.key, clock: Clock::get()?, - solana_accounts, - ethereum_accounts, - empty_ethereum_accounts: RefCell::new(HashSet::new()), - storage_accounts, - empty_storage_accounts: RefCell::new(HashSet::new()), + accounts, + keys: KeysCache::new(), }) } - pub fn solana_account(&self, solana_address: &Pubkey) -> Option<&'a AccountInfo<'a>> { - self.solana_accounts.get(solana_address).copied() + pub fn operator(&self) -> &Operator<'a> { + self.accounts.operator() } - pub fn ethereum_storage(&self, address: Address, index: U256) -> Option<&EthereumStorage<'a>> { - let key = (address, index); + pub fn operator_balance(&mut self) -> &mut BalanceAccount<'a> { + self.accounts.operator_balance() + } - if let Some(account) = self.storage_accounts.get(&key) { - return Some(account); - } + pub fn treasury(&self) -> &Treasury<'a> { + self.accounts.treasury() + } - let mut empty_accounts = self.empty_storage_accounts.borrow_mut(); - if empty_accounts.contains(&key) { - return None; - } + pub fn db(&self) -> &AccountsDB<'a> { + &self.accounts + } + + pub fn storage_cell(&self, address: Address, index: U256) -> Result> { + let pubkey = self.keys.storage_cell(&crate::ID, address, index); - let storage_address = - EthereumStorageAddress::new(self.program_id, &self.solana_address(&address).0, &index); - if let Some(&account) = self.solana_accounts.get(&storage_address.pubkey()) { - assert!(solana_program::system_program::check_id(account.owner)); + let account = self.accounts.get(&pubkey); + let result = StorageCell::from_account(&crate::ID, account.clone()); - empty_accounts.insert(key); - return None; + if result.is_err() { + // Check that account is not in a legacy format + // Correct account can ether be owned by System or be valid StorageCell + assert!(system_program::check_id(account.owner)); } - panic!( - "Storage account {} {} (solana address {}) must be present in the transaction", - address, - index, - storage_address.pubkey() - ); + result } - pub fn ethereum_account(&self, address: &Address) -> Option<&EthereumAccount<'a>> { - if let Some(account) = self.ethereum_accounts.get(address) { - return Some(account); - } - - let mut empty_accounts = self.empty_ethereum_accounts.borrow_mut(); - if empty_accounts.contains(address) { - return None; - } + pub fn contract_account(&self, address: Address) -> Result> { + let pubkey = self.keys.contract(&crate::ID, address); - let (solana_address, _bump_seed) = address.find_solana_address(self.program_id); - if let Some(account) = self.solana_accounts.get(&solana_address) { - assert!( - self.is_account_empty(account), - "Empty ethereum account {address} must belong to the system program or be uninitialized" - ); + let account = self.accounts.get(&pubkey); + let result = ContractAccount::from_account(&crate::ID, account.clone()); - empty_accounts.insert(*address); - return None; + if result.is_err() { + let legacy_tag = crate::account::legacy::TAG_ACCOUNT_CONTRACT_DEPRECATED; + assert!(crate::account::validate_tag(&crate::ID, account, legacy_tag).is_err()); } - panic!("Ethereum account {address} (solana address {solana_address}) must be present in the transaction"); + result } - pub fn ethereum_account_mut(&mut self, address: &Address) -> &mut EthereumAccount<'a> { - self.ethereum_accounts.get_mut(address).unwrap() // mutable accounts always present - } + pub fn balance_account(&self, address: Address, chain_id: u64) -> Result> { + let pubkey = self.keys.balance(&crate::ID, address, chain_id); - pub fn block_accounts(&mut self, block: bool) { - for account in &mut self.ethereum_accounts.values_mut() { - account.rw_blocked = block; - } - } + let account = self.accounts.get(&pubkey); + let result = BalanceAccount::from_account(&crate::ID, account.clone(), Some(address)); + + if result.is_err() && (chain_id == DEFAULT_CHAIN_ID) { + let contract_pubkey = self.keys.contract(&crate::ID, address); + let contract = self.accounts.get(&contract_pubkey); - pub fn check_for_blocked_accounts(&self) -> Result<(), ProgramError> { - for ethereum_account in self.ethereum_accounts.values() { - ethereum_account.check_blocked()?; + let legacy_tag = crate::account::legacy::TAG_ACCOUNT_CONTRACT_DEPRECATED; + assert!(crate::account::validate_tag(&crate::ID, contract, legacy_tag).is_err()); } - Ok(()) + result } - pub fn is_account_empty(&self, account: &AccountInfo) -> bool { - system_program::check_id(account.owner) - || (account.owner == self.program_id() - && (account.data_is_empty() || account.data.borrow()[0] == TAG_EMPTY)) + pub fn create_balance_account( + &self, + address: Address, + chain_id: u64, + ) -> Result> { + BalanceAccount::create(address, chain_id, &self.accounts, Some(&self.keys)) } } diff --git a/evm_loader/program/src/account_storage/block_hash.rs b/evm_loader/program/src/account_storage/block_hash.rs new file mode 100644 index 000000000..dd06bd2b2 --- /dev/null +++ b/evm_loader/program/src/account_storage/block_hash.rs @@ -0,0 +1,69 @@ +use solana_program::slot_history::Slot; +use std::cmp::Ordering; + +#[must_use] +pub fn find_slot_hash(value: Slot, slot_hashes_data: &[u8]) -> [u8; 32] { + let slot_hashes_len = u64::from_le_bytes(slot_hashes_data[..8].try_into().unwrap()); + + // copy-paste from slice::binary_search + let mut size = usize::try_from(slot_hashes_len).unwrap() - 1; + let mut left = 0; + let mut right = size; + + while left < right { + let mid = left + size / 2; + let offset = mid * 40 + 8; // +8 - the first 8 bytes for the len of vector + + let slot = u64::from_le_bytes(slot_hashes_data[offset..][..8].try_into().unwrap()); + let cmp = value.cmp(&slot); + + // The reason why we use if/else control flow rather than match + // is because match reorders comparison operations, which is perf sensitive. + // This is x86 asm for u8: https://rust.godbolt.org/z/8Y8Pra. + if cmp == Ordering::Less { + left = mid + 1; + } else if cmp == Ordering::Greater { + right = mid; + } else { + return slot_hashes_data[(offset + 8)..][..32].try_into().unwrap(); + } + + size = right - left; + } + + generate_fake_slot_hash(value) +} + +#[must_use] +pub fn generate_fake_slot_hash(slot: Slot) -> [u8; 32] { + let slot_bytes: [u8; 8] = slot.to_be_bytes(); + let mut initial = 0; + for b in slot_bytes { + if b != 0 { + break; + } + initial += 1; + } + let slot_slice = &slot_bytes[initial..]; + let slot_slice_len = slot_slice.len(); + let mut hash = [255; 32]; + hash[32 - slot_slice_len - 1] = 0; + hash[(32 - slot_slice_len)..].copy_from_slice(slot_slice); + hash +} + +#[test] +fn test_generate_fake_slot_hash() { + let slot = 0x46; + let mut expected: [u8; 32] = [255; 32]; + expected[30] = 0; + expected[31] = 0x46; + assert_eq!(generate_fake_slot_hash(slot), expected); + + let slot = 0x3e8; + let mut expected: [u8; 32] = [255; 32]; + expected[29] = 0; + expected[30] = 0x03; + expected[31] = 0xe8; + assert_eq!(generate_fake_slot_hash(slot), expected); +} diff --git a/evm_loader/program/src/account_storage/keys_cache.rs b/evm_loader/program/src/account_storage/keys_cache.rs new file mode 100644 index 000000000..a1922a980 --- /dev/null +++ b/evm_loader/program/src/account_storage/keys_cache.rs @@ -0,0 +1,96 @@ +use std::{cell::RefCell, collections::HashMap}; + +use ethnum::U256; +use solana_program::pubkey::Pubkey; + +use crate::{account::StorageCellAddress, types::Address}; + +type ContractKey = Address; +type BalanceKey = (Address, u64); +type StorageKey = (Address, U256); + +pub struct KeysCache { + contracts: RefCell>, + balances: RefCell>, + storage_cells: RefCell>, +} + +impl KeysCache { + #[must_use] + pub fn new() -> Self { + Self { + contracts: RefCell::new(HashMap::with_capacity(8)), + balances: RefCell::new(HashMap::with_capacity(8)), + storage_cells: RefCell::new(HashMap::with_capacity(32)), + } + } + + #[must_use] + pub fn contract_with_bump_seed(&self, program_id: &Pubkey, address: Address) -> (Pubkey, u8) { + *self + .contracts + .borrow_mut() + .entry(address) + .or_insert_with_key(|a| a.find_solana_address(program_id)) + } + + #[must_use] + pub fn contract(&self, program_id: &Pubkey, address: Address) -> Pubkey { + self.contract_with_bump_seed(program_id, address).0 + } + + #[must_use] + pub fn balance_with_bump_seed( + &self, + program_id: &Pubkey, + address: Address, + chain_id: u64, + ) -> (Pubkey, u8) { + *self + .balances + .borrow_mut() + .entry((address, chain_id)) + .or_insert_with_key(|(a, chain_id)| a.find_balance_address(program_id, *chain_id)) + } + + #[must_use] + pub fn balance(&self, program_id: &Pubkey, address: Address, chain_id: u64) -> Pubkey { + self.balance_with_bump_seed(program_id, address, chain_id).0 + } + + #[must_use] + pub fn storage_cell(&self, program_id: &Pubkey, address: Address, index: U256) -> Pubkey { + *self + .storage_cells + .borrow_mut() + .entry((address, index)) + .or_insert_with(|| { + let base = self.contract(program_id, address); + StorageCellAddress::new(program_id, &base, &index) + }) + .pubkey() + } + + #[must_use] + pub fn storage_cell_address( + &self, + program_id: &Pubkey, + address: Address, + index: U256, + ) -> StorageCellAddress { + *self + .storage_cells + .borrow_mut() + .entry((address, index)) + .or_insert_with(|| { + let base = self.contract(program_id, address); + StorageCellAddress::new(program_id, &base, &index) + }) + } +} + +impl Default for KeysCache { + fn default() -> Self { + Self::new() + } +} diff --git a/evm_loader/program/src/account_storage/mod.rs b/evm_loader/program/src/account_storage/mod.rs index 27e8c3978..5ad84fbdb 100644 --- a/evm_loader/program/src/account_storage/mod.rs +++ b/evm_loader/program/src/account_storage/mod.rs @@ -1,19 +1,13 @@ -use crate::account::EthereumAccount; -use crate::executor::{Action, OwnedAccountInfo}; +use crate::error::Result; +use crate::executor::OwnedAccountInfo; use crate::types::Address; use ethnum::U256; use maybe_async::maybe_async; use solana_program::account_info::AccountInfo; #[cfg(target_os = "solana")] -use { - crate::account::EthereumStorage, solana_program::clock::Clock, std::cell::RefCell, - std::collections::HashSet, -}; +use {crate::account::AccountsDB, solana_program::clock::Clock}; use solana_program::pubkey::Pubkey; -use solana_program::slot_history::Slot; -use std::cmp::Ordering; -use std::collections::HashMap; #[cfg(target_os = "solana")] mod apply; @@ -21,49 +15,27 @@ mod apply; mod backend; #[cfg(target_os = "solana")] mod base; +mod block_hash; +pub use block_hash::find_slot_hash; -#[derive(Debug)] -pub enum AccountOperation { - Create { space: usize }, - - Resize { from: usize, to: usize }, -} - -pub type AccountsOperations = Vec<(Address, AccountOperation)>; - -#[derive(Debug, PartialEq, Eq)] -pub enum AccountsReadiness { - Ready, - NeedMoreReallocations, -} +mod keys_cache; +pub use keys_cache::KeysCache; #[cfg(target_os = "solana")] pub struct ProgramAccountStorage<'a> { - program_id: &'a Pubkey, - operator: &'a Pubkey, clock: Clock, - - solana_accounts: HashMap<&'a Pubkey, &'a AccountInfo<'a>>, - - ethereum_accounts: HashMap>, - empty_ethereum_accounts: RefCell>, - - storage_accounts: HashMap<(Address, U256), EthereumStorage<'a>>, - empty_storage_accounts: RefCell>, + accounts: AccountsDB<'a>, + keys: keys_cache::KeysCache, } /// Account storage /// Trait to access account info #[maybe_async(?Send)] pub trait AccountStorage { - /// Get `NEON` token mint - fn neon_token_mint(&self) -> &Pubkey; - /// Get `NeonEVM` program id fn program_id(&self) -> &Pubkey; - /// Get operator pubkey - fn operator(&self) -> &Pubkey; + fn operator(&self) -> Pubkey; /// Get block number fn block_number(&self) -> U256; @@ -71,27 +43,30 @@ pub trait AccountStorage { fn block_timestamp(&self) -> U256; /// Get block hash async fn block_hash(&self, number: u64) -> [u8; 32]; - /// Get chain id - fn chain_id(&self) -> u64; - /// Check if ethereum account exists - async fn exists(&self, address: &Address) -> bool; /// Get account nonce - async fn nonce(&self, address: &Address) -> u64; + async fn nonce(&self, address: Address, chain_id: u64) -> u64; /// Get account balance - async fn balance(&self, address: &Address) -> U256; + async fn balance(&self, address: Address, chain_id: u64) -> U256; + + fn is_valid_chain_id(&self, chain_id: u64) -> bool; + fn chain_id_to_token(&self, chain_id: u64) -> Pubkey; + fn default_chain_id(&self) -> u64; + + /// Get contract chain_id + async fn contract_chain_id(&self, address: Address) -> Result; + /// Get contract solana address + fn contract_pubkey(&self, address: Address) -> (Pubkey, u8); - /// Get code size - async fn code_size(&self, address: &Address) -> usize; /// Get code hash - async fn code_hash(&self, address: &Address) -> [u8; 32]; + async fn code_hash(&self, address: Address, chain_id: u64) -> [u8; 32]; + /// Get code size + async fn code_size(&self, address: Address) -> usize; /// Get code data - async fn code(&self, address: &Address) -> crate::evm::Buffer; - /// Get contract generation - async fn generation(&self, address: &Address) -> u32; + async fn code(&self, address: Address) -> crate::evm::Buffer; /// Get data from storage - async fn storage(&self, address: &Address, index: &U256) -> [u8; 32]; + async fn storage(&self, address: Address, index: U256) -> [u8; 32]; /// Clone existing solana account async fn clone_solana_account(&self, address: &Pubkey) -> OwnedAccountInfo; @@ -100,121 +75,4 @@ pub trait AccountStorage { async fn map_solana_account(&self, address: &Pubkey, action: F) -> R where F: FnOnce(&AccountInfo) -> R; - - /// Resolve account solana address and bump seed - fn solana_address(&self, address: &Address) -> (Pubkey, u8) { - address.find_solana_address(self.program_id()) - } - - /// Solana account data len - async fn solana_account_space(&self, address: &Address) -> Option; - - async fn calc_accounts_operations(&self, actions: &[Action]) -> AccountsOperations { - let mut accounts = HashMap::new(); - for action in actions { - let (address, code_size) = match action { - Action::NeonTransfer { target, .. } => (target, 0), - Action::EvmSelfDestruct { address } => (address, 0), - Action::EvmSetCode { address, code, .. } => (address, code.len()), - _ => continue, - }; - - let space_needed = EthereumAccount::space_needed(code_size); - if let Some(max_size) = accounts.get_mut(&address) { - *max_size = space_needed.max(*max_size); - continue; - } - accounts.insert(address, space_needed); - } - - let mut result = AccountsOperations::new(); - - for (address, space_needed) in accounts { - match self.solana_account_space(address).await { - None => result.push(( - *address, - AccountOperation::Create { - space: space_needed, - }, - )), - Some(space_current) if space_current < space_needed => result.push(( - *address, - AccountOperation::Resize { - from: space_current, - to: space_needed, - }, - )), - _ => (), - } - } - - result - } -} - -#[must_use] -pub fn find_slot_hash(value: Slot, slot_hashes_data: &[u8]) -> [u8; 32] { - let slot_hashes_len = u64::from_le_bytes(slot_hashes_data[..8].try_into().unwrap()); - - // copy-paste from slice::binary_search - let mut size = usize::try_from(slot_hashes_len).unwrap() - 1; - let mut left = 0; - let mut right = size; - - while left < right { - let mid = left + size / 2; - let offset = mid * 40 + 8; // +8 - the first 8 bytes for the len of vector - - let slot = u64::from_le_bytes(slot_hashes_data[offset..][..8].try_into().unwrap()); - let cmp = value.cmp(&slot); - - // The reason why we use if/else control flow rather than match - // is because match reorders comparison operations, which is perf sensitive. - // This is x86 asm for u8: https://rust.godbolt.org/z/8Y8Pra. - if cmp == Ordering::Less { - left = mid + 1; - } else if cmp == Ordering::Greater { - right = mid; - } else { - return slot_hashes_data[(offset + 8)..][..32].try_into().unwrap(); - } - - size = right - left; - } - - generate_fake_slot_hash(value) -} - -#[must_use] -pub fn generate_fake_slot_hash(slot: Slot) -> [u8; 32] { - let slot_bytes: [u8; 8] = slot.to_be_bytes(); - let mut initial = 0; - for b in slot_bytes { - if b != 0 { - break; - } - initial += 1; - } - let slot_slice = &slot_bytes[initial..]; - let slot_slice_len = slot_slice.len(); - let mut hash = [255; 32]; - hash[32 - slot_slice_len - 1] = 0; - hash[(32 - slot_slice_len)..].copy_from_slice(slot_slice); - hash -} - -#[test] -fn test_generate_fake_slot_hash() { - let slot = 0x46; - let mut expected: [u8; 32] = [255; 32]; - expected[30] = 0; - expected[31] = 0x46; - assert_eq!(generate_fake_slot_hash(slot), expected); - - let slot = 0x3e8; - let mut expected: [u8; 32] = [255; 32]; - expected[29] = 0; - expected[30] = 0x03; - expected[31] = 0xe8; - assert_eq!(generate_fake_slot_hash(slot), expected); } From bd353f9242a6b5e9df6ed1cab55f9b7c75650d19 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Tue, 14 Nov 2023 18:05:25 +0300 Subject: [PATCH 050/318] [Multi Tokens] Config --- .../api/src/api_server/handlers/get_config.rs | 27 ++ evm_loader/lib/src/commands/get_config.rs | 289 ++++++++++++++++++ evm_loader/program-macro/src/config_parser.rs | 228 +++++++------- evm_loader/program-macro/src/lib.rs | 175 +++++------ evm_loader/program/config/common.toml | 6 +- evm_loader/program/config/default.toml | 20 +- evm_loader/program/config/devnet.toml | 12 +- evm_loader/program/config/elf_params.toml | 13 - evm_loader/program/config/govertest.toml | 8 +- evm_loader/program/config/mainnet.toml | 8 +- evm_loader/program/config/testnet.toml | 8 +- evm_loader/program/src/config.rs | 18 +- .../src/instruction/config_get_chain_count.rs | 18 ++ .../src/instruction/config_get_chain_info.rs | 20 ++ .../src/instruction/config_get_environment.rs | 29 ++ .../config_get_property_by_index.rs | 20 ++ .../config_get_property_by_name.rs | 24 ++ .../instruction/config_get_property_count.rs | 18 ++ .../src/instruction/config_get_status.rs | 19 ++ .../src/instruction/config_get_version.rs | 22 ++ 20 files changed, 709 insertions(+), 273 deletions(-) create mode 100644 evm_loader/api/src/api_server/handlers/get_config.rs create mode 100644 evm_loader/lib/src/commands/get_config.rs delete mode 100644 evm_loader/program/config/elf_params.toml create mode 100644 evm_loader/program/src/instruction/config_get_chain_count.rs create mode 100644 evm_loader/program/src/instruction/config_get_chain_info.rs create mode 100644 evm_loader/program/src/instruction/config_get_environment.rs create mode 100644 evm_loader/program/src/instruction/config_get_property_by_index.rs create mode 100644 evm_loader/program/src/instruction/config_get_property_by_name.rs create mode 100644 evm_loader/program/src/instruction/config_get_property_count.rs create mode 100644 evm_loader/program/src/instruction/config_get_status.rs create mode 100644 evm_loader/program/src/instruction/config_get_version.rs diff --git a/evm_loader/api/src/api_server/handlers/get_config.rs b/evm_loader/api/src/api_server/handlers/get_config.rs new file mode 100644 index 000000000..34aedb8e5 --- /dev/null +++ b/evm_loader/api/src/api_server/handlers/get_config.rs @@ -0,0 +1,27 @@ +use crate::api_server::handlers::process_error; +use crate::{api_context, NeonApiState}; +use actix_request_identifier::RequestId; +use actix_web::routes; +use actix_web::{http::StatusCode, Responder}; +use std::convert::Into; + +use crate::commands::get_config as GetConfigCommand; + +use super::process_result; + +#[tracing::instrument(skip(state, request_id), fields(id = request_id.as_str()))] +#[routes] +#[post("/config")] +#[get("/config")] +pub async fn get_config(state: NeonApiState, request_id: RequestId) -> impl Responder { + let rpc_client = match api_context::build_rpc_client(&state, None, None).await { + Ok(rpc_client) => rpc_client, + Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), + }; + + process_result( + &GetConfigCommand::execute(rpc_client.as_ref(), state.config.evm_loader) + .await + .map_err(Into::into), + ) +} diff --git a/evm_loader/lib/src/commands/get_config.rs b/evm_loader/lib/src/commands/get_config.rs new file mode 100644 index 000000000..8db6fd2c6 --- /dev/null +++ b/evm_loader/lib/src/commands/get_config.rs @@ -0,0 +1,289 @@ +use base64::Engine; +use std::collections::BTreeMap; +use tokio::sync::{Mutex, MutexGuard, OnceCell}; + +use serde::{Deserialize, Serialize}; +use solana_program_test::{ProgramTest, ProgramTestContext}; +use solana_sdk::{ + account::{Account, AccountSharedData}, + account_utils::StateMut, + bpf_loader, bpf_loader_deprecated, + bpf_loader_upgradeable::{self, UpgradeableLoaderState}, + instruction::Instruction, + pubkey::Pubkey, + rent::Rent, + signer::Signer, + transaction::Transaction, +}; + +use crate::{rpc::Rpc, NeonError, NeonResult}; + +use serde_with::{serde_as, DisplayFromStr}; + +#[derive(Debug, Serialize)] +pub enum Status { + Ok, + Emergency, + Unknown, +} + +#[serde_as] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ChainInfo { + pub id: u64, + pub name: String, + #[serde_as(as = "DisplayFromStr")] + pub token: Pubkey, +} + +#[serde_as] +#[derive(Debug, Serialize)] +pub struct GetConfigResponse { + pub version: String, + pub revision: String, + pub status: Status, + pub environment: String, + pub chains: Vec, + pub config: BTreeMap, +} + +static PROGRAM_TEST: OnceCell> = OnceCell::const_new(); + +async fn read_program_data_from_account( + rpc_client: &dyn Rpc, + program_id: Pubkey, +) -> NeonResult> { + let Some(account) = rpc_client.get_account(&program_id).await?.value else { + return Err(NeonError::AccountNotFound(program_id)); + }; + + if account.owner == bpf_loader::id() || account.owner == bpf_loader_deprecated::id() { + return Ok(account.data); + } + + if account.owner != bpf_loader_upgradeable::id() { + return Err(NeonError::AccountIsNotBpf(program_id)); + } + + if let Ok(UpgradeableLoaderState::Program { + programdata_address, + }) = account.state() + { + let Some(programdata_account) = rpc_client.get_account(&programdata_address).await?.value else { + return Err(NeonError::AssociatedPdaNotFound(programdata_address, program_id)); + }; + + let offset = UpgradeableLoaderState::size_of_programdata_metadata(); + let program_data = &programdata_account.data[offset..]; + + Ok(program_data.to_vec()) + } else { + Err(NeonError::AccountIsNotUpgradeable(program_id)) + } +} + +async fn lock_program_test( + program_id: Pubkey, + program_data: Vec, +) -> MutexGuard<'static, ProgramTestContext> { + async fn init_program_test() -> Mutex { + let program_test = ProgramTest::default(); + let context = program_test.start_with_context().await; + Mutex::new(context) + } + + let mut context = PROGRAM_TEST + .get_or_init(init_program_test) + .await + .lock() + .await; + + context.set_account( + &program_id, + &AccountSharedData::from(Account { + lamports: Rent::default().minimum_balance(program_data.len()).max(1), + data: program_data, + owner: bpf_loader::id(), + executable: true, + rent_epoch: 0, + }), + ); + + context +} + +enum ConfigSimulator<'r> { + Rpc(Pubkey, &'r dyn Rpc), + ProgramTest(MutexGuard<'static, ProgramTestContext>), +} + +impl<'r> ConfigSimulator<'r> { + pub async fn new( + rpc_client: &'r dyn Rpc, + program_id: Pubkey, + ) -> NeonResult> { + let simulator = if rpc_client.can_simulate_transaction() { + let identity = rpc_client.identity().await?; + Self::Rpc(identity, rpc_client) + } else { + let program_data = read_program_data_from_account(rpc_client, program_id).await?; + let mut program_test = lock_program_test(program_id, program_data).await; + program_test.get_new_latest_blockhash().await?; + + Self::ProgramTest(program_test) + }; + + Ok(simulator) + } + + async fn simulate_config( + &mut self, + program_id: Pubkey, + instruction: u8, + data: &[u8], + ) -> NeonResult> { + fn base64_decode(s: &str) -> Vec { + base64::engine::general_purpose::STANDARD.decode(s).unwrap() + } + + let input = [&[instruction], data].concat(); + + let logs = match self { + ConfigSimulator::Rpc(signer, rpc) => { + let result = rpc + .simulate_transaction( + Some(*signer), + &[Instruction::new_with_bytes(program_id, &input, vec![])], + ) + .await? + .value; + + if let Some(e) = result.err { + return Err(e.into()); + } + result.logs.unwrap() + } + ConfigSimulator::ProgramTest(context) => { + let payer_pubkey = context.payer.pubkey(); + let tx = Transaction::new_signed_with_payer( + &[Instruction::new_with_bytes(program_id, &input, vec![])], + Some(&payer_pubkey), + &[&context.payer], + context.last_blockhash, + ); + let result = context + .banks_client + .simulate_transaction(tx) + .await + .map_err(|e| NeonError::from(Box::new(e)))?; + + result.result.unwrap()?; + result.simulation_details.unwrap().logs + } + }; + + // Program return: 53DfF883gyixYNXnM7s5xhdeyV8mVk9T4i2hGV9vG9io AQAAAAAAAAA= + let return_data = logs + .into_iter() + .find_map(|msg| { + let prefix = std::format!("Program return: {program_id} "); + msg.strip_prefix(&prefix).map(base64_decode) + }) + .unwrap(); + + Ok(return_data) + } +} + +async fn get_version( + context: &mut ConfigSimulator<'_>, + program_id: Pubkey, +) -> NeonResult<(String, String)> { + let return_data = context.simulate_config(program_id, 0xA7, &[]).await?; + let (version, revision) = bincode::deserialize(&return_data)?; + + Ok((version, revision)) +} + +async fn get_status(context: &mut ConfigSimulator<'_>, program_id: Pubkey) -> NeonResult { + let return_data = context.simulate_config(program_id, 0xA6, &[]).await?; + match return_data[0] { + 0 => Ok(Status::Emergency), + 1 => Ok(Status::Ok), + _ => Ok(Status::Unknown), + } +} + +async fn get_environment( + context: &mut ConfigSimulator<'_>, + program_id: Pubkey, +) -> NeonResult { + let return_data = context.simulate_config(program_id, 0xA2, &[]).await?; + let environment = String::from_utf8(return_data)?; + + Ok(environment) +} + +async fn get_chains( + context: &mut ConfigSimulator<'_>, + program_id: Pubkey, +) -> NeonResult> { + let mut result = Vec::new(); + + let return_data = context.simulate_config(program_id, 0xA0, &[]).await?; + let chain_count = return_data.as_slice().try_into()?; + let chain_count = usize::from_le_bytes(chain_count); + + for i in 0..chain_count { + let index = i.to_le_bytes(); + let return_data = context.simulate_config(program_id, 0xA1, &index).await?; + + let (id, name, token) = bincode::deserialize(&return_data)?; + result.push(ChainInfo { id, name, token }); + } + + Ok(result) +} + +async fn get_properties( + context: &mut ConfigSimulator<'_>, + program_id: Pubkey, +) -> NeonResult> { + let mut result = BTreeMap::new(); + + let return_data = context.simulate_config(program_id, 0xA3, &[]).await?; + let count = return_data.as_slice().try_into()?; + let count = usize::from_le_bytes(count); + + for i in 0..count { + let index = i.to_le_bytes(); + let return_data = context.simulate_config(program_id, 0xA4, &index).await?; + + let (name, value) = bincode::deserialize(&return_data)?; + result.insert(name, value); + } + + Ok(result) +} + +pub async fn execute(rpc_client: &dyn Rpc, program_id: Pubkey) -> NeonResult { + let mut simulator = ConfigSimulator::new(rpc_client, program_id).await?; + + let (version, revision) = get_version(&mut simulator, program_id).await?; + + Ok(GetConfigResponse { + version, + revision, + status: get_status(&mut simulator, program_id).await?, + environment: get_environment(&mut simulator, program_id).await?, + chains: get_chains(&mut simulator, program_id).await?, + config: get_properties(&mut simulator, program_id).await?, + }) +} + +pub async fn read_chains(rpc_client: &dyn Rpc, program_id: Pubkey) -> NeonResult> { + let mut simulator = ConfigSimulator::new(rpc_client, program_id).await?; + + let chains = get_chains(&mut simulator, program_id).await?; + Ok(chains) +} diff --git a/evm_loader/program-macro/src/config_parser.rs b/evm_loader/program-macro/src/config_parser.rs index 7d79de7a2..51848ae8f 100644 --- a/evm_loader/program-macro/src/config_parser.rs +++ b/evm_loader/program-macro/src/config_parser.rs @@ -1,50 +1,93 @@ -use std::{collections::HashMap, path::PathBuf}; +use std::path::PathBuf; use itertools::Itertools; -use proc_macro::TokenStream; +use proc_macro2::Literal; use quote::quote; use serde::Deserialize; use syn::{ parse::{Parse, ParseStream}, - parse_str, Expr, Ident, LitFloat, LitInt, LitStr, Type, + parse_str, Ident, Lit, LitBool, LitFloat, LitInt, LitStr, Type, }; +use toml::Table; #[derive(Deserialize)] pub struct NetSpecificConfig { - pub chain_id: u64, + pub program_id: String, pub operators_whitelist: Vec, - pub token_mint: TokenMint, + pub neon_chain_id: u64, + pub neon_token_mint: String, + pub chains: Vec, } impl Parse for NetSpecificConfig { fn parse(input: ParseStream) -> syn::Result { - let file_relative_path: LitStr = input.parse()?; - let mut file_path = PathBuf::new(); - file_path.push(std::env::var("CARGO_MANIFEST_DIR").map_err(|_| { - syn::Error::new( - input.span(), - "This proc macro should be called from a Cargo project", - ) - })?); - file_path.push(file_relative_path.value()); - let file_contents = std::fs::read(&file_path).map_err(|_| { - syn::Error::new( - input.span(), - format!("{} should be a valid path", file_path.display()), - ) - })?; - toml::from_slice(&file_contents).map_err(|e| syn::Error::new(input.span(), e.to_string())) + let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); + let file_relative_path = input.parse::()?.value(); + + let file_path = PathBuf::from_iter([manifest_dir, file_relative_path]); + + let file_contents = std::fs::read_to_string(file_path).unwrap(); + + let root = file_contents.parse::().unwrap(); + + let program_id = root["program_id"].as_str().unwrap().to_string(); + let operators_whitelist = root["operators_whitelist"] + .as_array() + .unwrap() + .iter() + .map(|v| v.as_str().unwrap().to_string()) + .collect::>(); + + let chains = root["chain"] + .as_table() + .unwrap() + .iter() + .map(|(name, table)| { + let table = table.as_table().unwrap(); + Chain { + id: table["id"].as_integer().unwrap().try_into().unwrap(), + name: name.clone(), + token: table["token"].as_str().unwrap().to_string(), + } + }) + .collect::>(); + + let (neon_chain_id, neon_token_mint) = chains + .iter() + .find_map(|c| { + if c.name == "neon" { + Some((c.id, c.token.clone())) + } else { + None + } + }) + .unwrap(); + + Ok(Self { + program_id, + operators_whitelist, + neon_chain_id, + neon_token_mint, + chains, + }) } } -#[derive(Deserialize)] -pub struct TokenMint { - pub neon_token_mint: String, - pub decimals: u8, +#[derive(Deserialize, Debug)] +pub struct Chain { + pub id: u64, + pub name: String, + pub token: String, +} + +pub struct CommonVariable { + pub name: Ident, + pub r#type: Type, + pub value: Lit, } pub struct CommonConfig { - pub token_stream: TokenStream, + pub variables: Vec, } impl Parse for CommonConfig { @@ -58,58 +101,62 @@ impl Parse for CommonConfig { ) })?); file_path.push(file_relative_path.value()); - let file_contents = std::fs::read(&file_path).map_err(|_| { + let file_contents = std::fs::read_to_string(&file_path).map_err(|_| { syn::Error::new( input.span(), format!("{} should be a valid path", file_path.display()), ) })?; - let config: HashMap = toml::from_slice(&file_contents) + let config = file_contents + .parse::
() .map_err(|e| syn::Error::new(input.span(), e.to_string()))?; + let variables: Vec<_> = config .into_iter() .map(move |(name, value)| { - let uppercased_name = name.to_uppercase(); - let ident_name: Ident = parse_str(&uppercased_name)?; - let neon_ident_name: Ident = parse_str(&format!("NEON_{uppercased_name}"))?; + let name = name.to_uppercase(); + let name: Ident = parse_str(&name)?; + match value { - toml::Value::Float(v) => { - let v: LitFloat = parse_str(&v.to_string())?; - Ok(quote! { - pub const #ident_name: f64 = #v; - neon_elf_param!(#neon_ident_name, formatcp!("{}", #ident_name)); - }) - } - toml::Value::Integer(v) => { - let v: LitInt = parse_str(&v.to_string())?; - Ok(quote! { - pub const #ident_name: u64 = #v; - neon_elf_param!(#neon_ident_name, formatcp!("{}", #ident_name)); - }) - } - toml::Value::String(v) => Ok(quote! { - pub const #ident_name: &str = #v; - neon_elf_param!(#neon_ident_name, formatcp!("{}", #ident_name)); + toml::Value::Float(v) => Ok(CommonVariable { + name, + r#type: Type::Verbatim(quote!(f64)), + value: Lit::new(Literal::f64_unsuffixed(v)), + }), + toml::Value::Integer(v) => Ok(CommonVariable { + name, + r#type: Type::Verbatim(quote!(u64)), + value: Lit::new(Literal::i64_unsuffixed(v)), }), - toml::Value::Boolean(v) => Ok(quote! { - pub const #ident_name: bool = #v; - neon_elf_param!(#neon_ident_name, formatcp!("{}", #ident_name)); + toml::Value::String(v) => Ok(CommonVariable { + name, + r#type: Type::Verbatim(quote!(&str)), + value: Lit::Str(LitStr::new(&v, input.span())), + }), + toml::Value::Boolean(v) => Ok(CommonVariable { + name, + r#type: Type::Verbatim(quote!(bool)), + value: Lit::Bool(LitBool::new(v, input.span())), }), toml::Value::Array(ref array) => match (array.get(0), array.get(1)) { (Some(toml::Value::Integer(v)), Some(toml::Value::String(t))) => { - let v: LitInt = parse_str(&v.to_string())?; + let s = v.to_string(); + let v: LitInt = parse_str(&s)?; let t: Type = parse_str(t)?; - Ok(quote! { - pub const #ident_name: #t = #v; - neon_elf_param!(#neon_ident_name, formatcp!("{}", #ident_name)); + Ok(CommonVariable { + name, + r#type: t, + value: Lit::Int(v), }) } (Some(toml::Value::Float(v)), Some(toml::Value::String(t))) => { - let v: LitFloat = parse_str(&v.to_string())?; + let s = v.to_string(); + let v: LitFloat = parse_str(&s)?; let t: Type = parse_str(t)?; - Ok(quote! { - pub const #ident_name: #t = #v; - neon_elf_param!(#neon_ident_name, formatcp!("{}", #ident_name)); + Ok(CommonVariable { + name, + r#type: t, + value: Lit::Float(v), }) } _ => Err(syn::Error::new( @@ -123,69 +170,8 @@ impl Parse for CommonConfig { )), } }) - .flatten_ok() .try_collect()?; - Ok(Self { - token_stream: quote! {#(#variables)*}.into(), - }) - } -} - -#[derive(Deserialize)] -struct InternalElfParams { - env: HashMap, - formatcp: HashMap, -} - -pub struct ElfParams { - pub token_stream: TokenStream, -} - -impl Parse for ElfParams { - fn parse(input: ParseStream) -> syn::Result { - let file_relative_path: LitStr = input.parse()?; - let mut file_path = PathBuf::new(); - file_path.push(std::env::var("CARGO_MANIFEST_DIR").map_err(|_| { - syn::Error::new( - input.span(), - "This proc macro should be called from a Cargo project", - ) - })?); - file_path.push(file_relative_path.value()); - let file_contents = std::fs::read(&file_path).map_err(|_| { - syn::Error::new( - input.span(), - format!("{} should be a valid path", file_path.display()), - ) - })?; - let InternalElfParams { env, formatcp } = toml::from_slice(&file_contents) - .map_err(|e| syn::Error::new(input.span(), e.to_string()))?; - let env_tokens = env - .into_iter() - .map(|(name, env_name)| { - let name_ident: Ident = parse_str(&name.to_uppercase())?; - Ok(quote! { neon_elf_param!(#name_ident, env!(#env_name)); }) - }) - .flatten_ok() - .try_collect::<_, Vec<_>, syn::Error>()?; - - let formatcp_tokens = formatcp - .into_iter() - .map(|(name, value)| { - let name_ident: Ident = parse_str(&name.to_uppercase())?; - let value_expr: Expr = parse_str(&value)?; - Ok(quote! { neon_elf_param!(#name_ident, formatcp!("{}", #value_expr)); }) - }) - .flatten_ok() - .try_collect::<_, Vec<_>, syn::Error>()?; - - Ok(Self { - token_stream: quote! { - #(#env_tokens)* - #(#formatcp_tokens)* - } - .into(), - }) + Ok(Self { variables }) } } diff --git a/evm_loader/program-macro/src/lib.rs b/evm_loader/program-macro/src/lib.rs index ed88c6dff..1a96de2bf 100644 --- a/evm_loader/program-macro/src/lib.rs +++ b/evm_loader/program-macro/src/lib.rs @@ -3,54 +3,17 @@ mod config_parser; -use config_parser::{CommonConfig, ElfParams, NetSpecificConfig, TokenMint}; +use std::collections::BTreeMap; + +use config_parser::{CommonConfig, NetSpecificConfig}; use proc_macro::TokenStream; use syn::parse::{Parse, ParseStream}; -use syn::punctuated::Punctuated; use syn::{parse_macro_input, Expr, Ident, LitStr, Result, Token}; use quote::quote; extern crate proc_macro; -struct OperatorsWhitelistInput { - list: Punctuated, -} - -impl Parse for OperatorsWhitelistInput { - fn parse(input: ParseStream) -> Result { - let list = Punctuated::parse_terminated(input)?; - Ok(Self { list }) - } -} - -#[proc_macro] -pub fn operators_whitelist(tokens: TokenStream) -> TokenStream { - let input = parse_macro_input!(tokens as OperatorsWhitelistInput); - - let mut operators: Vec> = input - .list - .iter() - .map(LitStr::value) - .map(|key| { - bs58::decode(key) - .into_vec() - .expect("Pubkey is base64 encoded") - }) - .collect(); - - operators.sort_unstable(); - - let len = operators.len(); - - quote! { - pub static AUTHORIZED_OPERATOR_LIST: [::solana_program::pubkey::Pubkey; #len] = [ - #(::solana_program::pubkey::Pubkey::new_from_array([#((#operators),)*]),)* - ]; - } - .into() -} - struct ElfParamInput { name: Ident, _separator: Token![,], @@ -94,88 +57,96 @@ pub fn neon_elf_param(tokens: TokenStream) -> TokenStream { .into() } -struct ElfParamIdInput { - name: Ident, - _separator: Token![,], - value: LitStr, -} +/// # Panics +/// Panic at compile time if config file is not correct +#[proc_macro] +pub fn net_specific_config_parser(tokens: TokenStream) -> TokenStream { + let NetSpecificConfig { + program_id, + neon_chain_id, + neon_token_mint, + operators_whitelist, + mut chains, + } = parse_macro_input!(tokens as NetSpecificConfig); -impl Parse for ElfParamIdInput { - fn parse(input: ParseStream) -> Result { - Ok(Self { - name: input.parse()?, - _separator: input.parse()?, - value: input.parse()?, - }) - } -} + let mut operators: Vec> = operators_whitelist + .iter() + .map(|key| bs58::decode(key).into_vec().unwrap()) + .collect(); -#[proc_macro] -pub fn declare_param_id(tokens: TokenStream) -> TokenStream { - let input = parse_macro_input!(tokens as ElfParamIdInput); + operators.sort_unstable(); + let operators_len = operators.len(); - let name = input.name; + chains.sort_unstable_by_key(|c| c.id); + let chains_len = chains.len(); - let value = input.value.value(); - let value_bytes = value.as_bytes(); + let chain_ids = chains.iter().map(|c| c.id).collect::>(); + let chain_names = chains.iter().map(|c| c.name.clone()).collect::>(); + let chain_tokens = chains + .iter() + .map(|c| bs58::decode(&c.token).into_vec().unwrap()) + .collect::>(); - let len = value.len(); + let neon_chain_id_str = neon_chain_id.to_string(); quote! { - ::solana_program::declare_id!(#value); + pub const PROGRAM_ID: solana_program::pubkey::Pubkey = solana_program::pubkey!(#program_id); + pub const DEFAULT_CHAIN_ID: u64 = #neon_chain_id; - #[no_mangle] - #[used] - #[doc(hidden)] - pub static #name: [u8; #len] = [ - #((#value_bytes),)* + neon_elf_param!(NEON_CHAIN_ID, #neon_chain_id_str); + neon_elf_param!(NEON_TOKEN_MINT, #neon_token_mint); + + pub static AUTHORIZED_OPERATOR_LIST: [::solana_program::pubkey::Pubkey; #operators_len] = [ + #(::solana_program::pubkey::Pubkey::new_from_array([#((#operators),)*]),)* + ]; + + pub static CHAIN_ID_LIST: [(u64, &str, ::solana_program::pubkey::Pubkey); #chains_len] = [ + #( (#chain_ids, #chain_names, ::solana_program::pubkey::Pubkey::new_from_array([#(#chain_tokens),*])) ),* ]; } .into() } #[proc_macro] -pub fn net_specific_config_parser(tokens: TokenStream) -> TokenStream { - let NetSpecificConfig { - chain_id, - operators_whitelist, - token_mint: TokenMint { - neon_token_mint, - decimals, - }, - } = parse_macro_input!(tokens as NetSpecificConfig); +pub fn common_config_parser(tokens: TokenStream) -> TokenStream { + let config = parse_macro_input!(tokens as CommonConfig); - quote! { - /// Supported CHAIN_ID value for transactions - pub const CHAIN_ID: u64 = #chain_id; + let mut variables = BTreeMap::new(); + let mut tokens = Vec::::new(); + + for v in config.variables { + let t = v.r#type; + let name = v.name; + let value = v.value; + + let elf_name_string = "NEON_".to_string() + &name.to_string(); + let elf_name = Ident::new(&elf_name_string, name.span()); + let elf_value = match &value { + syn::Lit::Str(s) => s.clone(), + syn::Lit::Int(i) => LitStr::new(&i.to_string(), i.span()), + syn::Lit::Float(f) => LitStr::new(&f.to_string(), f.span()), + syn::Lit::Bool(b) => LitStr::new(&b.value().to_string(), b.span()), + _ => unreachable!(), + }; - operators_whitelist![#(#operators_whitelist),*]; + tokens.push(quote! { + pub const #name: #t = #value; + neon_elf_param!(#elf_name, #elf_value); + }); - /// Token Mint ID - pub mod token_mint { - use super::declare_param_id; + variables.insert(elf_name_string, elf_value); + } - declare_param_id!(NEON_TOKEN_MINT, #neon_token_mint); - /// Ethereum account version - pub const DECIMALS: u8 = #decimals; + let variables_len = variables.len(); + let variable_names = variables.keys(); + let variable_values = variables.values(); - /// Number of base 10 digits to the right of the decimal place - #[must_use] - pub const fn decimals() -> u8 { DECIMALS } + quote! { + #(#tokens)* - } + pub static PARAMETERS: [(&str, &str); #variables_len] = [ + #( (#variable_names, #variable_values) ),* + ]; } .into() } - -#[proc_macro] -pub fn common_config_parser(tokens: TokenStream) -> TokenStream { - let config = parse_macro_input!(tokens as CommonConfig); - config.token_stream -} - -#[proc_macro] -pub fn elf_config_parser(tokens: TokenStream) -> TokenStream { - let config = parse_macro_input!(tokens as ElfParams); - config.token_stream -} diff --git a/evm_loader/program/config/common.toml b/evm_loader/program/config/common.toml index 7fe56f187..717b0bf35 100644 --- a/evm_loader/program/config/common.toml +++ b/evm_loader/program/config/common.toml @@ -1,14 +1,10 @@ account_seed_version = [3, "u8"] payment_to_treasure = 5000 -payment_to_deposit = 5000 operator_priority_slots = 16 holder_msg_size = 950 -request_units_additional_fee = 0 evm_steps_min = 500 evm_steps_last_iteration_max = 1 -compute_budget_units = 500_000 -compute_budget_heap_frame = 262144 # 256 * 1024 gas_limit_multiplier_no_chainid = 1000 -storage_entries_in_contract_account = [64, "u32"] +storage_entries_in_contract_account = [64, "usize"] treasury_pool_count = 128 treasury_pool_seed = "treasury_pool" diff --git a/evm_loader/program/config/default.toml b/evm_loader/program/config/default.toml index 97eca7604..e334b68db 100644 --- a/evm_loader/program/config/default.toml +++ b/evm_loader/program/config/default.toml @@ -1,4 +1,4 @@ -chain_id = 111 +program_id = "53DfF883gyixYNXnM7s5xhdeyV8mVk9T4i2hGV9vG9io" operators_whitelist = [ "9kPRbbwKL5SYELF4cZqWWFmP88QkKys51DoaUBx8eK73", "BMp6gEnveANdvSvspESJUrNczuHz1GF5UQKjVLCkAZih", @@ -33,6 +33,18 @@ operators_whitelist = [ "eXiURdoUQ4JpUysAevcTPiLMdWwG8q6mRAmice5Kioh", ] -[token_mint] -neon_token_mint = "HPsV9Deocecw3GeZv1FkAPNCBRfuVyfw9MMwjwRe1xaU" -decimals = 9 +[chain.neon] +id = 111 +token = "HPsV9Deocecw3GeZv1FkAPNCBRfuVyfw9MMwjwRe1xaU" + +[chain.sol] +id = 112 +token = "So11111111111111111111111111111111111111112" + +[chain.abc] +id = 113 +token = "HPsV9Deocecw3GeZv1FkAPNCBRfuVyfw9MMwjwRe1xaU" + +[chain.def] +id = 114 +token = "HPsV9Deocecw3GeZv1FkAPNCBRfuVyfw9MMwjwRe1xaU" \ No newline at end of file diff --git a/evm_loader/program/config/devnet.toml b/evm_loader/program/config/devnet.toml index c2cb2bda1..57f8f233d 100644 --- a/evm_loader/program/config/devnet.toml +++ b/evm_loader/program/config/devnet.toml @@ -1,4 +1,4 @@ -chain_id = 245022926 +program_id = "eeLSJgWzzxrqKv1UxtRVVH8FX3qCQWUs9QuAjJpETGU" operators_whitelist = [ "NeoQM3utcHGxhKT41Nq81g8t4xGcPNFpkAgYj1N2N8v", "Gw3Xiwve6HdvpJeQguhwT23cpK9nRjSy1NpNYCFY4XU9", @@ -390,6 +390,10 @@ operators_whitelist = [ "E4sFXJ4p8CcxA2A5GsdjWRaSgPLvGNDdmFPyg65eoXrh", ] -[token_mint] -neon_token_mint = "89dre8rZjLNft7HoupGiyxu3MNftR577ZYu8bHe2kK7g" -decimals = 9 +[chain.neon] +id = 245022926 +token = "89dre8rZjLNft7HoupGiyxu3MNftR577ZYu8bHe2kK7g" + +[chain.sol] +id = 245022927 +token = "So11111111111111111111111111111111111111112" \ No newline at end of file diff --git a/evm_loader/program/config/elf_params.toml b/evm_loader/program/config/elf_params.toml deleted file mode 100644 index 5657613d5..000000000 --- a/evm_loader/program/config/elf_params.toml +++ /dev/null @@ -1,13 +0,0 @@ -[env] -neon_pkg_version = "CARGO_PKG_VERSION" -neon_revision = "NEON_REVISION" - -[formatcp] -neon_seed_version = "ACCOUNT_SEED_VERSION" -neon_token_mint_decimals = "token_mint::DECIMALS" -neon_chain_id = "CHAIN_ID" -neon_compute_units = "COMPUTE_BUDGET_UNITS" -neon_heap_frame = "COMPUTE_BUDGET_HEAP_FRAME" -neon_additional_fee = "REQUEST_UNITS_ADDITIONAL_FEE" -neon_pool_count = "TREASURY_POOL_COUNT" -neon_pool_seed = "TREASURY_POOL_SEED" diff --git a/evm_loader/program/config/govertest.toml b/evm_loader/program/config/govertest.toml index 843205930..c9fe2df8b 100644 --- a/evm_loader/program/config/govertest.toml +++ b/evm_loader/program/config/govertest.toml @@ -1,4 +1,4 @@ -chain_id = 111 +program_id = "53DfF883gyixYNXnM7s5xhdeyV8mVk9T4i2hGV9vG9io" operators_whitelist = [ "9kPRbbwKL5SYELF4cZqWWFmP88QkKys51DoaUBx8eK73", "BMp6gEnveANdvSvspESJUrNczuHz1GF5UQKjVLCkAZih", @@ -33,6 +33,6 @@ operators_whitelist = [ "eXiURdoUQ4JpUysAevcTPiLMdWwG8q6mRAmice5Kioh", ] -[token_mint] -neon_token_mint = "EjLGfD8mpxKLwGDi8AiTisAbGtWWM2L3htkJ6MpvS8Hk" -decimals = 9 +[chain.neon] +id = 111 +token = "EjLGfD8mpxKLwGDi8AiTisAbGtWWM2L3htkJ6MpvS8Hk" diff --git a/evm_loader/program/config/mainnet.toml b/evm_loader/program/config/mainnet.toml index 0f1e87382..e3660baf9 100644 --- a/evm_loader/program/config/mainnet.toml +++ b/evm_loader/program/config/mainnet.toml @@ -1,4 +1,4 @@ -chain_id = 245022934 +program_id = "NeonVMyRX5GbCrsAHnUwx1nYYoJAtskU1bWUo6JGNyG" operators_whitelist = [ "NeonPQFrw5stVvs1rFLDxALWUBDCnSPsWBP83RfNUKK", "GYt9w8MaXztDLhhsxmQr7Ar9FJ6MmaFwav7qBrxZKwhd", @@ -393,6 +393,6 @@ operators_whitelist = [ "DYS3mepDkhT62A2aJvnPmreUS74Uec34cnPn85AaZq3k", ] -[token_mint] -neon_token_mint = "NeonTjSjsuo3rexg9o6vHuMXw62f9V7zvmu8M8Zut44" -decimals = 9 +[chain.neon] +id = 245022934 +token = "NeonTjSjsuo3rexg9o6vHuMXw62f9V7zvmu8M8Zut44" diff --git a/evm_loader/program/config/testnet.toml b/evm_loader/program/config/testnet.toml index 17811bdcf..8ea5d890e 100644 --- a/evm_loader/program/config/testnet.toml +++ b/evm_loader/program/config/testnet.toml @@ -1,4 +1,4 @@ -chain_id = 245022940 +program_id = "eeLSJgWzzxrqKv1UxtRVVH8FX3qCQWUs9QuAjJpETGU" operators_whitelist = [ "NeoQM3utcHGxhKT41Nq81g8t4xGcPNFpkAgYj1N2N8v", "Gw3Xiwve6HdvpJeQguhwT23cpK9nRjSy1NpNYCFY4XU9", @@ -231,6 +231,6 @@ operators_whitelist = [ "B5Gefd2yR3nBi4eFDtp3grmVsRq6sw4UYmGVZG6vrda3", ] -[token_mint] -neon_token_mint = "89dre8rZjLNft7HoupGiyxu3MNftR577ZYu8bHe2kK7g" -decimals = 9 +[chain.neon] +id = 245022940 +token = "89dre8rZjLNft7HoupGiyxu3MNftR577ZYu8bHe2kK7g" diff --git a/evm_loader/program/src/config.rs b/evm_loader/program/src/config.rs index f233fe3bd..96b9edeaa 100644 --- a/evm_loader/program/src/config.rs +++ b/evm_loader/program/src/config.rs @@ -2,12 +2,7 @@ #![allow(clippy::useless_transmute)] use cfg_if::cfg_if; -use const_format::formatcp; -use evm_loader_macro::{ - common_config_parser, declare_param_id, elf_config_parser, neon_elf_param, - net_specific_config_parser, operators_whitelist, -}; -use static_assertions::const_assert; +use evm_loader_macro::{common_config_parser, neon_elf_param, net_specific_config_parser}; cfg_if! { if #[cfg(feature = "mainnet")] { @@ -23,16 +18,15 @@ cfg_if! { } } -common_config_parser!("config/common.toml"); - cfg_if! { if #[cfg(feature = "emergency")] { - neon_elf_param!( NEON_STATUS_NAME, "EMERGENCY"); + neon_elf_param!(NEON_STATUS_NAME, "EMERGENCY"); } else { - neon_elf_param!( NEON_STATUS_NAME, "WORK"); + neon_elf_param!(NEON_STATUS_NAME, "WORK"); } } -elf_config_parser!("config/elf_params.toml"); +common_config_parser!("config/common.toml"); -const_assert!(token_mint::decimals() <= 18); +neon_elf_param!(NEON_PKG_VERSION, env!("CARGO_PKG_VERSION")); +neon_elf_param!(NEON_REVISION, env!("NEON_REVISION")); diff --git a/evm_loader/program/src/instruction/config_get_chain_count.rs b/evm_loader/program/src/instruction/config_get_chain_count.rs new file mode 100644 index 000000000..bc932f2e9 --- /dev/null +++ b/evm_loader/program/src/instruction/config_get_chain_count.rs @@ -0,0 +1,18 @@ +use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; + +use crate::error::Result; + +pub fn process<'a>( + _program_id: &'a Pubkey, + _accounts: &'a [AccountInfo<'a>], + _instruction: &[u8], +) -> Result<()> { + solana_program::msg!("Instruction: Config Get Chain Count"); + + let count = crate::config::CHAIN_ID_LIST.len(); + + let return_data = count.to_le_bytes(); + solana_program::program::set_return_data(&return_data); + + Ok(()) +} diff --git a/evm_loader/program/src/instruction/config_get_chain_info.rs b/evm_loader/program/src/instruction/config_get_chain_info.rs new file mode 100644 index 000000000..13b1a397e --- /dev/null +++ b/evm_loader/program/src/instruction/config_get_chain_info.rs @@ -0,0 +1,20 @@ +use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; + +use crate::error::Result; + +pub fn process<'a>( + _program_id: &'a Pubkey, + _accounts: &'a [AccountInfo<'a>], + instruction: &[u8], +) -> Result<()> { + solana_program::msg!("Instruction: Config Get Chain Info"); + + let bytes = instruction.try_into()?; + let index = usize::from_le_bytes(bytes); + let info = &crate::config::CHAIN_ID_LIST[index]; + + let return_data = bincode::serialize(info)?; + solana_program::program::set_return_data(&return_data); + + Ok(()) +} diff --git a/evm_loader/program/src/instruction/config_get_environment.rs b/evm_loader/program/src/instruction/config_get_environment.rs new file mode 100644 index 000000000..e4c8513f7 --- /dev/null +++ b/evm_loader/program/src/instruction/config_get_environment.rs @@ -0,0 +1,29 @@ +use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; + +use crate::error::Result; + +pub fn process<'a>( + _program_id: &'a Pubkey, + _accounts: &'a [AccountInfo<'a>], + _instruction: &[u8], +) -> Result<()> { + solana_program::msg!("Instruction: Config Get Environment"); + + let environment: &str = if cfg!(feature = "mainnet") { + "mainnet" + } else if cfg!(feature = "testnet") { + "testnet" + } else if cfg!(feature = "devnet") { + "devnet" + } else if cfg!(feature = "govertest") { + "govertest" + } else if cfg!(feature = "ci") { + "ci" + } else { + "unknown" + }; + + solana_program::program::set_return_data(environment.as_bytes()); + + Ok(()) +} diff --git a/evm_loader/program/src/instruction/config_get_property_by_index.rs b/evm_loader/program/src/instruction/config_get_property_by_index.rs new file mode 100644 index 000000000..19c6d6e31 --- /dev/null +++ b/evm_loader/program/src/instruction/config_get_property_by_index.rs @@ -0,0 +1,20 @@ +use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; + +use crate::error::Result; + +pub fn process<'a>( + _program_id: &'a Pubkey, + _accounts: &'a [AccountInfo<'a>], + instruction: &[u8], +) -> Result<()> { + solana_program::msg!("Instruction: Config Get Property by Index"); + + let bytes = instruction.try_into()?; + let index = usize::from_le_bytes(bytes); + let info = &crate::config::PARAMETERS[index]; + + let return_data = bincode::serialize(info)?; + solana_program::program::set_return_data(&return_data); + + Ok(()) +} diff --git a/evm_loader/program/src/instruction/config_get_property_by_name.rs b/evm_loader/program/src/instruction/config_get_property_by_name.rs new file mode 100644 index 000000000..3937c7c69 --- /dev/null +++ b/evm_loader/program/src/instruction/config_get_property_by_name.rs @@ -0,0 +1,24 @@ +use solana_program::{account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey}; + +use crate::error::Result; + +pub fn process<'a>( + _program_id: &'a Pubkey, + _accounts: &'a [AccountInfo<'a>], + instruction: &[u8], +) -> Result<()> { + solana_program::msg!("Instruction: Config Get Property by Name"); + + let requested_property = std::str::from_utf8(instruction)?; + + let Ok(index) = crate::config::PARAMETERS.binary_search_by(|p| p.0.cmp(requested_property)) else { + return Err(ProgramError::InvalidArgument.into()); + }; + + let (name, value) = crate::config::PARAMETERS[index]; + assert_eq!(requested_property, name); + + solana_program::program::set_return_data(value.as_bytes()); + + Ok(()) +} diff --git a/evm_loader/program/src/instruction/config_get_property_count.rs b/evm_loader/program/src/instruction/config_get_property_count.rs new file mode 100644 index 000000000..c246b6b0a --- /dev/null +++ b/evm_loader/program/src/instruction/config_get_property_count.rs @@ -0,0 +1,18 @@ +use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; + +use crate::error::Result; + +pub fn process<'a>( + _program_id: &'a Pubkey, + _accounts: &'a [AccountInfo<'a>], + _instruction: &[u8], +) -> Result<()> { + solana_program::msg!("Instruction: Config Get Property Count"); + + let count = crate::config::PARAMETERS.len(); + + let return_data = count.to_le_bytes(); + solana_program::program::set_return_data(&return_data); + + Ok(()) +} diff --git a/evm_loader/program/src/instruction/config_get_status.rs b/evm_loader/program/src/instruction/config_get_status.rs new file mode 100644 index 000000000..42c5b9af0 --- /dev/null +++ b/evm_loader/program/src/instruction/config_get_status.rs @@ -0,0 +1,19 @@ +use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; + +use crate::error::Result; + +pub fn process<'a>( + _program_id: &'a Pubkey, + _accounts: &'a [AccountInfo<'a>], + _instruction: &[u8], +) -> Result<()> { + solana_program::msg!("Instruction: Config Get Status"); + + if cfg!(feature = "emergency") { + solana_program::program::set_return_data(&[0]); + } else { + solana_program::program::set_return_data(&[1]); + } + + Ok(()) +} diff --git a/evm_loader/program/src/instruction/config_get_version.rs b/evm_loader/program/src/instruction/config_get_version.rs new file mode 100644 index 000000000..3d16b2b52 --- /dev/null +++ b/evm_loader/program/src/instruction/config_get_version.rs @@ -0,0 +1,22 @@ +use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; + +use crate::{ + config::{NEON_PKG_VERSION, NEON_REVISION}, + error::Result, +}; + +pub fn process<'a>( + _program_id: &'a Pubkey, + _accounts: &'a [AccountInfo<'a>], + _instruction: &[u8], +) -> Result<()> { + solana_program::msg!("Instruction: Config Get Version"); + + let version = std::str::from_utf8(&NEON_PKG_VERSION)?; + let revision = std::str::from_utf8(&NEON_REVISION)?; + + let return_data = bincode::serialize(&(version, revision))?; + solana_program::program::set_return_data(&return_data); + + Ok(()) +} From 4b72df3dc58d8ca10a06c97fb6acff2e7eb50f90 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Tue, 14 Nov 2023 18:09:20 +0300 Subject: [PATCH 051/318] [Multi Tokens] EVM and Opcodes changes --- evm_loader/program/src/evm/buffer.rs | 71 +++------ evm_loader/program/src/evm/database.rs | 30 ++-- evm_loader/program/src/evm/mod.rs | 90 +++++++---- evm_loader/program/src/evm/opcode.rs | 166 ++++++++++++-------- evm_loader/program/src/evm/stack.rs | 4 +- evm_loader/program/src/executor/action.rs | 70 ++++++++- evm_loader/program/src/executor/cache.rs | 22 +++ evm_loader/program/src/executor/state.rs | 176 ++++++++++++---------- 8 files changed, 387 insertions(+), 242 deletions(-) diff --git a/evm_loader/program/src/evm/buffer.rs b/evm_loader/program/src/evm/buffer.rs index 7b95e248e..119f24328 100644 --- a/evm_loader/program/src/evm/buffer.rs +++ b/evm_loader/program/src/evm/buffer.rs @@ -1,24 +1,19 @@ use std::{ - alloc::{GlobalAlloc, Layout}, ops::{Deref, Range}, ptr::NonNull, }; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; -const BUFFER_ALIGN: usize = 1; - -#[derive(Debug)] enum Inner { Empty, Owned { - ptr: NonNull, - len: usize, + data: Vec, }, Account { key: Pubkey, - data: *mut u8, range: Range, + data: *const u8, }, AccountUninit { key: Pubkey, @@ -26,7 +21,6 @@ enum Inner { }, } -#[derive(Debug)] pub struct Buffer { ptr: *const u8, len: usize, @@ -36,13 +30,13 @@ pub struct Buffer { impl Buffer { fn new(inner: Inner) -> Self { let (ptr, len) = match &inner { - Inner::Empty => (NonNull::dangling().as_ptr(), 0), - Inner::Owned { ptr, len } => (ptr.as_ptr(), *len), + Inner::Empty => (NonNull::dangling().as_ptr() as *const _, 0), + Inner::Owned { data } => (data.as_ptr(), data.len()), Inner::Account { data, range, .. } => { let ptr = unsafe { data.add(range.start) }; (ptr, range.len()) } - Inner::AccountUninit { .. } => (std::ptr::null_mut(), 0), + Inner::AccountUninit { .. } => (std::ptr::null(), 0), }; Buffer { ptr, len, inner } @@ -56,9 +50,11 @@ impl Buffer { /// care of them. #[must_use] pub unsafe fn from_account(account: &AccountInfo, range: Range) -> Self { - // todo cell_leak #69099 - let ptr = account.data.as_ptr(); - let data = (*ptr).as_mut_ptr(); + let data = unsafe { + // todo cell_leak #69099 + let ptr = account.data.as_ptr(); + (*ptr).as_ptr() + }; Buffer::new(Inner::Account { key: *account.key, @@ -68,33 +64,18 @@ impl Buffer { } #[must_use] - pub fn from_slice(v: &[u8]) -> Self { + pub fn from_vec(v: Vec) -> Self { if v.is_empty() { return Self::empty(); } - unsafe { - let len = v.len(); - - let layout = Layout::from_size_align_unchecked(len, BUFFER_ALIGN); - let ptr = crate::allocator::EVM.alloc(layout); - if ptr.is_null() { - std::alloc::handle_alloc_error(layout); - } - - cfg_if::cfg_if! { - if #[cfg(target_os = "solana")] { - solana_program::syscalls::sol_memcpy_(ptr, v.as_ptr(), len as u64); - } else { - std::ptr::copy_nonoverlapping(v.as_ptr(), ptr, len); - } - } + let inner = Inner::Owned { data: v }; + Self::new(inner) + } - Buffer::new(Inner::Owned { - ptr: NonNull::new_unchecked(ptr), - len, - }) - } + #[must_use] + pub fn from_slice(v: &[u8]) -> Self { + Self::from_vec(v.to_vec()) } #[must_use] @@ -129,17 +110,6 @@ impl Buffer { } } -impl Drop for Buffer { - fn drop(&mut self) { - if let Inner::Owned { ptr, len } = self.inner { - unsafe { - let layout = Layout::from_size_align_unchecked(len, BUFFER_ALIGN); - crate::allocator::EVM.dealloc(ptr.as_ptr(), layout); - } - } - } -} - impl Deref for Buffer { type Target = [u8]; @@ -159,8 +129,8 @@ impl Clone for Buffer { Inner::Owned { .. } => Self::from_slice(self), Inner::Account { key, data, range } => Self::new(Inner::Account { key: *key, - data: *data, range: range.clone(), + data: *data, }), Inner::AccountUninit { key, range } => Self::new(Inner::AccountUninit { key: *key, @@ -185,9 +155,8 @@ impl serde::Serialize for Buffer { match &self.inner { Inner::Empty => serializer.serialize_unit_variant("evm_buffer", 0, "empty"), - Inner::Owned { ptr, len } => { - let slice = unsafe { std::slice::from_raw_parts(ptr.as_ptr(), *len) }; - let bytes = serde_bytes::Bytes::new(slice); + Inner::Owned { data } => { + let bytes = serde_bytes::Bytes::new(data); serializer.serialize_newtype_variant("evm_buffer", 1, "owned", bytes) } Inner::Account { key, range, .. } => { diff --git a/evm_loader/program/src/evm/database.rs b/evm_loader/program/src/evm/database.rs index 56efcb7e9..803d0cff6 100644 --- a/evm_loader/program/src/evm/database.rs +++ b/evm_loader/program/src/evm/database.rs @@ -6,21 +6,29 @@ use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; #[maybe_async(?Send)] pub trait Database { - fn chain_id(&self) -> U256; + fn default_chain_id(&self) -> u64; + fn is_valid_chain_id(&self, chain_id: u64) -> bool; + async fn contract_chain_id(&self, address: Address) -> Result; - async fn nonce(&self, address: &Address) -> Result; - fn increment_nonce(&mut self, address: Address) -> Result<()>; + async fn nonce(&self, address: Address, chain_id: u64) -> Result; + fn increment_nonce(&mut self, address: Address, chain_id: u64) -> Result<()>; - async fn balance(&self, address: &Address) -> Result; - async fn transfer(&mut self, source: Address, target: Address, value: U256) -> Result<()>; - - async fn code_size(&self, address: &Address) -> Result; - async fn code_hash(&self, address: &Address) -> Result<[u8; 32]>; - async fn code(&self, address: &Address) -> Result; - fn set_code(&mut self, address: Address, code: Buffer) -> Result<()>; + async fn balance(&self, address: Address, chain_id: u64) -> Result; + async fn transfer( + &mut self, + source: Address, + target: Address, + chain_id: u64, + value: U256, + ) -> Result<()>; + + async fn code_hash(&self, address: Address, chain_id: u64) -> Result<[u8; 32]>; + async fn code_size(&self, address: Address) -> Result; + async fn code(&self, address: Address) -> Result; + fn set_code(&mut self, address: Address, chain_id: u64, code: Vec) -> Result<()>; fn selfdestruct(&mut self, address: Address) -> Result<()>; - async fn storage(&self, address: &Address, index: &U256) -> Result<[u8; 32]>; + async fn storage(&self, address: Address, index: U256) -> Result<[u8; 32]>; fn set_storage(&mut self, address: Address, index: U256, value: [u8; 32]) -> Result<()>; async fn block_hash(&self, number: U256) -> Result<[u8; 32]>; diff --git a/evm_loader/program/src/evm/mod.rs b/evm_loader/program/src/evm/mod.rs index add5b66f2..c237db03f 100644 --- a/evm_loader/program/src/evm/mod.rs +++ b/evm_loader/program/src/evm/mod.rs @@ -2,7 +2,7 @@ #![allow(clippy::type_repetition_in_bounds)] #![allow(clippy::unsafe_derive_deserialize)] -use std::{marker::PhantomData, ops::Range}; +use std::{fmt::Display, marker::PhantomData, ops::Range}; use ethnum::U256; use maybe_async::maybe_async; @@ -81,6 +81,12 @@ pub enum ExitStatus { StepLimit, } +impl Display for ExitStatus { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(self.status()) + } +} + impl ExitStatus { #[must_use] pub fn status(&self) -> &'static str { @@ -119,6 +125,7 @@ pub enum Reason { pub struct Context { pub caller: Address, pub contract: Address, + pub contract_chain_id: u64, #[serde(with = "ethnum::serde::bytes::le")] pub value: U256, @@ -129,6 +136,7 @@ pub struct Context { #[serde(bound = "B: Database")] pub struct Machine { origin: Address, + chain_id: u64, context: Context, #[serde(with = "ethnum::serde::bytes::le")] @@ -197,41 +205,44 @@ impl Machine { #[maybe_async] pub async fn new( - trx: &mut Transaction, + trx: Transaction, origin: Address, backend: &mut B, #[cfg(not(target_os = "solana"))] tracer: TracerTypeOpt, ) -> Result { - let origin_nonce = backend.nonce(&origin).await?; + let trx_chain_id = trx.chain_id().unwrap_or_else(|| backend.default_chain_id()); - if origin_nonce == u64::MAX { - return Err(Error::NonceOverflow(origin)); + if !backend.is_valid_chain_id(trx_chain_id) { + return Err(Error::InvalidChainId(trx_chain_id)); } - if origin_nonce != trx.nonce() { - return Err(Error::InvalidTransactionNonce( - origin, - origin_nonce, - trx.nonce(), - )); - } + let nonce = backend.nonce(origin, trx_chain_id).await?; - if let Some(chain_id) = trx.chain_id() { - if backend.chain_id() != chain_id { - return Err(Error::InvalidChainId(chain_id)); - } + if nonce == u64::MAX { + return Err(Error::NonceOverflow(origin)); } - if backend.balance(&origin).await? < trx.value() { - return Err(Error::InsufficientBalance(origin, trx.value())); + if nonce != trx.nonce() { + return Err(Error::InvalidTransactionNonce(origin, nonce, trx.nonce())); } - if backend.code_size(&origin).await? != 0 { - return Err(Error::SenderHasDeployedCode(origin)); + if backend.balance(origin, trx_chain_id).await? < trx.value() { + return Err(Error::InsufficientBalance( + origin, + trx_chain_id, + trx.value(), + )); } + // TODO may be remove. This requires additional account + // Never actually happens, or at least should not + // if backend.code_size(origin).await? != 0 { + // return Err(Error::SenderHasDeployedCode(origin)); + // } + if trx.target().is_some() { Self::new_call( + trx_chain_id, trx, origin, backend, @@ -241,6 +252,7 @@ impl Machine { .await } else { Self::new_create( + trx_chain_id, trx, origin, backend, @@ -253,7 +265,8 @@ impl Machine { #[maybe_async] async fn new_call( - trx: &mut Transaction, + chain_id: u64, + trx: Transaction, origin: Address, backend: &mut B, #[cfg(not(target_os = "solana"))] tracer: TracerTypeOpt, @@ -263,25 +276,29 @@ impl Machine { let target = trx.target().unwrap(); sol_log_data(&[b"ENTER", b"CALL", target.as_bytes()]); - backend.increment_nonce(origin)?; + backend.increment_nonce(origin, chain_id)?; backend.snapshot(); - backend.transfer(origin, target, trx.value()).await?; + backend + .transfer(origin, target, chain_id, trx.value()) + .await?; - let execution_code = backend.code(&target).await?; + let execution_code = backend.code(target).await?; Ok(Self { origin, + chain_id, context: Context { caller: origin, contract: target, + contract_chain_id: backend.contract_chain_id(target).await.unwrap_or(chain_id), value: trx.value(), code_address: Some(target), }, gas_price: trx.gas_price(), gas_limit: trx.gas_limit(), execution_code, - call_data: trx.extract_call_data(), + call_data: trx.into_call_data(), return_data: Buffer::empty(), return_range: 0..0, stack: Stack::new(), @@ -298,7 +315,8 @@ impl Machine { #[maybe_async] async fn new_create( - trx: &mut Transaction, + chain_id: u64, + trx: Transaction, origin: Address, backend: &mut B, #[cfg(not(target_os = "solana"))] tracer: TracerTypeOpt, @@ -308,21 +326,26 @@ impl Machine { let target = Address::from_create(&origin, trx.nonce()); sol_log_data(&[b"ENTER", b"CREATE", target.as_bytes()]); - if (backend.nonce(&target).await? != 0) || (backend.code_size(&target).await? != 0) { + if (backend.nonce(target, chain_id).await? != 0) || (backend.code_size(target).await? != 0) + { return Err(Error::DeployToExistingAccount(target, origin)); } - backend.increment_nonce(origin)?; + backend.increment_nonce(origin, chain_id)?; backend.snapshot(); - backend.increment_nonce(target)?; - backend.transfer(origin, target, trx.value()).await?; + backend.increment_nonce(target, chain_id)?; + backend + .transfer(origin, target, chain_id, trx.value()) + .await?; Ok(Self { origin, + chain_id, context: Context { caller: origin, contract: target, + contract_chain_id: chain_id, value: trx.value(), code_address: None, }, @@ -335,7 +358,7 @@ impl Machine { pc: 0_usize, is_static: false, reason: Reason::Create, - execution_code: trx.extract_call_data(), + execution_code: trx.into_call_data(), call_data: Buffer::empty(), parent: None, phantom: PhantomData, @@ -388,8 +411,7 @@ impl Machine { Ok(result) => result, Err(e) => { let message = build_revert_message(&e.to_string()); - self.opcode_revert_impl(Buffer::from_slice(&message), backend) - .await? + self.opcode_revert_impl(message, backend).await? } }; @@ -423,6 +445,7 @@ impl Machine { fn fork( &mut self, reason: Reason, + chain_id: u64, context: Context, execution_code: Buffer, call_data: Buffer, @@ -430,6 +453,7 @@ impl Machine { ) { let mut other = Self { origin: self.origin, + chain_id, context, gas_price: self.gas_price, gas_limit: gas_limit.unwrap_or(self.gas_limit), diff --git a/evm_loader/program/src/evm/opcode.rs b/evm_loader/program/src/evm/opcode.rs index 6e3690291..acc9ed5dc 100644 --- a/evm_loader/program/src/evm/opcode.rs +++ b/evm_loader/program/src/evm/opcode.rs @@ -478,7 +478,7 @@ impl Machine { pub async fn opcode_balance(&mut self, backend: &mut B) -> Result { let balance = { let address = self.stack.pop_address()?; - backend.balance(address).await? + backend.balance(address, self.chain_id).await? }; self.stack.push_u256(balance)?; @@ -605,12 +605,12 @@ impl Machine { /// copy contract's bytecode #[maybe_async] pub async fn opcode_extcodecopy(&mut self, backend: &mut B) -> Result { - let address = *self.stack.pop_address()?; + let address = self.stack.pop_address()?; let memory_offset = self.stack.pop_usize()?; let data_offset = self.stack.pop_usize()?; let length = self.stack.pop_usize()?; - let code = backend.code(&address).await?; + let code = backend.code(address).await?; self.memory .write_buffer(memory_offset, length, &code, data_offset)?; @@ -648,7 +648,7 @@ impl Machine { pub async fn opcode_extcodehash(&mut self, backend: &mut B) -> Result { let code_hash = { let address = self.stack.pop_address()?; - backend.code_hash(address).await? + backend.code_hash(address, self.chain_id).await? }; self.stack.push_array(&code_hash)?; @@ -720,8 +720,8 @@ impl Machine { /// Istanbul hardfork, EIP-1344: current network's chain id #[maybe_async] - pub async fn opcode_chainid(&mut self, backend: &mut B) -> Result { - let chain_id = backend.chain_id(); + pub async fn opcode_chainid(&mut self, _backend: &mut B) -> Result { + let chain_id = self.chain_id.into(); self.stack.push_u256(chain_id)?; @@ -731,7 +731,9 @@ impl Machine { /// Istanbul hardfork, EIP-1884: balance of the executing contract in wei #[maybe_async] pub async fn opcode_selfbalance(&mut self, backend: &mut B) -> Result { - let balance = backend.balance(&self.context.contract).await?; + let balance = backend + .balance(self.context.contract, self.chain_id) + .await?; self.stack.push_u256(balance)?; @@ -792,7 +794,7 @@ impl Machine { #[maybe_async] pub async fn opcode_sload(&mut self, backend: &mut B) -> Result { let index = self.stack.pop_u256()?; - let value = backend.storage(&self.context.contract, &index).await?; + let value = backend.storage(self.context.contract, index).await?; tracing_event!(self, super::tracing::Event::StorageAccess { index, value }); @@ -1002,8 +1004,12 @@ impl Machine { let length = self.stack.pop_usize()?; let created_address = { - let nonce = backend.nonce(&self.context.contract).await?; - Address::from_create(&self.context.contract, nonce) + let source = self.context.contract; + let chain_id = self.context.contract_chain_id; + + let nonce = backend.nonce(source, chain_id).await?; + + Address::from_create(&source, nonce) }; self.opcode_create_impl(created_address, value, offset, length, backend) @@ -1040,11 +1046,14 @@ impl Machine { length: usize, backend: &mut B, ) -> Result { - if backend.nonce(&self.context.contract).await? == u64::MAX { + let chain_id = self.context.contract_chain_id; + + let contract_nonce = backend.nonce(self.context.contract, chain_id).await?; + if contract_nonce == u64::MAX { return Err(Error::NonceOverflow(self.context.contract)); } - backend.increment_nonce(self.context.contract)?; + backend.increment_nonce(self.context.contract, chain_id)?; self.return_data = Buffer::empty(); self.return_range = 0..0; @@ -1054,6 +1063,7 @@ impl Machine { let context = Context { caller: self.context.contract, contract: address, + contract_chain_id: chain_id, value, code_address: None, }; @@ -1066,22 +1076,27 @@ impl Machine { } ); - self.fork(Reason::Create, context, init_code, Buffer::empty(), None); + self.fork( + Reason::Create, + chain_id, + context, + init_code, + Buffer::empty(), + None, + ); backend.snapshot(); sol_log_data(&[b"ENTER", b"CREATE", address.as_bytes()]); - if (backend.nonce(&address).await? != 0) || (backend.code_size(&address).await? != 0) { + if (backend.nonce(address, chain_id).await? != 0) + || (backend.code_size(address).await? != 0) + { return Err(Error::DeployToExistingAccount(address, self.context.caller)); } - if backend.balance(&self.context.caller).await? < value { - return Err(Error::InsufficientBalance(self.context.caller, value)); - } - - backend.increment_nonce(address)?; + backend.increment_nonce(address, chain_id)?; backend - .transfer(self.context.caller, address, value) + .transfer(self.context.caller, address, chain_id, value) .await?; Ok(Action::Noop) @@ -1091,7 +1106,7 @@ impl Machine { #[maybe_async] pub async fn opcode_call(&mut self, backend: &mut B) -> Result { let gas_limit = self.stack.pop_u256()?; - let address = *self.stack.pop_address()?; + let address = self.stack.pop_address()?; let value = self.stack.pop_u256()?; let args_offset = self.stack.pop_usize()?; let args_length = self.stack.pop_usize()?; @@ -1102,11 +1117,13 @@ impl Machine { self.return_range = return_offset..(return_offset + return_length); let call_data = self.memory.read_buffer(args_offset, args_length)?; - let code = backend.code(&address).await?; + let code = backend.code(address).await?; + let chain_id = self.context.contract_chain_id; let context = Context { caller: self.context.contract, contract: address, + contract_chain_id: backend.contract_chain_id(address).await.unwrap_or(chain_id), value, code_address: Some(address), }; @@ -1119,7 +1136,14 @@ impl Machine { } ); - self.fork(Reason::Call, context, code, call_data, Some(gas_limit)); + self.fork( + Reason::Call, + chain_id, + context, + code, + call_data, + Some(gas_limit), + ); backend.snapshot(); sol_log_data(&[b"ENTER", b"CALL", address.as_bytes()]); @@ -1128,12 +1152,8 @@ impl Machine { return Err(Error::StaticModeViolation(self.context.caller)); } - if backend.balance(&self.context.caller).await? < value { - return Err(Error::InsufficientBalance(self.context.caller, value)); - } - backend - .transfer(self.context.caller, self.context.contract, value) + .transfer(self.context.caller, self.context.contract, chain_id, value) .await?; self.opcode_call_precompile_impl(backend, &address).await @@ -1143,7 +1163,7 @@ impl Machine { #[maybe_async] pub async fn opcode_callcode(&mut self, backend: &mut B) -> Result { let gas_limit = self.stack.pop_u256()?; - let address = *self.stack.pop_address()?; + let address = self.stack.pop_address()?; let value = self.stack.pop_u256()?; let args_offset = self.stack.pop_usize()?; let args_length = self.stack.pop_usize()?; @@ -1154,13 +1174,13 @@ impl Machine { self.return_range = return_offset..(return_offset + return_length); let call_data = self.memory.read_buffer(args_offset, args_length)?; - let code = backend.code(&address).await?; + let code = backend.code(address).await?; + let chain_id = self.context.contract_chain_id; let context = Context { - caller: self.context.contract, - contract: self.context.contract, value, code_address: Some(address), + ..self.context }; tracing_event!( @@ -1171,13 +1191,24 @@ impl Machine { } ); - self.fork(Reason::Call, context, code, call_data, Some(gas_limit)); + self.fork( + Reason::Call, + chain_id, + context, + code, + call_data, + Some(gas_limit), + ); backend.snapshot(); sol_log_data(&[b"ENTER", b"CALLCODE", address.as_bytes()]); - if backend.balance(&self.context.caller).await? < value { - return Err(Error::InsufficientBalance(self.context.caller, value)); + if backend.balance(self.context.caller, chain_id).await? < value { + return Err(Error::InsufficientBalance( + self.context.caller, + chain_id, + value, + )); } self.opcode_call_precompile_impl(backend, &address).await @@ -1188,7 +1219,7 @@ impl Machine { #[maybe_async] pub async fn opcode_delegatecall(&mut self, backend: &mut B) -> Result { let gas_limit = self.stack.pop_u256()?; - let address = *self.stack.pop_address()?; + let address = self.stack.pop_address()?; let args_offset = self.stack.pop_usize()?; let args_length = self.stack.pop_usize()?; let return_offset = self.stack.pop_usize()?; @@ -1198,7 +1229,7 @@ impl Machine { self.return_range = return_offset..(return_offset + return_length); let call_data = self.memory.read_buffer(args_offset, args_length)?; - let code = backend.code(&address).await?; + let code = backend.code(address).await?; let context = Context { code_address: Some(address), @@ -1213,7 +1244,14 @@ impl Machine { } ); - self.fork(Reason::Call, context, code, call_data, Some(gas_limit)); + self.fork( + Reason::Call, + self.chain_id, + context, + code, + call_data, + Some(gas_limit), + ); backend.snapshot(); sol_log_data(&[b"ENTER", b"DELEGATECALL", address.as_bytes()]); @@ -1226,7 +1264,7 @@ impl Machine { #[maybe_async] pub async fn opcode_staticcall(&mut self, backend: &mut B) -> Result { let gas_limit = self.stack.pop_u256()?; - let address = *self.stack.pop_address()?; + let address = self.stack.pop_address()?; let args_offset = self.stack.pop_usize()?; let args_length = self.stack.pop_usize()?; let return_offset = self.stack.pop_usize()?; @@ -1236,11 +1274,13 @@ impl Machine { self.return_range = return_offset..(return_offset + return_length); let call_data = self.memory.read_buffer(args_offset, args_length)?; - let code = backend.code(&address).await?; + let code = backend.code(address).await?; + let chain_id = self.context.contract_chain_id; let context = Context { caller: self.context.contract, contract: address, + contract_chain_id: backend.contract_chain_id(address).await.unwrap_or(chain_id), value: U256::ZERO, code_address: Some(address), }; @@ -1253,7 +1293,14 @@ impl Machine { } ); - self.fork(Reason::Call, context, code, call_data, Some(gas_limit)); + self.fork( + Reason::Call, + chain_id, + context, + code, + call_data, + Some(gas_limit), + ); self.is_static = true; backend.snapshot(); @@ -1281,9 +1328,7 @@ impl Machine { }; if let Some(return_data) = result.transpose()? { - return self - .opcode_return_impl(Buffer::from_slice(&return_data), backend) - .await; + return self.opcode_return_impl(return_data, backend).await; } Ok(Action::Noop) @@ -1295,7 +1340,7 @@ impl Machine { let offset = self.stack.pop_usize()?; let length = self.stack.pop_usize()?; - let return_data = self.memory.read_buffer(offset, length)?; + let return_data = self.memory.read(offset, length)?.to_vec(); self.opcode_return_impl(return_data, backend).await } @@ -1304,26 +1349,26 @@ impl Machine { #[maybe_async] pub async fn opcode_return_impl( &mut self, - mut return_data: Buffer, + mut return_data: Vec, backend: &mut B, ) -> Result { if self.reason == Reason::Create { let code = std::mem::take(&mut return_data); - backend.set_code(self.context.contract, code)?; + backend.set_code(self.context.contract, self.chain_id, code)?; } backend.commit_snapshot(); sol_log_data(&[b"EXIT", b"RETURN"]); if self.parent.is_none() { - return Ok(Action::Return(return_data.to_vec())); + return Ok(Action::Return(return_data)); } - trace_end_step!(self, Some(return_data.to_vec())); + trace_end_step!(self, Some(return_data.clone())); tracing_event!( self, super::tracing::Event::EndVM { - status: super::ExitStatus::Return(return_data.to_vec()) + status: super::ExitStatus::Return(return_data.clone()) } ); @@ -1333,7 +1378,7 @@ impl Machine { self.memory.write_range(&self.return_range, &return_data)?; self.stack.push_bool(true)?; // success - self.return_data = return_data; + self.return_data = Buffer::from_vec(return_data); } Reason::Create => { let address = returned.context.contract; @@ -1350,7 +1395,7 @@ impl Machine { let offset = self.stack.pop_usize()?; let length = self.stack.pop_usize()?; - let return_data = self.memory.read_buffer(offset, length)?; + let return_data = self.memory.read(offset, length)?.to_vec(); self.opcode_revert_impl(return_data, backend).await } @@ -1358,21 +1403,21 @@ impl Machine { #[maybe_async] pub async fn opcode_revert_impl( &mut self, - return_data: Buffer, + return_data: Vec, backend: &mut B, ) -> Result { backend.revert_snapshot(); sol_log_data(&[b"EXIT", b"REVERT", &return_data]); if self.parent.is_none() { - return Ok(Action::Revert(return_data.to_vec())); + return Ok(Action::Revert(return_data)); } - trace_end_step!(self, Some(return_data.to_vec())); + trace_end_step!(self, Some(return_data.clone())); tracing_event!( self, super::tracing::Event::EndVM { - status: super::ExitStatus::Revert(return_data.to_vec()) + status: super::ExitStatus::Revert(return_data.clone()) } ); @@ -1387,7 +1432,7 @@ impl Machine { } } - self.return_data = return_data; + self.return_data = Buffer::from_vec(return_data); Ok(Action::Continue) } @@ -1408,11 +1453,12 @@ impl Machine { return Err(Error::StaticModeViolation(self.context.contract)); } - let address = *self.stack.pop_address()?; + let address = self.stack.pop_address()?; - let value = backend.balance(&self.context.contract).await?; + let chain_id = self.context.contract_chain_id; + let value = backend.balance(self.context.contract, chain_id).await?; backend - .transfer(self.context.contract, address, value) + .transfer(self.context.contract, address, chain_id, value) .await?; backend.selfdestruct(self.context.contract)?; diff --git a/evm_loader/program/src/evm/stack.rs b/evm_loader/program/src/evm/stack.rs index 71d45258f..8d8b322ba 100644 --- a/evm_loader/program/src/evm/stack.rs +++ b/evm_loader/program/src/evm/stack.rs @@ -115,7 +115,7 @@ impl Stack { } #[inline(always)] - pub fn pop_address(&mut self) -> Result<&Address, Error> { + pub fn pop_address(&mut self) -> Result { static_assertions::assert_eq_align!(Address, u8); static_assertions::assert_eq_size!(Address, [u8; 20]); @@ -123,7 +123,7 @@ impl Stack { let address = unsafe { let ptr = self.top.add(12); // discard 12 bytes - &*(ptr as *const Address) + *(ptr as *const Address) }; Ok(address) diff --git a/evm_loader/program/src/executor/action.rs b/evm_loader/program/src/executor/action.rs index 83af0d221..326224c16 100644 --- a/evm_loader/program/src/executor/action.rs +++ b/evm_loader/program/src/executor/action.rs @@ -14,14 +14,16 @@ pub enum Action { seeds: Vec>, fee: u64, }, - NeonTransfer { + Transfer { source: Address, target: Address, + chain_id: u64, #[serde(with = "ethnum::serde::bytes::le")] value: U256, }, - NeonWithdraw { + Burn { source: Address, + chain_id: u64, #[serde(with = "ethnum::serde::bytes::le")] value: U256, }, @@ -34,22 +36,61 @@ pub enum Action { }, EvmIncrementNonce { address: Address, + chain_id: u64, }, EvmSetCode { address: Address, - code: crate::evm::Buffer, + chain_id: u64, + #[serde(with = "serde_bytes")] + code: Vec, }, EvmSelfDestruct { address: Address, }, } +pub fn filter_selfdestruct(actions: Vec) -> Vec { + // Find all the account addresses which are scheduled to EvmSelfDestruct + let accounts_to_destroy: std::collections::HashSet<_> = actions + .iter() + .filter_map(|action| match action { + Action::EvmSelfDestruct { address } => Some(*address), + _ => None, + }) + .collect(); + + actions + .into_iter() + .filter(|action| { + match action { + // We always apply ExternalInstruction for Solana accounts + // and NeonTransfer + NeonWithdraw + Action::ExternalInstruction { .. } + | Action::Transfer { .. } + | Action::Burn { .. } => true, + // We remove EvmSetStorage|EvmIncrementNonce|EvmSetCode if account is scheduled for destroy + Action::EvmSetStorage { address, .. } + | Action::EvmSetCode { address, .. } + | Action::EvmIncrementNonce { address, .. } => { + !accounts_to_destroy.contains(address) + } + // SelfDestruct is only aplied to contracts deployed in the current transaction + Action::EvmSelfDestruct { .. } => false, + } + }) + .collect() +} + mod serde_bytes_32 { pub fn serialize(value: &[u8; 32], serializer: S) -> Result where S: serde::ser::Serializer, { - serializer.serialize_bytes(value) + if serializer.is_human_readable() { + serializer.serialize_str(&hex::encode(value)) + } else { + serializer.serialize_bytes(value) + } } pub fn deserialize<'de, D>(deserializer: D) -> Result<[u8; 32], D::Error> @@ -65,6 +106,21 @@ mod serde_bytes_32 { f.write_str("[u8; 32]") } + fn visit_str(self, value: &str) -> Result + where + E: serde::de::Error, + { + use serde::de::Unexpected::Str; + + let value = hex::decode(value) + .map_err(|_| serde::de::Error::invalid_value(Str(value), &self))?; + + let value_len = value.len(); + value + .try_into() + .map_err(|_| serde::de::Error::invalid_length(value_len, &self)) + } + fn visit_bytes(self, value: &[u8]) -> Result where E: serde::de::Error, @@ -88,7 +144,11 @@ mod serde_bytes_32 { } } - deserializer.deserialize_bytes(BytesVisitor) + if deserializer.is_human_readable() { + deserializer.deserialize_str(BytesVisitor) + } else { + deserializer.deserialize_bytes(BytesVisitor) + } } } diff --git a/evm_loader/program/src/executor/cache.rs b/evm_loader/program/src/executor/cache.rs index 062d2829a..0c3c51b6e 100644 --- a/evm_loader/program/src/executor/cache.rs +++ b/evm_loader/program/src/executor/cache.rs @@ -1,9 +1,12 @@ use std::{cell::RefCell, collections::BTreeMap, rc::Rc}; use ethnum::U256; +use maybe_async::maybe_async; use serde::{Deserialize, Serialize}; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; +use crate::account_storage::AccountStorage; + #[derive(Clone, Serialize, Deserialize)] pub struct OwnedAccountInfo { pub key: Pubkey, @@ -62,3 +65,22 @@ pub struct Cache { #[serde(with = "ethnum::serde::bytes::le")] pub block_timestamp: U256, } + +#[maybe_async] +#[allow(clippy::await_holding_refcell_ref)] // We don't use this RefCell in other execution context +pub async fn cache_get_or_insert_account( + cache: &RefCell, + key: Pubkey, + backend: &B, +) -> OwnedAccountInfo { + use std::collections::btree_map::Entry; + + let mut cache = cache.borrow_mut(); + match cache.solana_accounts.entry(key) { + Entry::Vacant(entry) => { + let owned_account_info = backend.clone_solana_account(&key).await; + entry.insert(owned_account_info).clone() + } + Entry::Occupied(entry) => entry.get().clone(), + } +} diff --git a/evm_loader/program/src/executor/state.rs b/evm_loader/program/src/executor/state.rs index 0d04a36c1..bf30b232d 100644 --- a/evm_loader/program/src/executor/state.rs +++ b/evm_loader/program/src/executor/state.rs @@ -13,7 +13,7 @@ use crate::evm::{Context, ExitStatus}; use crate::types::Address; use super::action::Action; -use super::cache::Cache; +use super::cache::{cache_get_or_insert_account, Cache}; use super::OwnedAccountInfo; /// Represents the state of executor abstracted away from a self.backend. @@ -67,7 +67,7 @@ impl<'a, B: AccountStorage> ExecutorState<'a, B> { pub fn into_actions(self) -> Vec { assert!(self.stack.is_empty()); - self.actions + crate::executor::action::filter_selfdestruct(self.actions) } pub fn exit_status(&self) -> Option<&ExitStatus> { @@ -82,9 +82,13 @@ impl<'a, B: AccountStorage> ExecutorState<'a, B> { self.stack.len() } - pub fn withdraw_neons(&mut self, source: Address, value: U256) { - let withdraw = Action::NeonWithdraw { source, value }; - self.actions.push(withdraw); + pub fn burn(&mut self, source: Address, chain_id: u64, value: U256) { + let burn = Action::Burn { + source, + chain_id, + value, + }; + self.actions.push(burn); } pub fn queue_external_instruction( @@ -120,29 +124,15 @@ impl<'a, B: AccountStorage> ExecutorState<'a, B> { .collect::>(); if !metas.iter().any(|m| (m.pubkey == address) && m.is_writable) { - insert_account_if_not_present(&self.cache, address, self.backend).await; - return Ok(self - .cache - .borrow() - .solana_accounts - .get(&address) - .unwrap() - .clone()); + let account = cache_get_or_insert_account(&self.cache, address, self.backend).await; + return Ok(account); } let mut accounts = BTreeMap::::new(); for m in metas { - insert_account_if_not_present(&self.cache, m.pubkey, self.backend).await; - accounts.insert( - m.pubkey, - self.cache - .borrow() - .solana_accounts - .get(&m.pubkey) - .unwrap() - .clone(), - ); + let account = cache_get_or_insert_account(&self.cache, m.pubkey, self.backend).await; + accounts.insert(account.key, account); } for action in &self.actions { @@ -183,71 +173,57 @@ impl<'a, B: AccountStorage> ExecutorState<'a, B> { } } -#[maybe_async] -async fn insert_account_if_not_present( - cache: &RefCell, - key: Pubkey, - backend: &B, -) { - if !cache.borrow().solana_accounts.contains_key(&key) { - let owned_account_info = backend.clone_solana_account(&key).await; - cache - .borrow_mut() - .solana_accounts - .insert(key, owned_account_info); - } -} - #[maybe_async(?Send)] impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { - fn chain_id(&self) -> U256 { - let chain_id = self.backend.chain_id(); - U256::from(chain_id) - } - - async fn nonce(&self, from_address: &Address) -> Result { - let mut nonce = self.backend.nonce(from_address).await; + async fn nonce(&self, from_address: Address, from_chain_id: u64) -> Result { + let mut nonce = self.backend.nonce(from_address, from_chain_id).await; + let mut increment = 0_u64; for action in &self.actions { - if let Action::EvmIncrementNonce { address } = action { - if from_address == address { - nonce = nonce.checked_add(1).ok_or(Error::IntegerOverflow)?; + if let Action::EvmIncrementNonce { address, chain_id } = action { + if (&from_address == address) && (&from_chain_id == chain_id) { + increment += 1; } } } + nonce = nonce.checked_add(increment).ok_or(Error::IntegerOverflow)?; + Ok(nonce) } - fn increment_nonce(&mut self, address: Address) -> Result<()> { - let increment = Action::EvmIncrementNonce { address }; + fn increment_nonce(&mut self, address: Address, chain_id: u64) -> Result<()> { + let increment = Action::EvmIncrementNonce { address, chain_id }; self.actions.push(increment); Ok(()) } - async fn balance(&self, from_address: &Address) -> Result { - let mut balance = self.backend.balance(from_address).await; + async fn balance(&self, from_address: Address, from_chain_id: u64) -> Result { + let mut balance = self.backend.balance(from_address, from_chain_id).await; for action in &self.actions { match action { - Action::NeonTransfer { + Action::Transfer { source, target, + chain_id, value, - } => { - if from_address == source { + } if (&from_chain_id == chain_id) => { + if &from_address == source { balance = balance.checked_sub(*value).ok_or(Error::IntegerOverflow)?; } - if from_address == target { + if &from_address == target { balance = balance.checked_add(*value).ok_or(Error::IntegerOverflow)?; } } - Action::NeonWithdraw { source, value } => { - if from_address == source { - balance = balance.checked_sub(*value).ok_or(Error::IntegerOverflow)?; - } + Action::Burn { + source, + chain_id, + value, + } if (&from_chain_id == chain_id) && (&from_address == source) => { + balance = balance.checked_sub(*value).ok_or(Error::IntegerOverflow)?; } _ => {} } @@ -256,22 +232,35 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { Ok(balance) } - async fn transfer(&mut self, source: Address, target: Address, value: U256) -> Result<()> { + async fn transfer( + &mut self, + source: Address, + target: Address, + chain_id: u64, + value: U256, + ) -> Result<()> { if value == U256::ZERO { return Ok(()); } + let target_chain_id = self.contract_chain_id(target).await.unwrap_or(chain_id); + + if (self.code_size(target).await? > 0) && (target_chain_id != chain_id) { + return Err(Error::InvalidTransferToken(source, chain_id)); + } + if source == target { return Ok(()); } - if self.balance(&source).await? < value { - return Err(Error::InsufficientBalance(source, value)); + if self.balance(source, chain_id).await? < value { + return Err(Error::InsufficientBalance(source, chain_id, value)); } - let transfer = Action::NeonTransfer { + let transfer = Action::Transfer { source, target, + chain_id, value, }; self.actions.push(transfer); @@ -279,14 +268,14 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { Ok(()) } - async fn code_size(&self, from_address: &Address) -> Result { - if self.is_precompile_extension(from_address) { + async fn code_size(&self, from_address: Address) -> Result { + if self.is_precompile_extension(&from_address) { return Ok(1); // This is required in order to make a normal call to an extension contract } for action in &self.actions { - if let Action::EvmSetCode { address, code } = action { - if from_address == address { + if let Action::EvmSetCode { address, code, .. } = action { + if &from_address == address { return Ok(code.len()); } } @@ -295,25 +284,25 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { Ok(self.backend.code_size(from_address).await) } - async fn code_hash(&self, from_address: &Address) -> Result<[u8; 32]> { + async fn code_hash(&self, from_address: Address, chain_id: u64) -> Result<[u8; 32]> { use solana_program::keccak::hash; for action in &self.actions { - if let Action::EvmSetCode { address, code } = action { - if from_address == address { + if let Action::EvmSetCode { address, code, .. } = action { + if &from_address == address { return Ok(hash(code).to_bytes()); } } } - Ok(self.backend.code_hash(from_address).await) + Ok(self.backend.code_hash(from_address, chain_id).await) } - async fn code(&self, from_address: &Address) -> Result { + async fn code(&self, from_address: Address) -> Result { for action in &self.actions { - if let Action::EvmSetCode { address, code } = action { - if from_address == address { - return Ok(code.clone()); + if let Action::EvmSetCode { address, code, .. } = action { + if &from_address == address { + return Ok(crate::evm::Buffer::from_slice(code)); } } } @@ -321,7 +310,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { Ok(self.backend.code(from_address).await) } - fn set_code(&mut self, address: Address, code: crate::evm::Buffer) -> Result<()> { + fn set_code(&mut self, address: Address, chain_id: u64, code: Vec) -> Result<()> { if code.starts_with(&[0xEF]) { // https://eips.ethereum.org/EIPS/eip-3541 return Err(Error::EVMObjectFormatNotSupported(address)); @@ -332,7 +321,11 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { return Err(Error::ContractCodeSizeLimit(address, code.len())); } - let set_code = Action::EvmSetCode { address, code }; + let set_code = Action::EvmSetCode { + address, + chain_id, + code, + }; self.actions.push(set_code); Ok(()) @@ -345,7 +338,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { Ok(()) } - async fn storage(&self, from_address: &Address, from_index: &U256) -> Result<[u8; 32]> { + async fn storage(&self, from_address: Address, from_index: U256) -> Result<[u8; 32]> { for action in self.actions.iter().rev() { if let Action::EvmSetStorage { address, @@ -353,7 +346,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { value, } = action { - if (from_address == address) && (from_index == index) { + if (&from_address == address) && (&from_index == index) { return Ok(*value); } } @@ -450,4 +443,27 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { self.call_precompile_extension(context, address, data, is_static) .await } + + fn default_chain_id(&self) -> u64 { + self.backend.default_chain_id() + } + + fn is_valid_chain_id(&self, chain_id: u64) -> bool { + self.backend.is_valid_chain_id(chain_id) + } + + async fn contract_chain_id(&self, contract: Address) -> Result { + for action in self.actions.iter().rev() { + if let Action::EvmSetCode { + address, chain_id, .. + } = action + { + if &contract == address { + return Ok(*chain_id); + } + } + } + + self.backend.contract_chain_id(contract).await + } } From 5d37cd3021cc7b85246a9a3526787a6b2c539382 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Tue, 14 Nov 2023 18:10:29 +0300 Subject: [PATCH 052/318] [Multi Tokens] Instructions changes --- evm_loader/program/src/entrypoint.rs | 99 +++++++-- evm_loader/program/src/gasometer.rs | 27 +-- .../src/instruction/account_block_add.rs | 62 +++--- .../program/src/instruction/account_create.rs | 71 ------ .../src/instruction/account_create_balance.rs | 42 ++++ .../src/instruction/account_holder_create.rs | 29 +-- .../src/instruction/account_holder_delete.rs | 31 +-- .../src/instruction/account_holder_write.rs | 32 +-- .../src/instruction/create_main_treasury.rs | 52 +++-- evm_loader/program/src/instruction/mod.rs | 46 ++-- .../src/instruction/neon_tokens_deposit.rs | 205 +++++++++--------- .../instruction/test_account_update_nonce.rs | 75 ------- .../src/instruction/transaction_cancel.rs | 90 +++----- .../src/instruction/transaction_execute.rs | 91 +++----- .../transaction_execute_from_account.rs | 53 ++--- .../transaction_execute_from_instruction.rs | 51 ++--- .../src/instruction/transaction_step.rs | 150 +++++-------- .../transaction_step_from_account.rs | 161 +++++++------- ...ransaction_step_from_account_no_chainid.rs | 35 +-- .../transaction_step_from_instruction.rs | 114 +++++----- 20 files changed, 630 insertions(+), 886 deletions(-) delete mode 100644 evm_loader/program/src/instruction/account_create.rs create mode 100644 evm_loader/program/src/instruction/account_create_balance.rs delete mode 100644 evm_loader/program/src/instruction/test_account_update_nonce.rs diff --git a/evm_loader/program/src/entrypoint.rs b/evm_loader/program/src/entrypoint.rs index f41a95a87..e58144bce 100644 --- a/evm_loader/program/src/entrypoint.rs +++ b/evm_loader/program/src/entrypoint.rs @@ -7,18 +7,53 @@ use solana_program::{ pubkey::Pubkey, }; -#[cfg(not(feature = "emergency"))] use crate::{instruction, instruction::EvmInstruction}; entrypoint!(process_instruction); #[cfg(feature = "emergency")] fn process_instruction<'a>( - _program_id: &'a Pubkey, - _accounts: &'a [AccountInfo<'a>], - _instruction_data: &[u8], + program_id: &'a Pubkey, + accounts: &'a [AccountInfo<'a>], + instruction_data: &[u8], ) -> ProgramResult { - Err!(ProgramError::InvalidInstructionData; "Emergency image: all instructions are rejected") + assert!(crate::check_id(program_id)); + + let (tag, instruction) = instruction_data + .split_first() + .ok_or(ProgramError::InvalidInstructionData)?; + + match EvmInstruction::parse(tag)? { + EvmInstruction::ConfigGetChainCount => { + instruction::config_get_chain_count::process(program_id, accounts, instruction) + } + EvmInstruction::ConfigGetChainInfo => { + instruction::config_get_chain_info::process(program_id, accounts, instruction) + } + EvmInstruction::ConfigGetEnvironment => { + instruction::config_get_environment::process(program_id, accounts, instruction) + } + EvmInstruction::ConfigGetPropertyCount => { + instruction::config_get_property_count::process(program_id, accounts, instruction) + } + EvmInstruction::ConfigGetPropertyByIndex => { + instruction::config_get_property_by_index::process(program_id, accounts, instruction) + } + EvmInstruction::ConfigGetPropertyByName => { + instruction::config_get_property_by_name::process(program_id, accounts, instruction) + } + EvmInstruction::ConfigGetStatus => { + instruction::config_get_status::process(program_id, accounts, instruction) + } + EvmInstruction::ConfigGetVersion => { + instruction::config_get_version::process(program_id, accounts, instruction) + } + _ => { + solana_program::msg!("Emergency image: all instructions are rejected"); + Err(ProgramError::InvalidInstructionData.into()) + } + } + .map_err(ProgramError::from) } #[cfg(not(feature = "emergency"))] @@ -27,22 +62,23 @@ fn process_instruction<'a>( accounts: &'a [AccountInfo<'a>], instruction_data: &[u8], ) -> ProgramResult { - let (tag, instruction) = instruction_data.split_first().ok_or_else( - || E!(ProgramError::InvalidInstructionData; "Invalid instruction - {:?}", instruction_data), - )?; + use crate::error::Error; + + assert!(crate::check_id(program_id)); + + let (tag, instruction) = instruction_data + .split_first() + .ok_or(ProgramError::InvalidInstructionData)?; match EvmInstruction::parse(tag)? { EvmInstruction::HolderCreate => { instruction::account_holder_create::process(program_id, accounts, instruction) - .map_err(ProgramError::from) } EvmInstruction::HolderDelete => { instruction::account_holder_delete::process(program_id, accounts, instruction) - .map_err(ProgramError::from) } EvmInstruction::HolderWrite => { instruction::account_holder_write::process(program_id, accounts, instruction) - .map_err(ProgramError::from) } EvmInstruction::DepositV03 => { instruction::neon_tokens_deposit::process(program_id, accounts, instruction) @@ -56,7 +92,6 @@ fn process_instruction<'a>( accounts, instruction, ) - .map_err(ProgramError::from) } EvmInstruction::TransactionExecuteFromAccount => { instruction::transaction_execute_from_account::process( @@ -64,7 +99,6 @@ fn process_instruction<'a>( accounts, instruction, ) - .map_err(ProgramError::from) } EvmInstruction::TransactionStepFromInstruction => { instruction::transaction_step_from_instruction::process( @@ -72,11 +106,9 @@ fn process_instruction<'a>( accounts, instruction, ) - .map_err(ProgramError::from) } EvmInstruction::TransactionStepFromAccount => { instruction::transaction_step_from_account::process(program_id, accounts, instruction) - .map_err(ProgramError::from) } EvmInstruction::TransactionStepFromAccountNoChainId => { instruction::transaction_step_from_account_no_chainid::process( @@ -84,24 +116,45 @@ fn process_instruction<'a>( accounts, instruction, ) - .map_err(ProgramError::from) - } - EvmInstruction::CreateAccountV03 => { - instruction::account_create::process(program_id, accounts, instruction) } EvmInstruction::CollectTreasure => { instruction::collect_treasury::process(program_id, accounts, instruction) + .map_err(Error::from) } EvmInstruction::CreateMainTreasury => { instruction::create_main_treasury::process(program_id, accounts, instruction) + .map_err(Error::from) } EvmInstruction::AccountBlockAdd => { instruction::account_block_add::process(program_id, accounts, instruction) - .map_err(ProgramError::from) } - EvmInstruction::TestAccountUpdateNonce => { - instruction::test_account_update_nonce::process(program_id, accounts, instruction) - .map_err(ProgramError::from) + EvmInstruction::AccountCreateBalance => { + instruction::account_create_balance::process(program_id, accounts, instruction) + } + EvmInstruction::ConfigGetChainCount => { + instruction::config_get_chain_count::process(program_id, accounts, instruction) + } + EvmInstruction::ConfigGetChainInfo => { + instruction::config_get_chain_info::process(program_id, accounts, instruction) + } + EvmInstruction::ConfigGetEnvironment => { + instruction::config_get_environment::process(program_id, accounts, instruction) + } + EvmInstruction::ConfigGetPropertyCount => { + instruction::config_get_property_count::process(program_id, accounts, instruction) + } + EvmInstruction::ConfigGetPropertyByIndex => { + instruction::config_get_property_by_index::process(program_id, accounts, instruction) + } + EvmInstruction::ConfigGetPropertyByName => { + instruction::config_get_property_by_name::process(program_id, accounts, instruction) + } + EvmInstruction::ConfigGetStatus => { + instruction::config_get_status::process(program_id, accounts, instruction) + } + EvmInstruction::ConfigGetVersion => { + instruction::config_get_version::process(program_id, accounts, instruction) } } + .map_err(ProgramError::from) } diff --git a/evm_loader/program/src/gasometer.rs b/evm_loader/program/src/gasometer.rs index 8894b694f..025a85b5a 100644 --- a/evm_loader/program/src/gasometer.rs +++ b/evm_loader/program/src/gasometer.rs @@ -9,32 +9,38 @@ use solana_program::program_error::ProgramError; pub const LAMPORTS_PER_SIGNATURE: u64 = 5000; const WRITE_TO_HOLDER_TRX_COST: u64 = LAMPORTS_PER_SIGNATURE; -const CANCEL_TRX_COST: u64 = LAMPORTS_PER_SIGNATURE; -const LAST_ITERATION_COST: u64 = LAMPORTS_PER_SIGNATURE; +pub const CANCEL_TRX_COST: u64 = LAMPORTS_PER_SIGNATURE; +pub const LAST_ITERATION_COST: u64 = LAMPORTS_PER_SIGNATURE; pub struct Gasometer { paid_gas: U256, gas: u64, + refund: u64, operator_balance: u64, } impl Gasometer { - pub fn new(paid_gas: Option, operator: &Operator) -> Result { + pub fn new(paid_gas: U256, operator: &Operator) -> Result { Ok(Self { - paid_gas: paid_gas.unwrap_or(U256::ZERO), + paid_gas, gas: 0_u64, + refund: 0_u64, operator_balance: operator.lamports(), }) } #[must_use] pub fn used_gas(&self) -> U256 { - U256::from(self.gas) + U256::from(self.gas.saturating_sub(self.refund)) } #[must_use] pub fn used_gas_total(&self) -> U256 { - self.paid_gas.saturating_add(U256::from(self.gas)) + self.paid_gas.saturating_add(self.used_gas()) + } + + pub fn refund_lamports(&mut self, lamports: u64) { + self.refund = self.refund.saturating_add(lamports); } pub fn record_operator_expenses(&mut self, operator: &Operator) { @@ -47,15 +53,6 @@ impl Gasometer { self.gas = self.gas.saturating_add(LAMPORTS_PER_SIGNATURE); } - pub fn record_iterative_overhead(&mut self) { - // High chance of last iteration to fail with solana error - // Consume gas for it in the first iteration - self.gas = self - .gas - .saturating_add(LAST_ITERATION_COST) - .saturating_add(CANCEL_TRX_COST); - } - pub fn record_write_to_holder(&mut self, trx: &Transaction) { let size: u64 = trx.rlp_len().try_into().expect("usize is 8 bytes"); let cost: u64 = ((size + (HOLDER_MSG_SIZE - 1)) / HOLDER_MSG_SIZE) diff --git a/evm_loader/program/src/instruction/account_block_add.rs b/evm_loader/program/src/instruction/account_block_add.rs index 4d16feba9..ab2f5254b 100644 --- a/evm_loader/program/src/instruction/account_block_add.rs +++ b/evm_loader/program/src/instruction/account_block_add.rs @@ -1,14 +1,10 @@ -use std::collections::BTreeSet; - -use crate::account::{EthereumAccount, Operator, State}; -use crate::error::{Error, Result}; -use crate::state_account::BlockedAccountMeta; +use crate::error::Result; use solana_program::instruction::TRANSACTION_LEVEL_STACK_HEIGHT; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; pub fn process<'a>( - program_id: &'a Pubkey, - accounts: &'a [AccountInfo<'a>], + _program_id: &'a Pubkey, + _accounts: &'a [AccountInfo<'a>], _instruction: &[u8], ) -> Result<()> { let stack_height = solana_program::instruction::get_stack_height(); @@ -16,37 +12,39 @@ pub fn process<'a>( solana_program::msg!("Instruction: Block Accounts"); - let mut state = State::from_account(program_id, &accounts[0])?; - let operator = Operator::from_account(&accounts[1])?; + todo!(); + + // let mut state = State::from_account(program_id, &accounts[0])?; + // let operator = Operator::from_account(&accounts[1])?; - if &state.owner != operator.key { - return Err(Error::HolderInvalidOwner(state.owner, *operator.key)); - } + // if &state.owner != operator.key { + // return Err(Error::HolderInvalidOwner(state.owner, *operator.key)); + // } - let mut blocked_accounts = state.read_blocked_accounts()?; - let mut blocked_keys: BTreeSet = blocked_accounts.iter().map(|a| a.key).collect(); + // let mut blocked_accounts = state.read_blocked_accounts()?; + // let mut blocked_keys: BTreeSet = blocked_accounts.iter().map(|a| a.key).collect(); - for account_info in &accounts[2..] { - if blocked_keys.contains(account_info.key) { - continue; - } + // for account_info in &accounts[2..] { + // if blocked_keys.contains(account_info.key) { + // continue; + // } - let mut meta = BlockedAccountMeta { - key: *account_info.key, - exists: false, - is_writable: account_info.is_writable, - }; + // let mut meta = BlockedAccountMeta { + // key: *account_info.key, + // exists: false, + // is_writable: account_info.is_writable, + // }; - if let Ok(mut account) = EthereumAccount::from_account(program_id, account_info) { - account.check_blocked()?; - account.rw_blocked = true; + // if let Ok(mut account) = EthereumAccount::from_account(program_id, account_info) { + // account.check_blocked()?; + // account.rw_blocked = true; - meta.exists = true; - } + // meta.exists = true; + // } - blocked_accounts.push(meta); - blocked_keys.insert(*account_info.key); - } + // blocked_accounts.push(meta); + // blocked_keys.insert(*account_info.key); + // } - state.update_blocked_accounts(blocked_accounts.into_iter()) + // state.update_blocked_accounts(blocked_accounts.into_iter()) } diff --git a/evm_loader/program/src/instruction/account_create.rs b/evm_loader/program/src/instruction/account_create.rs deleted file mode 100644 index 75b7fb567..000000000 --- a/evm_loader/program/src/instruction/account_create.rs +++ /dev/null @@ -1,71 +0,0 @@ -use arrayref::array_ref; -use solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, - pubkey::Pubkey, -}; - -use crate::account::{program, EthereumAccount, Operator}; -use crate::types::Address; - -struct Accounts<'a> { - operator: Operator<'a>, - system_program: program::System<'a>, - ether_account: &'a AccountInfo<'a>, -} - -pub fn process<'a>( - program_id: &'a Pubkey, - accounts: &'a [AccountInfo<'a>], - instruction: &[u8], -) -> ProgramResult { - solana_program::msg!("Instruction: Create Account"); - - let parsed_accounts = Accounts { - operator: unsafe { Operator::from_account_not_whitelisted(&accounts[0]) }?, - system_program: program::System::from_account(&accounts[1])?, - ether_account: &accounts[2], - }; - - let address = array_ref![instruction, 0, 20]; - let address = Address::from(*address); - solana_program::msg!("Address: {}", address); - - let bump_seed = validate(program_id, &parsed_accounts, &address)?; - execute(program_id, &parsed_accounts, address, bump_seed) -} - -fn validate( - program_id: &Pubkey, - accounts: &Accounts, - address: &Address, -) -> Result { - if !solana_program::system_program::check_id(accounts.ether_account.owner) { - return Err!(ProgramError::InvalidArgument; "Account {} - expected system owned", accounts.ether_account.key); - } - - let (expected_address, bump_seed) = address.find_solana_address(program_id); - if expected_address != *accounts.ether_account.key { - return Err!(ProgramError::InvalidArgument; "Account {} - expected PDA address {}", accounts.ether_account.key, expected_address); - } - - Ok(bump_seed) -} - -fn execute( - program_id: &Pubkey, - accounts: &Accounts, - address: Address, - bump_seed: u8, -) -> ProgramResult { - EthereumAccount::create_and_init_account( - &accounts.system_program, - program_id, - &accounts.operator, - address, - accounts.ether_account, - bump_seed, - EthereumAccount::SIZE, - )?; - - Ok(()) -} diff --git a/evm_loader/program/src/instruction/account_create_balance.rs b/evm_loader/program/src/instruction/account_create_balance.rs new file mode 100644 index 000000000..08743ac92 --- /dev/null +++ b/evm_loader/program/src/instruction/account_create_balance.rs @@ -0,0 +1,42 @@ +use arrayref::array_ref; +use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; + +use crate::account::{program, AccountsDB, BalanceAccount, Operator}; +use crate::config::DEFAULT_CHAIN_ID; +use crate::error::Result; +use crate::types::Address; + +pub fn process<'a>( + _program_id: &'a Pubkey, + accounts: &'a [AccountInfo<'a>], + instruction: &[u8], +) -> Result<()> { + solana_program::msg!("Instruction: Create Balance Account"); + + let operator = unsafe { Operator::from_account_not_whitelisted(&accounts[0]) }?; + let system = program::System::from_account(&accounts[1])?; + + let accounts_db = AccountsDB::new(&accounts[2..], operator, None, Some(system), None); + + let address = array_ref![instruction, 0, 20]; + let address = Address::from(*address); + + let chain_id = array_ref![instruction, 20, 8]; + let chain_id = u64::from_le_bytes(*chain_id); + + // TODO: validate chain_id? + + solana_program::msg!("Address: {}, ChainID: {}", address, chain_id); + + let mut excessive_lamports = 0; + if chain_id == DEFAULT_CHAIN_ID { + // we don't have enough accounts to update non Neon chains + excessive_lamports += crate::account::legacy::update_legacy_accounts(&accounts_db)?; + }; + + BalanceAccount::create(address, chain_id, &accounts_db, None)?; + + **accounts_db.operator().try_borrow_mut_lamports()? += excessive_lamports; + + Ok(()) +} diff --git a/evm_loader/program/src/instruction/account_holder_create.rs b/evm_loader/program/src/instruction/account_holder_create.rs index 19bc61c7b..7509b9d1c 100644 --- a/evm_loader/program/src/instruction/account_holder_create.rs +++ b/evm_loader/program/src/instruction/account_holder_create.rs @@ -1,40 +1,23 @@ use crate::account::{Holder, Operator}; +use crate::error::Result; use arrayref::array_ref; -use solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, - pubkey::Pubkey, -}; +use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; pub fn process<'a>( program_id: &'a Pubkey, accounts: &'a [AccountInfo<'a>], instruction: &[u8], -) -> ProgramResult { +) -> Result<()> { solana_program::msg!("Instruction: Create Holder Account"); - let holder = &accounts[0]; + let holder = accounts[0].clone(); let operator = unsafe { Operator::from_account_not_whitelisted(&accounts[1]) }?; let seed_len = usize::from_le_bytes(*array_ref![instruction, 0, 8]); let seed_bytes = instruction[8..8 + seed_len].to_vec(); - let seed = String::from_utf8(seed_bytes) - .map_err(|_| E!(ProgramError::InvalidArgument; "Seed bytes aren't valid UTF8"))?; + let seed = std::str::from_utf8(&seed_bytes)?; - let expected_holder = Pubkey::create_with_seed(operator.key, &seed, program_id) - .map_err(|_| E!(ProgramError::InvalidArgument; "Invalid seed bytes"))?; - if expected_holder != *holder.key { - return Err!(ProgramError::InvalidArgument; "Holder doesn't match seeds"); - } - - Holder::init( - program_id, - holder, - crate::account::holder::Data { - owner: *operator.key, - transaction_hash: [0_u8; 32], - transaction_len: 0, - }, - )?; + Holder::create(program_id, holder, seed, &operator)?; Ok(()) } diff --git a/evm_loader/program/src/instruction/account_holder_delete.rs b/evm_loader/program/src/instruction/account_holder_delete.rs index da8af4ea3..8873f2642 100644 --- a/evm_loader/program/src/instruction/account_holder_delete.rs +++ b/evm_loader/program/src/instruction/account_holder_delete.rs @@ -1,5 +1,5 @@ -use crate::account::{FinalizedState, Holder, Operator}; -use crate::error::{Error, Result}; +use crate::account::{Holder, Operator}; +use crate::error::Result; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; pub fn process<'a>( @@ -9,30 +9,15 @@ pub fn process<'a>( ) -> Result<()> { solana_program::msg!("Instruction: Delete Holder Account"); + let holder_info = accounts[0].clone(); let operator = unsafe { Operator::from_account_not_whitelisted(&accounts[1]) }?; - match crate::account::tag(program_id, &accounts[0])? { - Holder::TAG => { - let holder = Holder::from_account(program_id, &accounts[0])?; - holder.validate_owner(&operator)?; + crate::account::legacy::update_holder_account(&holder_info)?; - unsafe { - holder.suicide(&operator); - } - } - FinalizedState::TAG => { - let finalized = FinalizedState::from_account(program_id, &accounts[0])?; - if &finalized.owner != operator.key { - return Err(Error::HolderInvalidOwner(finalized.owner, *operator.key)); - } - - unsafe { - finalized.suicide(&operator); - } - } - _ => { - return Err(Error::AccountInvalidTag(*accounts[0].key, Holder::TAG)); - } + let holder = Holder::from_account(program_id, holder_info)?; + holder.validate_owner(&operator)?; + unsafe { + holder.suicide(&operator); } Ok(()) diff --git a/evm_loader/program/src/instruction/account_holder_write.rs b/evm_loader/program/src/instruction/account_holder_write.rs index c305cc5c9..47cca15eb 100644 --- a/evm_loader/program/src/instruction/account_holder_write.rs +++ b/evm_loader/program/src/instruction/account_holder_write.rs @@ -1,5 +1,5 @@ -use crate::account::{FinalizedState, Holder, Operator}; -use crate::error::{Error, Result}; +use crate::account::{Holder, Operator}; +use crate::error::Result; use arrayref::array_ref; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; @@ -14,32 +14,14 @@ pub fn process<'a>( let offset = usize::from_le_bytes(*array_ref![instruction, 32, 8]); let data = &instruction[32 + 8..]; - let holder_info = &accounts[0]; - - let mut holder = match crate::account::tag(program_id, holder_info)? { - Holder::TAG => Holder::from_account(program_id, holder_info), - FinalizedState::TAG => { - let finalized_state = FinalizedState::from_account(program_id, holder_info)?; - let holder_data = crate::account::holder::Data { - owner: finalized_state.owner, - transaction_hash, - transaction_len: 0, - }; - unsafe { finalized_state.replace(holder_data) } - } - _ => { - return Err(Error::AccountInvalidTag(*holder_info.key, Holder::TAG)); - } - }?; - + let holder_info = accounts[0].clone(); let operator = unsafe { Operator::from_account_not_whitelisted(&accounts[1]) }?; - holder.validate_owner(&operator)?; + crate::account::legacy::update_holder_account(&holder_info)?; - if holder.transaction_hash != transaction_hash { - holder.clear()?; - holder.transaction_hash = transaction_hash; - } + let mut holder = Holder::from_account(program_id, holder_info)?; + holder.validate_owner(&operator)?; + holder.update_transaction_hash(transaction_hash); solana_program::log::sol_log_data(&[b"HASH", &transaction_hash]); diff --git a/evm_loader/program/src/instruction/create_main_treasury.rs b/evm_loader/program/src/instruction/create_main_treasury.rs index 172b36d30..86c5f7972 100644 --- a/evm_loader/program/src/instruction/create_main_treasury.rs +++ b/evm_loader/program/src/instruction/create_main_treasury.rs @@ -1,13 +1,12 @@ use crate::{ account::{program::System, program::Token, MainTreasury, Operator}, config::TREASURY_POOL_SEED, + error::{Error, Result}, }; use solana_program::{ account_info::AccountInfo, bpf_loader_upgradeable::{self, UpgradeableLoaderState}, - entrypoint::ProgramResult, msg, - program_error::ProgramError, program_pack::Pack, pubkey::Pubkey, system_program, @@ -24,7 +23,7 @@ struct Accounts<'a> { } impl<'a> Accounts<'a> { - pub fn from_slice(accounts: &'a [AccountInfo<'a>]) -> Result, ProgramError> { + pub fn from_slice(accounts: &'a [AccountInfo<'a>]) -> Result> { Ok(Accounts { main_treasury: &accounts[0], program_data: &accounts[1], @@ -40,26 +39,26 @@ impl<'a> Accounts<'a> { fn get_program_upgrade_authority<'a>( program_id: &'a Pubkey, program_data: &'a AccountInfo<'a>, -) -> Result { +) -> Result { let (expected_program_data_key, _) = Pubkey::find_program_address(&[program_id.as_ref()], &bpf_loader_upgradeable::id()); if *program_data.key != expected_program_data_key { - return Err!(ProgramError::InvalidArgument; "Account {} - invalid current program data account", program_data.key); + return Err(Error::AccountInvalidKey( + *program_data.key, + expected_program_data_key, + )); } - let unpacked_program_data: UpgradeableLoaderState = bincode::deserialize( - &program_data.data.borrow(), - ) - .map_err(|_| E!(ProgramError::InvalidAccountData; "Unable to deserialize program data"))?; + let unpacked_program_data: UpgradeableLoaderState = + bincode::deserialize(&program_data.data.borrow())?; let upgrade_authority: Pubkey = match unpacked_program_data { UpgradeableLoaderState::ProgramData { slot: _, upgrade_authority_address, - } => upgrade_authority_address - .ok_or_else(|| E!(ProgramError::InvalidAccountData; "Not upgradeable program" ))?, - _ => return Err!(ProgramError::InvalidAccountData; "Not ProgramData"), + } => upgrade_authority_address.ok_or_else(|| Error::from("Not upgradeable program"))?, + _ => return Err(Error::from("Not ProgramData")), }; Ok(upgrade_authority) @@ -69,35 +68,50 @@ pub fn process<'a>( program_id: &'a Pubkey, accounts: &'a [AccountInfo<'a>], _instruction: &[u8], -) -> ProgramResult { +) -> Result<()> { msg!("Instruction: Create Main Treasury"); let accounts = Accounts::from_slice(accounts)?; let (expected_key, bump_seed) = MainTreasury::address(program_id); if *accounts.main_treasury.key != expected_key { - return Err!(ProgramError::InvalidArgument; "Account {} - invalid main treasure account", accounts.main_treasury.key); + return Err(Error::AccountInvalidKey( + *accounts.main_treasury.key, + expected_key, + )); } if *accounts.mint.key != spl_token::native_mint::id() { - return Err!(ProgramError::InvalidArgument; "Account {} - not wrapped SOL mint", accounts.mint.key); + return Err(Error::Custom(std::format!( + "Account {} - not wrapped SOL mint", + accounts.mint.key + ))); } if *accounts.system_program.key != system_program::id() { - return Err!(ProgramError::InvalidArgument; "Account {} - not system program", accounts.system_program.key); + return Err(Error::AccountInvalidKey( + *accounts.system_program.key, + system_program::id(), + )); } if *accounts.token_program.key != spl_token::id() { - return Err!(ProgramError::InvalidArgument; "Account {} - not spl-token program", accounts.token_program.key); + return Err(Error::AccountInvalidKey( + *accounts.token_program.key, + spl_token::id(), + )); } let expected_upgrade_auth_key = get_program_upgrade_authority(program_id, accounts.program_data)?; if *accounts.program_upgrade_auth.key != expected_upgrade_auth_key { - return Err!(ProgramError::InvalidArgument; "Account {} - invalid program upgrade authority", accounts.program_upgrade_auth.key); + return Err(Error::AccountInvalidKey( + *accounts.program_upgrade_auth.key, + expected_upgrade_auth_key, + )); } if !accounts.program_upgrade_auth.is_signer { - return Err!(ProgramError::MissingRequiredSignature; "Required signature from program upgrade authority"); + return Err(Error::AccountNotSigner(*accounts.program_upgrade_auth.key)); } accounts.system_program.create_pda_account( diff --git a/evm_loader/program/src/instruction/mod.rs b/evm_loader/program/src/instruction/mod.rs index 63f45e32f..5648cff75 100644 --- a/evm_loader/program/src/instruction/mod.rs +++ b/evm_loader/program/src/instruction/mod.rs @@ -20,13 +20,6 @@ pub enum EvmInstruction { /// 5. `[]` System program. DepositV03, - /// Create Ethereum account V3 - /// # Account references - /// 0. [WRITE, SIGNER] Funding account - /// 1. [] System Program - /// 2. [WRITE] New account (program_address(version, ether, bump_seed)) - CreateAccountV03, - /// Collect lamports from treasury pool accounts to main pool balance /// 0. `[WRITE]` Main treasury balance: PDA["treasury_pool"] /// 1. `[WRITE]` Auxiliary treasury balance: PDA["treasury_pool", index.to_le_bytes()] @@ -73,8 +66,17 @@ pub enum EvmInstruction { /// Block additional accounts AccountBlockAdd, - /// Modify account's nonce. Only for test environment. - TestAccountUpdateNonce, + /// Create User Balance account + AccountCreateBalance, + + ConfigGetChainCount, + ConfigGetChainInfo, + ConfigGetEnvironment, + ConfigGetPropertyCount, + ConfigGetPropertyByIndex, + ConfigGetPropertyByName, + ConfigGetStatus, + ConfigGetVersion, } impl EvmInstruction { @@ -94,23 +96,39 @@ impl EvmInstruction { 0x25 => Self::HolderDelete, // 37 0x26 => Self::HolderWrite, // 38 0x27 => Self::DepositV03, // 39 - 0x28 => Self::CreateAccountV03, // 40 0x29 => Self::CreateMainTreasury, // 41 0x2A => Self::TransactionExecuteFromAccount, // 42 0x2B => Self::AccountBlockAdd, // 43 - 0x2C => Self::TestAccountUpdateNonce, // 44 - + // 0x2C => Self::TestAccountUpdateNonce, // 44 + 0x2D => Self::AccountCreateBalance, // 45 + + 0xA0 => Self::ConfigGetChainCount, // 160 + 0xA1 => Self::ConfigGetChainInfo, + 0xA2 => Self::ConfigGetEnvironment, + 0xA3 => Self::ConfigGetPropertyCount, + 0xA4 => Self::ConfigGetPropertyByIndex, + 0xA5 => Self::ConfigGetPropertyByName, + 0xA6 => Self::ConfigGetStatus, + 0xA7 => Self::ConfigGetVersion, _ => return Err(ProgramError::InvalidInstructionData), }) } } pub mod account_block_add; -pub mod account_create; +pub mod account_create_balance; pub mod account_holder_create; pub mod account_holder_delete; pub mod account_holder_write; pub mod collect_treasury; +pub mod config_get_chain_count; +pub mod config_get_chain_info; +pub mod config_get_environment; +pub mod config_get_property_by_index; +pub mod config_get_property_by_name; +pub mod config_get_property_count; +pub mod config_get_status; +pub mod config_get_version; pub mod create_main_treasury; pub mod neon_tokens_deposit; pub mod transaction_cancel; @@ -121,5 +139,3 @@ pub mod transaction_step; pub mod transaction_step_from_account; pub mod transaction_step_from_account_no_chainid; pub mod transaction_step_from_instruction; - -pub mod test_account_update_nonce; diff --git a/evm_loader/program/src/instruction/neon_tokens_deposit.rs b/evm_loader/program/src/instruction/neon_tokens_deposit.rs index 0ae014f8f..b0ecb80fc 100644 --- a/evm_loader/program/src/instruction/neon_tokens_deposit.rs +++ b/evm_loader/program/src/instruction/neon_tokens_deposit.rs @@ -1,19 +1,20 @@ use arrayref::array_ref; use ethnum::U256; use solana_program::program::invoke_signed; -use solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, - pubkey::Pubkey, -}; +use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; use spl_associated_token_account::get_associated_token_address; -use crate::account::{program, token, EthereumAccount, Operator, ACCOUNT_SEED_VERSION}; +use crate::account::{program, token, AccountsDB, BalanceAccount, Operator, ACCOUNT_SEED_VERSION}; +use crate::config::DEFAULT_CHAIN_ID; +use crate::error::{Error, Result}; use crate::types::Address; struct Accounts<'a> { + mint: token::Mint<'a>, source: token::State<'a>, pool: token::State<'a>, - ethereum_account: &'a AccountInfo<'a>, + balance_account: &'a AccountInfo<'a>, + contract_account: &'a AccountInfo<'a>, token_program: program::Token<'a>, operator: Operator<'a>, system_program: program::System<'a>, @@ -22,14 +23,16 @@ struct Accounts<'a> { const AUTHORITY_SEED: &[u8] = b"Deposit"; impl<'a> Accounts<'a> { - pub fn from_slice(accounts: &'a [AccountInfo<'a>]) -> Result, ProgramError> { + pub fn from_slice(accounts: &'a [AccountInfo<'a>]) -> Result> { Ok(Accounts { - source: token::State::from_account(&accounts[0])?, - pool: token::State::from_account(&accounts[1])?, - ethereum_account: &accounts[2], - token_program: program::Token::from_account(&accounts[3])?, - operator: unsafe { Operator::from_account_not_whitelisted(&accounts[4]) }?, - system_program: program::System::from_account(&accounts[5])?, + mint: token::Mint::from_account(&accounts[0])?, + source: token::State::from_account(&accounts[1])?, + pool: token::State::from_account(&accounts[2])?, + balance_account: &accounts[3], + contract_account: &accounts[4], + token_program: program::Token::from_account(&accounts[5])?, + operator: unsafe { Operator::from_account_not_whitelisted(&accounts[6]) }?, + system_program: program::System::from_account(&accounts[7])?, }) } } @@ -38,106 +41,91 @@ pub fn process<'a>( program_id: &'a Pubkey, accounts: &'a [AccountInfo<'a>], instruction: &[u8], -) -> ProgramResult { +) -> Result<()> { solana_program::msg!("Instruction: Deposit"); let parsed_accounts = Accounts::from_slice(accounts)?; - let ethereum_address = Address::from(*array_ref![instruction, 0, 20]); - - let ethereum_bump_seed = validate(program_id, &parsed_accounts, ðereum_address)?; - execute( - program_id, - &parsed_accounts, - ethereum_address, - ethereum_bump_seed, - ) + + let address = array_ref![instruction, 0, 20]; + let address = Address::from(*address); + + let chain_id = array_ref![instruction, 20, 8]; + let chain_id = u64::from_le_bytes(*chain_id); + + validate(program_id, &parsed_accounts, address, chain_id)?; + execute(program_id, parsed_accounts, address, chain_id) } fn validate( program_id: &Pubkey, accounts: &Accounts, - ethereum_address: &Address, -) -> Result { - let (expected_solana_address, ethereum_bump_seed) = - ethereum_address.find_solana_address(program_id); - if expected_solana_address != *accounts.ethereum_account.key { - return Err!( - ProgramError::InvalidArgument; - "Account {} - expected PDA address {}", - accounts.ethereum_account.key, - expected_solana_address - ); + address: Address, + chain_id: u64, +) -> Result<()> { + let balance_account = *accounts.balance_account.key; + let contract_account = *accounts.contract_account.key; + let pool = *accounts.pool.info.key; + let mint = *accounts.mint.info.key; + + let (expected_pubkey, _) = address.find_balance_address(program_id, chain_id); + if expected_pubkey != balance_account { + return Err(Error::AccountInvalidKey(balance_account, expected_pubkey)); } - if accounts.source.mint != crate::config::token_mint::id() { - return Err!( - ProgramError::InvalidArgument; - "Account {} - expected Neon Token account", - accounts.source.info.key - ); + let (expected_pubkey, _) = address.find_solana_address(program_id); + if expected_pubkey != contract_account { + return Err(Error::AccountInvalidKey(contract_account, expected_pubkey)); + } + + let Ok(chain_id_index) = crate::config::CHAIN_ID_LIST.binary_search_by_key(&chain_id, |c| c.0) else { + return Err(Error::InvalidChainId(chain_id)); + }; + + let expected_mint = crate::config::CHAIN_ID_LIST[chain_id_index].2; + if mint != expected_mint { + return Err(Error::AccountInvalidKey(mint, expected_mint)); } let (authority_address, _) = Pubkey::find_program_address(&[AUTHORITY_SEED], program_id); - let expected_pool_address = - get_associated_token_address(&authority_address, &crate::config::token_mint::id()); - - if accounts.pool.info.key != &expected_pool_address { - return Err!( - ProgramError::InvalidArgument; - "Account {} - expected Neon Token Pool {}", - accounts.pool.info.key, - expected_pool_address - ); + let expected_pool = get_associated_token_address(&authority_address, &mint); + if pool != expected_pool { + return Err(Error::AccountInvalidKey(pool, expected_pool)); } - if accounts.pool.mint != crate::config::token_mint::id() { - return Err!( - ProgramError::InvalidArgument; - "Account {} - expected Neon Token account", - accounts.pool.info.key - ); + if (accounts.pool.mint != mint) || (accounts.source.mint != mint) { + return Err(Error::from("Invalid token mint")); } - if !accounts + let is_correct_delegate = accounts .source .delegate - .contains(accounts.ethereum_account.key) - { - return Err!( - ProgramError::InvalidArgument; - "Account {} - expected tokens delegated to an user account", - accounts.source.info.key - ); + .contains(accounts.balance_account.key); + + if !is_correct_delegate { + return Err(Error::from("Expected tokens delegated to balance account")); } if accounts.source.delegated_amount < 1 { - return Err!( - ProgramError::InvalidArgument; - "Account {} - expected positive tokens amount delegated to an user account", - accounts.source.info.key - ); + return Err(Error::from("Expected positive tokens amount delegated")); } - Ok(ethereum_bump_seed) + Ok(()) } -fn execute( - program_id: &Pubkey, - accounts: &Accounts, - ethereum_address: Address, - ethereum_bump_seed: u8, -) -> ProgramResult { - let signers_seeds: &[&[&[u8]]] = &[&[ +fn execute(program_id: &Pubkey, accounts: Accounts, address: Address, chain_id: u64) -> Result<()> { + let (_, bump_seed) = address.find_balance_address(program_id, chain_id); + let signer_seeds: &[&[u8]] = &[ &[ACCOUNT_SEED_VERSION], - ethereum_address.as_bytes(), - &[ethereum_bump_seed], - ]]; + address.as_bytes(), + &U256::from(chain_id).to_be_bytes(), + &[bump_seed], + ]; let instruction = spl_token::instruction::transfer( accounts.token_program.key, accounts.source.info.key, accounts.pool.info.key, - accounts.ethereum_account.key, + accounts.balance_account.key, &[], accounts.source.delegated_amount, )?; @@ -145,38 +133,39 @@ fn execute( let account_infos: &[AccountInfo] = &[ accounts.source.info.clone(), accounts.pool.info.clone(), - accounts.ethereum_account.clone(), + accounts.balance_account.clone(), accounts.token_program.clone(), ]; - invoke_signed(&instruction, account_infos, signers_seeds)?; - - if solana_program::system_program::check_id(accounts.ethereum_account.owner) { - EthereumAccount::create_and_init_account( - &accounts.system_program, - program_id, - &accounts.operator, - ethereum_address, - accounts.ethereum_account, - ethereum_bump_seed, - EthereumAccount::SIZE, - )?; - } + invoke_signed(&instruction, account_infos, &[signer_seeds])?; + + let token_decimals = accounts.mint.decimals; + assert!(token_decimals <= 18); - let additional_decimals: u32 = (18 - crate::config::token_mint::decimals()).into(); + let additional_decimals: u32 = (18 - token_decimals).into(); let deposit = U256::from(accounts.source.delegated_amount) * 10_u128.pow(additional_decimals); - let mut ethereum_account = - EthereumAccount::from_account(program_id, accounts.ethereum_account)?; - ethereum_account.balance = ethereum_account - .balance - .checked_add(deposit) - .ok_or_else(|| { - E!( - ProgramError::InvalidArgument; - "Account {} - balance overflow", - ethereum_address - ) - })?; + + let accounts_db = AccountsDB::new( + &[ + accounts.balance_account.clone(), + accounts.contract_account.clone(), + ], + accounts.operator, + None, + Some(accounts.system_program), + None, + ); + + let mut excessive_lamports = 0; + if chain_id == DEFAULT_CHAIN_ID { + // we don't have enough accounts to update non Neon chains + excessive_lamports += crate::account::legacy::update_legacy_accounts(&accounts_db)?; + } + + let mut balance_account = BalanceAccount::create(address, chain_id, &accounts_db, None)?; + balance_account.mint(deposit)?; + + **accounts_db.operator().try_borrow_mut_lamports()? += excessive_lamports; Ok(()) } diff --git a/evm_loader/program/src/instruction/test_account_update_nonce.rs b/evm_loader/program/src/instruction/test_account_update_nonce.rs deleted file mode 100644 index f974eacf4..000000000 --- a/evm_loader/program/src/instruction/test_account_update_nonce.rs +++ /dev/null @@ -1,75 +0,0 @@ -use crate::{ - account::EthereumAccount, - error::{Error, Result}, -}; -use arrayref::array_ref; -use solana_program::{ - account_info::AccountInfo, - bpf_loader_upgradeable::{self, UpgradeableLoaderState}, - program_error::ProgramError, - pubkey::Pubkey, -}; - -struct Accounts<'a> { - program_data: &'a AccountInfo<'a>, - signer: &'a AccountInfo<'a>, - ethereum_account: EthereumAccount<'a>, -} - -fn get_program_upgrade_authority( - program_id: &Pubkey, - program_data: &AccountInfo, -) -> Result { - let (expected_key, _) = - Pubkey::find_program_address(&[program_id.as_ref()], &bpf_loader_upgradeable::id()); - - if *program_data.key != expected_key { - return Err(Error::AccountInvalidKey(*program_data.key, expected_key)); - } - - match bincode::deserialize(&program_data.data.borrow())? { - UpgradeableLoaderState::ProgramData { - upgrade_authority_address, - .. - } => upgrade_authority_address - .ok_or_else(|| "NeonEVM must have valid upgrade authority".into()), - _ => Err(Error::AccountInvalidData(*program_data.key)), - } -} - -pub fn process<'a>( - program_id: &'a Pubkey, - accounts: &'a [AccountInfo<'a>], - instruction: &[u8], -) -> Result<()> { - solana_program::msg!("Instruction: TEST Set Account Nonce"); - - if cfg!(feature = "mainnet") { - return Err(ProgramError::InvalidInstructionData.into()); - } - - if !(cfg!(feature = "devnet") || cfg!(feature = "testnet") || cfg!(feature = "ci")) { - return Err(ProgramError::InvalidInstructionData.into()); - } - - let nonce = u64::from_le_bytes(*array_ref![instruction, 0, 8]); - - let mut accounts = Accounts { - signer: &accounts[0], - program_data: &accounts[1], - ethereum_account: EthereumAccount::from_account(program_id, &accounts[2])?, - }; - - if !accounts.signer.is_signer { - return Err(Error::AccountNotSigner(*accounts.signer.key)); - } - - let upgrade_authority = get_program_upgrade_authority(program_id, accounts.program_data)?; - if upgrade_authority != *accounts.signer.key { - return Err("Signer is not program upgrade authority".into()); - } - - accounts.ethereum_account.trx_count = nonce; - - Ok(()) -} diff --git a/evm_loader/program/src/instruction/transaction_cancel.rs b/evm_loader/program/src/instruction/transaction_cancel.rs index 532edbba4..be9038e4f 100644 --- a/evm_loader/program/src/instruction/transaction_cancel.rs +++ b/evm_loader/program/src/instruction/transaction_cancel.rs @@ -1,90 +1,70 @@ -use crate::account::{EthereumAccount, Incinerator, Operator, State}; -use crate::state_account::{BlockedAccounts, Deposit}; +use crate::account::{AccountsDB, BalanceAccount, Operator, StateAccount}; +use crate::error::{Error, Result}; +use crate::gasometer::{CANCEL_TRX_COST, LAST_ITERATION_COST}; use arrayref::array_ref; use ethnum::U256; -use solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, - pubkey::Pubkey, -}; - -struct Accounts<'a> { - storage: State<'a>, - incinerator: Incinerator<'a>, - remaining_accounts: &'a [AccountInfo<'a>], -} +use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; pub fn process<'a>( program_id: &'a Pubkey, accounts: &'a [AccountInfo<'a>], instruction: &[u8], -) -> ProgramResult { +) -> Result<()> { solana_program::msg!("Instruction: Cancel Transaction"); - let storage_info = &accounts[0]; + let storage_info = accounts[0].clone(); let operator = Operator::from_account(&accounts[1])?; - let incinerator = Incinerator::from_account(&accounts[2])?; - let remaining_accounts = &accounts[3..]; + let balance = BalanceAccount::from_account(program_id, accounts[2].clone(), None)?; + + let accounts_database = AccountsDB::new(&accounts[3..], operator, Some(balance), None, None); - let (storage, blocked_accounts) = State::restore( - program_id, - storage_info, - &operator, - remaining_accounts, - true, - )?; + let storage = StateAccount::restore(program_id, storage_info, &accounts_database, true)?; - let accounts = Accounts { - storage, - incinerator, - remaining_accounts, - }; let transaction_hash = array_ref![instruction, 0, 32]; solana_program::log::sol_log_data(&[b"HASH", transaction_hash]); - validate(&accounts, transaction_hash)?; - execute(program_id, accounts, &blocked_accounts) + validate(&storage, transaction_hash)?; + execute(program_id, accounts_database, storage) } -fn validate(accounts: &Accounts, transaction_hash: &[u8; 32]) -> ProgramResult { - let storage = &accounts.storage; - - if &storage.transaction_hash != transaction_hash { - return Err!(ProgramError::InvalidInstructionData; "Invalid transaction hash"); +fn validate(storage: &StateAccount, transaction_hash: &[u8; 32]) -> Result<()> { + if &storage.trx_hash() != transaction_hash { + return Err(Error::HolderInvalidHash( + storage.trx_hash(), + *transaction_hash, + )); } Ok(()) } fn execute<'a>( - program_id: &'a Pubkey, - accounts: Accounts<'a>, - blocked_accounts: &BlockedAccounts, -) -> ProgramResult { + program_id: &Pubkey, + mut accounts: AccountsDB<'a>, + mut storage: StateAccount<'a>, +) -> Result<()> { let used_gas = U256::ZERO; - let total_used_gas = accounts.storage.gas_used; + let total_used_gas = storage.gas_used(); solana_program::log::sol_log_data(&[ b"GAS", &used_gas.to_le_bytes(), &total_used_gas.to_le_bytes(), ]); - for (info, blocked) in accounts.remaining_accounts.iter().zip(blocked_accounts) { - if !blocked.exists { - continue; - } + let gas = U256::from(CANCEL_TRX_COST + LAST_ITERATION_COST); + let _ = storage.consume_gas(gas, accounts.operator_balance()); // ignore error - if let Ok(mut ether_account) = EthereumAccount::from_account(program_id, info) { - ether_account.rw_blocked = false; - if ether_account.address == accounts.storage.caller { - ether_account.trx_count += 1; - } - } - } + let origin = storage.trx_origin(); + let (origin_pubkey, _) = origin.find_balance_address(program_id, storage.trx_chain_id()); - accounts - .storage - .finalize(Deposit::Burn(accounts.incinerator))?; + { + let origin_info = accounts.get(&origin_pubkey).clone(); + let mut account = BalanceAccount::from_account(program_id, origin_info, Some(origin))?; + account.increment_nonce()?; - Ok(()) + storage.refund_unused_gas(&mut account)?; + } + + storage.finalize(program_id, &accounts) } diff --git a/evm_loader/program/src/instruction/transaction_execute.rs b/evm_loader/program/src/instruction/transaction_execute.rs index 3fdd83405..9c27de786 100644 --- a/evm_loader/program/src/instruction/transaction_execute.rs +++ b/evm_loader/program/src/instruction/transaction_execute.rs @@ -1,60 +1,44 @@ -use crate::account::{program, EthereumAccount, Operator, Treasury}; -use crate::account_storage::{AccountsReadiness, ProgramAccountStorage}; -use crate::config::CHAIN_ID; +use solana_program::pubkey::Pubkey; + +use crate::account::{AccountsDB, AllocateResult}; +use crate::account_storage::ProgramAccountStorage; use crate::error::{Error, Result}; use crate::evm::Machine; use crate::executor::ExecutorState; use crate::gasometer::Gasometer; use crate::instruction::transaction_step::log_return_value; use crate::types::{Address, Transaction}; -use ethnum::U256; -use solana_program::account_info::AccountInfo; - -pub struct Accounts<'a> { - pub operator: Operator<'a>, - pub treasury: Treasury<'a>, - pub operator_ether_account: EthereumAccount<'a>, - pub system_program: program::System<'a>, - pub neon_program: program::Neon<'a>, - pub remaining_accounts: &'a [AccountInfo<'a>], - pub all_accounts: &'a [AccountInfo<'a>], -} -pub fn validate( - _accounts: &Accounts, - account_storage: &ProgramAccountStorage, - trx: &Transaction, - _caller_address: &Address, -) -> Result<()> { - if trx.chain_id() != Some(CHAIN_ID.into()) { - return Err(Error::InvalidChainId(trx.chain_id().unwrap_or(U256::ZERO))); - } +pub fn validate(program_id: &Pubkey, accounts: &AccountsDB) -> Result<()> { + for account in accounts { + if account.owner != program_id { + continue; + } - account_storage.check_for_blocked_accounts()?; + if crate::account::is_blocked(program_id, account)? { + return Err(Error::AccountBlocked(*account.key)); + } + } Ok(()) } -pub fn execute<'a>( - accounts: Accounts<'a>, - account_storage: &mut ProgramAccountStorage<'a>, +pub fn execute( + accounts: AccountsDB<'_>, mut gasometer: Gasometer, - trx: &mut Transaction, - caller_address: Address, + trx: Transaction, + origin: Address, ) -> Result<()> { - accounts.system_program.transfer( - &accounts.operator, - &accounts.treasury, - crate::config::PAYMENT_TO_TREASURE, - )?; - + let chain_id = trx.chain_id().unwrap_or(crate::config::DEFAULT_CHAIN_ID); let gas_limit = trx.gas_limit(); let gas_price = trx.gas_price(); + let mut account_storage = ProgramAccountStorage::new(accounts)?; + let (exit_reason, apply_state) = { - let mut backend = ExecutorState::new(account_storage); + let mut backend = ExecutorState::new(&account_storage); - let mut evm = Machine::new(trx, caller_address, &mut backend)?; + let mut evm = Machine::new(trx, origin, &mut backend)?; let (result, _) = evm.execute(u64::MAX, &mut backend)?; let actions = backend.into_actions(); @@ -62,22 +46,15 @@ pub fn execute<'a>( (result, actions) }; - let accounts_readiness = account_storage.apply_state_change( - &accounts.neon_program, - &accounts.system_program, - &accounts.operator, - apply_state, - )?; - - assert_eq!( - accounts_readiness, - AccountsReadiness::Ready, - "Deployment of contract which needs more than 10kb of account space needs several \ - transactions for reallocation and cannot be performed in a single instruction. \ - That's why you have to use iterative transaction for the deployment.", - ); - - gasometer.record_operator_expenses(&accounts.operator); + let allocate_result = account_storage.allocate(&apply_state)?; + if allocate_result != AllocateResult::Ready { + return Err(Error::AccountSpaceAllocationFailure); + } + + account_storage.apply_state_change(apply_state)?; + account_storage.transfer_treasury_payment()?; + + gasometer.record_operator_expenses(account_storage.operator()); let used_gas = gasometer.used_gas(); if used_gas > gas_limit { return Err(Error::OutOfGas(gas_limit, used_gas)); @@ -86,11 +63,7 @@ pub fn execute<'a>( solana_program::log::sol_log_data(&[b"GAS", &used_gas.to_le_bytes(), &used_gas.to_le_bytes()]); let gas_cost = used_gas.saturating_mul(gas_price); - account_storage.transfer_gas_payment( - caller_address, - accounts.operator_ether_account, - gas_cost, - )?; + account_storage.transfer_gas_payment(origin, chain_id, gas_cost)?; log_return_value(&exit_reason); diff --git a/evm_loader/program/src/instruction/transaction_execute_from_account.rs b/evm_loader/program/src/instruction/transaction_execute_from_account.rs index b9fb55277..a1538f887 100644 --- a/evm_loader/program/src/instruction/transaction_execute_from_account.rs +++ b/evm_loader/program/src/instruction/transaction_execute_from_account.rs @@ -1,10 +1,9 @@ -use crate::account::{program, EthereumAccount, Holder, Operator, Treasury}; -use crate::account_storage::ProgramAccountStorage; +use crate::account::{program, AccountsDB, BalanceAccount, Holder, Operator, Treasury}; use crate::error::Result; use crate::gasometer::Gasometer; -use crate::instruction::transaction_execute::Accounts; use crate::types::Transaction; use arrayref::array_ref; +use ethnum::U256; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; /// Execute Ethereum transaction in a single Solana transaction @@ -17,44 +16,34 @@ pub fn process<'a>( let treasury_index = u32::from_le_bytes(*array_ref![instruction, 0, 4]); - let holder = Holder::from_account(program_id, &accounts[0])?; + let holder = Holder::from_account(program_id, accounts[0].clone())?; - let accounts = Accounts { - operator: unsafe { Operator::from_account_not_whitelisted(&accounts[1])? }, - treasury: Treasury::from_account(program_id, treasury_index, &accounts[2])?, - operator_ether_account: EthereumAccount::from_account(program_id, &accounts[3])?, - system_program: program::System::from_account(&accounts[4])?, - neon_program: program::Neon::from_account(program_id, &accounts[5])?, - remaining_accounts: &accounts[6..], - all_accounts: accounts, - }; + let operator = unsafe { Operator::from_account_not_whitelisted(&accounts[1])? }; + let treasury = Treasury::from_account(program_id, treasury_index, &accounts[2])?; + let operator_balance = BalanceAccount::from_account(program_id, accounts[3].clone(), None)?; + let system = program::System::from_account(&accounts[4])?; - holder.validate_owner(&accounts.operator)?; - let mut trx = Transaction::from_rlp(&holder.transaction())?; + holder.validate_owner(&operator)?; + let trx = Transaction::from_rlp(&holder.transaction())?; holder.validate_transaction(&trx)?; - let caller_address = trx.recover_caller_address()?; + let origin = trx.recover_caller_address()?; solana_program::log::sol_log_data(&[b"HASH", &trx.hash()]); - let mut account_storage = ProgramAccountStorage::new( - program_id, - &accounts.operator, - Some(&accounts.system_program), - accounts.remaining_accounts, - )?; + let accounts_db = AccountsDB::new( + &accounts[5..], + operator, + Some(operator_balance), + Some(system), + Some(treasury), + ); - let mut gasometer = Gasometer::new(None, &accounts.operator)?; + let mut gasometer = Gasometer::new(U256::ZERO, accounts_db.operator())?; gasometer.record_solana_transaction_cost(); - gasometer.record_address_lookup_table(accounts.all_accounts); + gasometer.record_address_lookup_table(accounts); gasometer.record_write_to_holder(&trx); - super::transaction_execute::validate(&accounts, &account_storage, &trx, &caller_address)?; - super::transaction_execute::execute( - accounts, - &mut account_storage, - gasometer, - &mut trx, - caller_address, - ) + super::transaction_execute::validate(program_id, &accounts_db)?; + super::transaction_execute::execute(accounts_db, gasometer, trx, origin) } diff --git a/evm_loader/program/src/instruction/transaction_execute_from_instruction.rs b/evm_loader/program/src/instruction/transaction_execute_from_instruction.rs index 2593bebb9..bd2aeb998 100644 --- a/evm_loader/program/src/instruction/transaction_execute_from_instruction.rs +++ b/evm_loader/program/src/instruction/transaction_execute_from_instruction.rs @@ -1,10 +1,9 @@ -use crate::account::{program, EthereumAccount, Operator, Treasury}; -use crate::account_storage::ProgramAccountStorage; +use crate::account::{program, AccountsDB, BalanceAccount, Operator, Treasury}; use crate::error::Result; use crate::gasometer::Gasometer; -use crate::instruction::transaction_execute::Accounts; use crate::types::Transaction; use arrayref::array_ref; +use ethnum::U256; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; /// Execute Ethereum transaction in a single Solana transaction @@ -18,38 +17,28 @@ pub fn process<'a>( let treasury_index = u32::from_le_bytes(*array_ref![instruction, 0, 4]); let messsage = &instruction[4..]; - let accounts = Accounts { - operator: unsafe { Operator::from_account_not_whitelisted(&accounts[0])? }, - treasury: Treasury::from_account(program_id, treasury_index, &accounts[1])?, - operator_ether_account: EthereumAccount::from_account(program_id, &accounts[2])?, - system_program: program::System::from_account(&accounts[3])?, - neon_program: program::Neon::from_account(program_id, &accounts[4])?, - remaining_accounts: &accounts[5..], - all_accounts: accounts, - }; + let operator = unsafe { Operator::from_account_not_whitelisted(&accounts[0])? }; + let treasury = Treasury::from_account(program_id, treasury_index, &accounts[1])?; + let operator_balance = BalanceAccount::from_account(program_id, accounts[2].clone(), None)?; + let system = program::System::from_account(&accounts[3])?; - let mut trx = Transaction::from_rlp(messsage)?; - let caller_address = trx.recover_caller_address()?; + let trx = Transaction::from_rlp(messsage)?; + let origin = trx.recover_caller_address()?; solana_program::log::sol_log_data(&[b"HASH", &trx.hash()]); - let mut account_storage = ProgramAccountStorage::new( - program_id, - &accounts.operator, - Some(&accounts.system_program), - accounts.remaining_accounts, - )?; + let accounts_db = AccountsDB::new( + &accounts[4..], + operator, + Some(operator_balance), + Some(system), + Some(treasury), + ); - let mut gasometer = Gasometer::new(None, &accounts.operator)?; + let mut gasometer = Gasometer::new(U256::ZERO, accounts_db.operator())?; gasometer.record_solana_transaction_cost(); - gasometer.record_address_lookup_table(accounts.all_accounts); - - super::transaction_execute::validate(&accounts, &account_storage, &trx, &caller_address)?; - super::transaction_execute::execute( - accounts, - &mut account_storage, - gasometer, - &mut trx, - caller_address, - ) + gasometer.record_address_lookup_table(accounts); + + super::transaction_execute::validate(program_id, &accounts_db)?; + super::transaction_execute::execute(accounts_db, gasometer, trx, origin) } diff --git a/evm_loader/program/src/instruction/transaction_step.rs b/evm_loader/program/src/instruction/transaction_step.rs index 7b1aa8ef6..c8b20a3af 100644 --- a/evm_loader/program/src/instruction/transaction_step.rs +++ b/evm_loader/program/src/instruction/transaction_step.rs @@ -1,66 +1,54 @@ -use ethnum::U256; -use solana_program::account_info::AccountInfo; - -use crate::account::{program, EthereumAccount, Operator, State, Treasury}; -use crate::account_storage::{AccountsReadiness, ProgramAccountStorage}; -use crate::config::{EVM_STEPS_LAST_ITERATION_MAX, EVM_STEPS_MIN, PAYMENT_TO_TREASURE}; +use crate::account::{AccountsDB, AllocateResult, StateAccount}; +use crate::account_storage::{AccountStorage, ProgramAccountStorage}; +use crate::config::{EVM_STEPS_LAST_ITERATION_MAX, EVM_STEPS_MIN}; use crate::error::{Error, Result}; use crate::evm::{ExitStatus, Machine}; use crate::executor::{Action, ExecutorState}; use crate::gasometer::Gasometer; -use crate::state_account::Deposit; use crate::types::{Address, Transaction}; type EvmBackend<'a, 'r> = ExecutorState<'r, ProgramAccountStorage<'a>>; type Evm<'a, 'r> = Machine>; -pub struct Accounts<'a> { - pub operator: Operator<'a>, - pub treasury: Treasury<'a>, - pub operator_ether_account: EthereumAccount<'a>, - pub system_program: program::System<'a>, - pub neon_program: program::Neon<'a>, - pub remaining_accounts: &'a [AccountInfo<'a>], - pub all_accounts: &'a [AccountInfo<'a>], -} - pub fn do_begin<'a>( - accounts: Accounts<'a>, - mut storage: State<'a>, - account_storage: &mut ProgramAccountStorage<'a>, + accounts: AccountsDB<'a>, + mut storage: StateAccount<'a>, gasometer: Gasometer, - trx: &mut Transaction, - caller: Address, + trx: Transaction, + origin: Address, ) -> Result<()> { debug_print!("do_begin"); - account_storage.check_for_blocked_accounts()?; - account_storage.block_accounts(true); + let accounts = ProgramAccountStorage::new(accounts)?; - let mut backend = ExecutorState::new(account_storage); - let evm = Machine::new(trx, caller, &mut backend)?; + let mut backend = ExecutorState::new(&accounts); + let evm = Machine::new(trx, origin, &mut backend)?; - serialize_evm_state(&mut storage, &backend, &evm)?; + // Burn `gas_limit` tokens from the origin account + // Later we will mint them to the operator + let mut origin_balance = accounts.create_balance_account(origin, storage.trx_chain_id())?; + origin_balance.burn(storage.gas_limit_in_tokens()?)?; - finalize(0, accounts, storage, account_storage, None, gasometer) + serialize_evm_state(&mut storage, &backend, &evm)?; + finalize(0, storage, accounts, None, gasometer) } pub fn do_continue<'a>( step_count: u64, - accounts: Accounts<'a>, - mut storage: State<'a>, - account_storage: &mut ProgramAccountStorage<'a>, + accounts: AccountsDB<'a>, + mut storage: StateAccount<'a>, gasometer: Gasometer, ) -> Result<()> { debug_print!("do_continue"); - if (step_count < EVM_STEPS_MIN) && (storage.gas_price > 0) { + if (step_count < EVM_STEPS_MIN) && (storage.trx_gas_price() > 0) { return Err(Error::Custom(format!( "Step limit {step_count} below minimum {EVM_STEPS_MIN}" ))); } - let (mut backend, mut evm) = deserialize_evm_state(&storage, account_storage)?; + let account_storage = ProgramAccountStorage::new(accounts)?; + let (mut backend, mut evm) = deserialize_evm_state(&storage, &account_storage)?; let (result, steps_executed) = { match backend.exit_status() { @@ -83,60 +71,26 @@ pub fn do_continue<'a>( result => Some((result, backend.into_actions())), }; - finalize( - steps_executed, - accounts, - storage, - account_storage, - results, - gasometer, - ) -} - -fn pay_gas_cost<'a>( - used_gas: U256, - operator_ether_account: EthereumAccount<'a>, - storage: &mut State<'a>, - account_storage: &mut ProgramAccountStorage<'a>, -) -> Result<()> { - debug_print!("pay_gas_cost {}", used_gas); - - // Can overflow in malicious transaction - let value = used_gas.saturating_mul(storage.gas_price); - storage.gas_used = storage.gas_used.saturating_add(used_gas); - - account_storage.transfer_gas_payment(storage.caller, operator_ether_account, value)?; - - Ok(()) + finalize(steps_executed, storage, account_storage, results, gasometer) } fn finalize<'a>( steps_executed: u64, - accounts: Accounts<'a>, - mut storage: State<'a>, - account_storage: &mut ProgramAccountStorage<'a>, + mut storage: StateAccount<'a>, + mut accounts: ProgramAccountStorage<'a>, results: Option<(ExitStatus, Vec)>, mut gasometer: Gasometer, ) -> Result<()> { debug_print!("finalize"); if steps_executed > 0 { - accounts.system_program.transfer( - &accounts.operator, - &accounts.treasury, - PAYMENT_TO_TREASURE, - )?; + accounts.transfer_treasury_payment()?; } - let exit_reason_opt = if let Some((exit_reason, apply_state)) = results { - if account_storage.apply_state_change( - &accounts.neon_program, - &accounts.system_program, - &accounts.operator, - apply_state, - )? == AccountsReadiness::Ready - { - Some(exit_reason) + let status = if let Some((status, actions)) = results { + if accounts.allocate(&actions)? == AllocateResult::Ready { + accounts.apply_state_change(actions)?; + Some(status) } else { None } @@ -144,33 +98,25 @@ fn finalize<'a>( None }; - gasometer.record_operator_expenses(&accounts.operator); - - let total_used_gas = gasometer.used_gas_total(); - let gas_limit = storage.gas_limit; - if total_used_gas > gas_limit { - return Err(Error::OutOfGas(gas_limit, total_used_gas)); - } + gasometer.record_operator_expenses(accounts.operator()); let used_gas = gasometer.used_gas(); + let total_used_gas = gasometer.used_gas_total(); solana_program::log::sol_log_data(&[ b"GAS", &used_gas.to_le_bytes(), &total_used_gas.to_le_bytes(), ]); - pay_gas_cost( - used_gas, - accounts.operator_ether_account, - &mut storage, - account_storage, - )?; + storage.consume_gas(used_gas, accounts.operator_balance())?; - if let Some(exit_reason) = exit_reason_opt { - log_return_value(&exit_reason); + if let Some(status) = status { + log_return_value(&status); - account_storage.block_accounts(false); - storage.finalize(Deposit::ReturnToOperator(accounts.operator))?; + let mut origin = accounts.balance_account(storage.trx_origin(), storage.trx_chain_id())?; + storage.refund_unused_gas(&mut origin)?; + + storage.finalize(accounts.program_id(), accounts.db())?; } Ok(()) @@ -195,9 +141,13 @@ pub fn log_return_value(status: &ExitStatus) { sol_log_data(&[b"RETURN", &[code]]); } -fn serialize_evm_state(state: &mut State, backend: &EvmBackend, machine: &Evm) -> Result<()> { +fn serialize_evm_state( + state: &mut StateAccount, + backend: &EvmBackend, + machine: &Evm, +) -> Result<()> { let (evm_state_len, evm_machine_len) = { - let mut buffer = state.evm_data_mut(); + let mut buffer = state.buffer_mut(); let backend_bytes = backend.serialize_into(&mut buffer)?; let buffer = &mut buffer[backend_bytes..]; @@ -206,22 +156,22 @@ fn serialize_evm_state(state: &mut State, backend: &EvmBackend, machine: &Evm) - (backend_bytes, evm_bytes) }; - state.evm_state_len = evm_state_len; - state.evm_machine_len = evm_machine_len; + state.set_buffer_variables(evm_state_len, evm_machine_len); Ok(()) } fn deserialize_evm_state<'a, 'r>( - state: &State<'a>, + state: &StateAccount<'a>, account_storage: &'r ProgramAccountStorage<'a>, ) -> Result<(EvmBackend<'a, 'r>, Evm<'a, 'r>)> { - let buffer = state.evm_data(); + let (evm_state_len, evm_machine_len) = state.buffer_variables(); + let buffer = state.buffer(); - let executor_state_data = &buffer[..state.evm_state_len]; + let executor_state_data = &buffer[..evm_state_len]; let backend = ExecutorState::deserialize_from(executor_state_data, account_storage)?; - let evm_data = &buffer[state.evm_state_len..][..state.evm_machine_len]; + let evm_data = &buffer[evm_state_len..][..evm_machine_len]; let evm = Machine::deserialize_from(evm_data, &backend)?; Ok((backend, evm)) diff --git a/evm_loader/program/src/instruction/transaction_step_from_account.rs b/evm_loader/program/src/instruction/transaction_step_from_account.rs index 9393cf4da..7872e9eaa 100644 --- a/evm_loader/program/src/instruction/transaction_step_from_account.rs +++ b/evm_loader/program/src/instruction/transaction_step_from_account.rs @@ -1,9 +1,12 @@ -use crate::account::{program, EthereumAccount, FinalizedState, Holder, Operator, State, Treasury}; -use crate::account_storage::ProgramAccountStorage; -use crate::config::{CHAIN_ID, GAS_LIMIT_MULTIPLIER_NO_CHAINID}; +use crate::account::legacy::{TAG_HOLDER_DEPRECATED, TAG_STATE_FINALIZED_DEPRECATED}; +use crate::account::{ + program, AccountsDB, BalanceAccount, Holder, Operator, StateAccount, Treasury, TAG_HOLDER, + TAG_STATE, TAG_STATE_FINALIZED, +}; + use crate::error::{Error, Result}; use crate::gasometer::Gasometer; -use crate::instruction::transaction_step::{do_begin, do_continue, Accounts}; +use crate::instruction::transaction_step::{do_begin, do_continue}; use crate::types::Transaction; use arrayref::array_ref; use ethnum::U256; @@ -16,51 +19,45 @@ pub fn process<'a>( ) -> Result<()> { solana_program::msg!("Instruction: Begin or Continue Transaction from Account"); - let treasury_index = u32::from_le_bytes(*array_ref![instruction, 0, 4]); - let step_count = u64::from(u32::from_le_bytes(*array_ref![instruction, 4, 4])); - - let holder_or_storage_info = &accounts[0]; - - let accounts = Accounts { - operator: Operator::from_account(&accounts[1])?, - treasury: Treasury::from_account(program_id, treasury_index, &accounts[2])?, - operator_ether_account: EthereumAccount::from_account(program_id, &accounts[3])?, - system_program: program::System::from_account(&accounts[4])?, - neon_program: program::Neon::from_account(program_id, &accounts[5])?, - remaining_accounts: &accounts[6..], - all_accounts: accounts, - }; - - let mut account_storage = ProgramAccountStorage::new( - program_id, - &accounts.operator, - Some(&accounts.system_program), - accounts.remaining_accounts, - )?; - - execute( - program_id, - holder_or_storage_info, - accounts, - &mut account_storage, - step_count, - Some(CHAIN_ID.into()), - ) + process_inner(program_id, accounts, instruction, false) } -pub fn execute<'a>( +pub fn process_inner<'a>( program_id: &'a Pubkey, - holder_or_storage_info: &'a AccountInfo<'a>, - accounts: Accounts<'a>, - account_storage: &mut ProgramAccountStorage<'a>, - step_count: u64, - expected_chain_id: Option, + accounts: &'a [AccountInfo<'a>], + instruction: &[u8], + increase_gas_limit: bool, ) -> Result<()> { - match crate::account::tag(program_id, holder_or_storage_info)? { - Holder::TAG => { - let mut trx = { - let holder = Holder::from_account(program_id, holder_or_storage_info)?; - holder.validate_owner(&accounts.operator)?; + let treasury_index = u32::from_le_bytes(*array_ref![instruction, 0, 4]); + let step_count = u64::from(u32::from_le_bytes(*array_ref![instruction, 4, 4])); + + let holder_or_storage = &accounts[0]; + + let operator = Operator::from_account(&accounts[1])?; + let treasury = Treasury::from_account(program_id, treasury_index, &accounts[2])?; + let operator_balance = BalanceAccount::from_account(program_id, accounts[3].clone(), None)?; + let system = program::System::from_account(&accounts[4])?; + + let accounts_db = AccountsDB::new( + &accounts[5..], + operator.clone(), + Some(operator_balance), + Some(system), + Some(treasury), + ); + + let mut excessive_lamports = 0_u64; + + let mut tag = crate::account::tag(program_id, &holder_or_storage)?; + if (tag == TAG_HOLDER_DEPRECATED) || (tag == TAG_STATE_FINALIZED_DEPRECATED) { + tag = crate::account::legacy::update_holder_account(&holder_or_storage)?; + } + + match tag { + TAG_HOLDER | TAG_HOLDER_DEPRECATED => { + let trx = { + let holder = Holder::from_account(program_id, holder_or_storage.clone())?; + holder.validate_owner(accounts_db.operator())?; let message = holder.transaction(); let trx = Transaction::from_rlp(&message)?; @@ -70,56 +67,48 @@ pub fn execute<'a>( trx }; - if trx.chain_id() != expected_chain_id { - return Err(Error::InvalidChainId(trx.chain_id().unwrap_or(U256::ZERO))); - } - - solana_program::log::sol_log_data(&[b"HASH", &trx.hash()]); + solana_program::log::sol_log_data(&[b"HASH", &trx.hash]); + let origin = trx.recover_caller_address()?; - let caller = trx.recover_caller_address()?; - let mut storage = - State::new(program_id, holder_or_storage_info, &accounts, caller, &trx)?; - - if expected_chain_id.is_none() { - let gas_multiplier = U256::from(GAS_LIMIT_MULTIPLIER_NO_CHAINID); - storage.gas_limit = storage.gas_limit.saturating_mul(gas_multiplier); - } - - let mut gasometer = Gasometer::new(None, &accounts.operator)?; + let mut gasometer = Gasometer::new(U256::ZERO, accounts_db.operator())?; gasometer.record_solana_transaction_cost(); - gasometer.record_address_lookup_table(accounts.all_accounts); - gasometer.record_iterative_overhead(); + gasometer.record_address_lookup_table(accounts); gasometer.record_write_to_holder(&trx); - do_begin( - accounts, - storage, - account_storage, - gasometer, - &mut trx, - caller, - ) - } - State::TAG => { - let (storage, _blocked_accounts) = State::restore( + excessive_lamports += crate::account::legacy::update_legacy_accounts(&accounts_db)?; + gasometer.refund_lamports(excessive_lamports); + + let mut storage = StateAccount::new( program_id, - holder_or_storage_info, - &accounts.operator, - accounts.remaining_accounts, - false, + holder_or_storage.clone(), + &accounts_db, + origin, + &trx, )?; - solana_program::log::sol_log_data(&[b"HASH", &storage.transaction_hash]); + if increase_gas_limit { + assert!(trx.chain_id().is_none()); + storage.use_gas_limit_multiplier(); + } + + do_begin(accounts_db, storage, gasometer, trx, origin) + } + TAG_STATE => { + let storage = + StateAccount::restore(program_id, holder_or_storage.clone(), &accounts_db, false)?; + + solana_program::log::sol_log_data(&[b"HASH", &storage.trx_hash()]); - let mut gasometer = Gasometer::new(Some(storage.gas_used), &accounts.operator)?; + let mut gasometer = Gasometer::new(storage.gas_used(), accounts_db.operator())?; gasometer.record_solana_transaction_cost(); - do_continue(step_count, accounts, storage, account_storage, gasometer) + do_continue(step_count, accounts_db, storage, gasometer) } - FinalizedState::TAG => Err(Error::StorageAccountFinalized), - _ => Err(Error::AccountInvalidTag( - *holder_or_storage_info.key, - Holder::TAG, - )), - } + TAG_STATE_FINALIZED | TAG_STATE_FINALIZED_DEPRECATED => Err(Error::StorageAccountFinalized), + _ => Err(Error::AccountInvalidTag(*holder_or_storage.key, TAG_HOLDER)), + }?; + + **operator.try_borrow_mut_lamports()? += excessive_lamports; + + Ok(()) } diff --git a/evm_loader/program/src/instruction/transaction_step_from_account_no_chainid.rs b/evm_loader/program/src/instruction/transaction_step_from_account_no_chainid.rs index 392779c4b..041ac6b42 100644 --- a/evm_loader/program/src/instruction/transaction_step_from_account_no_chainid.rs +++ b/evm_loader/program/src/instruction/transaction_step_from_account_no_chainid.rs @@ -1,8 +1,4 @@ -use crate::account::{program, EthereumAccount, Operator, Treasury}; -use crate::account_storage::ProgramAccountStorage; use crate::error::Result; -use crate::instruction::transaction_step::Accounts; -use arrayref::array_ref; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; pub fn process<'a>( @@ -12,34 +8,5 @@ pub fn process<'a>( ) -> Result<()> { solana_program::msg!("Instruction: Begin or Continue Transaction from Account Without ChainId"); - let treasury_index = u32::from_le_bytes(*array_ref![instruction, 0, 4]); - let step_count = u64::from(u32::from_le_bytes(*array_ref![instruction, 4, 4])); - - let holder_or_storage_info = &accounts[0]; - - let accounts = Accounts { - operator: Operator::from_account(&accounts[1])?, - treasury: Treasury::from_account(program_id, treasury_index, &accounts[2])?, - operator_ether_account: EthereumAccount::from_account(program_id, &accounts[3])?, - system_program: program::System::from_account(&accounts[4])?, - neon_program: program::Neon::from_account(program_id, &accounts[5])?, - remaining_accounts: &accounts[6..], - all_accounts: accounts, - }; - - let mut account_storage = ProgramAccountStorage::new( - program_id, - &accounts.operator, - Some(&accounts.system_program), - accounts.remaining_accounts, - )?; - - super::transaction_step_from_account::execute( - program_id, - holder_or_storage_info, - accounts, - &mut account_storage, - step_count, - None, - ) + super::transaction_step_from_account::process_inner(program_id, accounts, instruction, true) } diff --git a/evm_loader/program/src/instruction/transaction_step_from_instruction.rs b/evm_loader/program/src/instruction/transaction_step_from_instruction.rs index dfcee2ae1..3cdf97f70 100644 --- a/evm_loader/program/src/instruction/transaction_step_from_instruction.rs +++ b/evm_loader/program/src/instruction/transaction_step_from_instruction.rs @@ -1,10 +1,14 @@ -use crate::account::{program, EthereumAccount, FinalizedState, Holder, Operator, State, Treasury}; -use crate::account_storage::ProgramAccountStorage; +use crate::account::legacy::{TAG_HOLDER_DEPRECATED, TAG_STATE_FINALIZED_DEPRECATED}; +use crate::account::{ + program, AccountsDB, BalanceAccount, Operator, StateAccount, Treasury, TAG_HOLDER, TAG_STATE, + TAG_STATE_FINALIZED, +}; use crate::error::{Error, Result}; use crate::gasometer::Gasometer; -use crate::instruction::transaction_step::{do_begin, do_continue, Accounts}; +use crate::instruction::transaction_step::{do_begin, do_continue}; use crate::types::Transaction; use arrayref::array_ref; +use ethnum::U256; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; pub fn process<'a>( @@ -19,69 +23,59 @@ pub fn process<'a>( // skip let unique_index = u32::from_le_bytes(*array_ref![instruction, 8, 4]); let message = &instruction[4 + 4 + 4..]; - let storage_info = &accounts[0]; - - let accounts = Accounts { - operator: Operator::from_account(&accounts[1])?, - treasury: Treasury::from_account(program_id, treasury_index, &accounts[2])?, - operator_ether_account: EthereumAccount::from_account(program_id, &accounts[3])?, - system_program: program::System::from_account(&accounts[4])?, - neon_program: program::Neon::from_account(program_id, &accounts[5])?, - remaining_accounts: &accounts[6..], - all_accounts: accounts, - }; - - let mut account_storage = ProgramAccountStorage::new( - program_id, - &accounts.operator, - Some(&accounts.system_program), - accounts.remaining_accounts, - )?; - - match crate::account::tag(program_id, storage_info)? { - Holder::TAG | FinalizedState::TAG => { - let mut trx = Transaction::from_rlp(message)?; - let caller = trx.recover_caller_address()?; + let storage_info = accounts[0].clone(); - solana_program::log::sol_log_data(&[b"HASH", &trx.hash()]); + let operator = Operator::from_account(&accounts[1])?; + let treasury = Treasury::from_account(program_id, treasury_index, &accounts[2])?; + let operator_balance = BalanceAccount::from_account(program_id, accounts[3].clone(), None)?; + let system = program::System::from_account(&accounts[4])?; + + let accounts_db = AccountsDB::new( + &accounts[5..], + operator.clone(), + Some(operator_balance), + Some(system), + Some(treasury), + ); - let storage = State::new(program_id, storage_info, &accounts, caller, &trx)?; + let mut excessive_lamports = 0_u64; + + let mut tag = crate::account::tag(program_id, &storage_info)?; + if (tag == TAG_HOLDER_DEPRECATED) || (tag == TAG_STATE_FINALIZED_DEPRECATED) { + tag = crate::account::legacy::update_holder_account(&storage_info)?; + } + + match tag { + TAG_HOLDER | TAG_STATE_FINALIZED => { + let trx = Transaction::from_rlp(message)?; + let origin = trx.recover_caller_address()?; + + solana_program::log::sol_log_data(&[b"HASH", &trx.hash()]); - let mut gasometer = Gasometer::new(None, &accounts.operator)?; + let mut gasometer = Gasometer::new(U256::ZERO, accounts_db.operator())?; gasometer.record_solana_transaction_cost(); - gasometer.record_address_lookup_table(accounts.all_accounts); - gasometer.record_iterative_overhead(); - - do_begin( - accounts, - storage, - &mut account_storage, - gasometer, - &mut trx, - caller, - ) + gasometer.record_address_lookup_table(accounts); + + excessive_lamports += crate::account::legacy::update_legacy_accounts(&accounts_db)?; + gasometer.refund_lamports(excessive_lamports); + + let storage = StateAccount::new(program_id, storage_info, &accounts_db, origin, &trx)?; + + do_begin(accounts_db, storage, gasometer, trx, origin) } - State::TAG => { - let (storage, _blocked_accounts) = State::restore( - program_id, - storage_info, - &accounts.operator, - accounts.remaining_accounts, - false, - )?; - solana_program::log::sol_log_data(&[b"HASH", &storage.transaction_hash]); - - let mut gasometer = Gasometer::new(Some(storage.gas_used), &accounts.operator)?; + TAG_STATE => { + let storage = StateAccount::restore(program_id, storage_info, &accounts_db, false)?; + solana_program::log::sol_log_data(&[b"HASH", &storage.trx_hash()]); + + let mut gasometer = Gasometer::new(storage.gas_used(), accounts_db.operator())?; gasometer.record_solana_transaction_cost(); - do_continue( - step_count, - accounts, - storage, - &mut account_storage, - gasometer, - ) + do_continue(step_count, accounts_db, storage, gasometer) } - _ => Err(Error::AccountInvalidTag(*storage_info.key, Holder::TAG)), - } + _ => Err(Error::AccountInvalidTag(*storage_info.key, TAG_HOLDER)), + }?; + + **operator.try_borrow_mut_lamports()? += excessive_lamports; + + Ok(()) } From 0fdd66e18117bce46d429ab8b6ca8b265f1007a5 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Tue, 14 Nov 2023 18:14:02 +0300 Subject: [PATCH 053/318] [Multi Tokens] Misc changes in EVM --- evm_loader/program/src/error.rs | 76 +++++++++++-------- .../executor/precompile_extension/metaplex.rs | 9 +-- .../precompile_extension/neon_token.rs | 36 ++++++--- .../precompile_extension/spl_token.rs | 29 +++---- evm_loader/program/src/lib.rs | 3 +- evm_loader/program/src/types/address.rs | 9 +++ evm_loader/program/src/types/transaction.rs | 49 ++++++------ 7 files changed, 127 insertions(+), 84 deletions(-) diff --git a/evm_loader/program/src/error.rs b/evm_loader/program/src/error.rs index 40631225e..e824095b0 100644 --- a/evm_loader/program/src/error.rs +++ b/evm_loader/program/src/error.rs @@ -1,11 +1,13 @@ //! Error types #![allow(clippy::use_self)] -use std::{array::TryFromSliceError, num::TryFromIntError}; +use std::{array::TryFromSliceError, num::TryFromIntError, str::Utf8Error}; use ethnum::U256; use solana_program::{ - program_error::ProgramError, pubkey::Pubkey, secp256k1_recover::Secp256k1RecoverError, + program_error::ProgramError, + pubkey::{Pubkey, PubkeyError}, + secp256k1_recover::Secp256k1RecoverError, }; use thiserror::Error; @@ -20,6 +22,9 @@ pub enum Error { #[error("Solana Program Error: {0}")] ProgramError(#[from] ProgramError), + #[error("Solana Pubkey Error: {0}")] + PubkeyError(#[from] PubkeyError), + #[error("RLP error: {0}")] RlpError(#[from] rlp::DecoderError), @@ -38,11 +43,17 @@ pub enum Error { #[error("TryFromSliceError error: {0}")] TryFromSliceError(#[from] TryFromSliceError), + #[error("Utf8Error error: {0}")] + Utf8Error(#[from] Utf8Error), + #[error("Account {0} - not found")] - AccountMissing(Address), + AccountMissing(Pubkey), - #[error("Account {0} - blocked")] - AccountBlocked(Address), + #[error("Account {0} - blocked, trying to execute transaction on rw locked account")] + AccountBlocked(Pubkey), + + #[error("Account {0} - was empty, created by another transaction")] + AccountCreatedByAnotherTransaction(Pubkey), #[error("Account {0} - invalid tag, expected {1}")] AccountInvalidTag(Pubkey, u8), @@ -74,18 +85,24 @@ pub enum Error { #[error("Storage Account is uninitialized")] StorageAccountUninitialized, - #[error("Storage Account is finalized")] + #[error("Transaction already finalized")] StorageAccountFinalized, #[error("Unknown extension method selector {1:?}, contract {0}")] UnknownPrecompileMethodSelector(Address, [u8; 4]), - #[error("Insufficient balance for transfer, account = {0}, required = {1}")] - InsufficientBalance(Address, U256), + #[error("Insufficient balance for transfer, account = {0}, chain = {1}, required = {2}")] + InsufficientBalance(Address, u64, U256), + + #[error("Invalid token for transfer, account = {0}, chain = {1}")] + InvalidTransferToken(Address, u64), #[error("Out of Gas, limit = {0}, required = {1}")] OutOfGas(U256, U256), + #[error("Invalid gas balance account")] + GasReceiverInvalidChainId, + #[error("EVM Stack Overflow")] StackOverflow, @@ -113,14 +130,14 @@ pub enum Error { #[error("EVM encountered unknown opcode, contract = {0}, opcode = {1:X}")] UnknownOpcode(Address, u8), - #[error("Account {0} nonce overflow")] + #[error("Account {0} - nonce overflow")] NonceOverflow(Address), #[error("Invalid Nonce, origin {0} nonce {1} != Transaction nonce {2}")] InvalidTransactionNonce(Address, u64, u64), #[error("Invalid Chain ID {0}")] - InvalidChainId(U256), + InvalidChainId(u64), #[error("Attempt to deploy to existing account {0}, caller = {1}")] DeployToExistingAccount(Address, Address), @@ -143,8 +160,18 @@ pub enum Error { #[error("Holder Account - invalid owner {0}, expected = {1}")] HolderInvalidOwner(Pubkey, Pubkey), + #[error("Holder Account - insufficient size {0}, required = {1}")] + HolderInsufficientSize(usize, usize), + #[error("Holder Account - invalid transaction hash {}, expected = {}", hex::encode(.0), hex::encode(.1))] HolderInvalidHash([u8; 32], [u8; 32]), + + #[error( + "Deployment of contract which needs more than 10kb of account space needs several \ + transactions for reallocation and cannot be performed in a single instruction. \ + That's why you have to use iterative transaction for the deployment." + )] + AccountSpaceAllocationFailure, } pub type Result = std::result::Result; @@ -165,6 +192,12 @@ impl From<&'static str> for Error { } } +impl From for Error { + fn from(value: String) -> Self { + Self::Custom(value) + } +} + /// Macro to log a `ProgramError` in the current transaction log /// with the source file position like: file.rc:42 /// and additional info if needed @@ -188,29 +221,6 @@ macro_rules! Err { }); } -/// Macro to log a `ProgramError` in the current transaction log. -/// with the source file position like: file.rc:777 -/// and additional info if needed -/// See `https://github.com/neonlabsorg/neon-evm/issues/159` -/// -/// # Examples -/// -/// ```ignore -/// # map_err(|s| E!(ProgramError::InvalidArgument; "s={:?}", s)) -/// ``` -/// -macro_rules! E { - ( $n:expr; $($args:expr),* ) => ({ - #[cfg(target_os = "solana")] - solana_program::msg!("{}:{} : {}", file!(), line!(), &format!($($args),*)); - - #[cfg(all(not(target_os = "solana"), feature = "log"))] - log::error!("{}", &format!($($args),*)); - - $n - }); -} - #[must_use] fn format_revert_error(msg: &[u8]) -> Option<&str> { if msg.starts_with(&[0x08, 0xc3, 0x79, 0xa0]) { diff --git a/evm_loader/program/src/executor/precompile_extension/metaplex.rs b/evm_loader/program/src/executor/precompile_extension/metaplex.rs index 180cfed6d..b0fc2626d 100644 --- a/evm_loader/program/src/executor/precompile_extension/metaplex.rs +++ b/evm_loader/program/src/executor/precompile_extension/metaplex.rs @@ -1,5 +1,4 @@ #![allow(clippy::unnecessary_wraps)] - use std::convert::{Into, TryInto}; use ethnum::U256; @@ -153,7 +152,7 @@ fn create_metadata( uri: String, ) -> Result> { let signer = context.caller; - let (signer_pubkey, bump_seed) = state.backend.solana_address(&signer); + let (signer_pubkey, bump_seed) = state.backend.contract_pubkey(signer); let seeds = vec![ vec![ACCOUNT_SEED_VERSION], @@ -168,7 +167,7 @@ fn create_metadata( metadata_pubkey, mint, signer_pubkey, - *state.backend.operator(), + state.backend.operator(), signer_pubkey, name, symbol, @@ -208,7 +207,7 @@ fn create_master_edition( max_supply: Option, ) -> Result> { let signer = context.caller; - let (signer_pubkey, bump_seed) = state.backend.solana_address(&signer); + let (signer_pubkey, bump_seed) = state.backend.contract_pubkey(signer); let seeds = vec![ vec![ACCOUNT_SEED_VERSION], @@ -226,7 +225,7 @@ fn create_master_edition( signer_pubkey, signer_pubkey, metadata_pubkey, - *state.backend.operator(), + state.backend.operator(), max_supply, ); diff --git a/evm_loader/program/src/executor/precompile_extension/neon_token.rs b/evm_loader/program/src/executor/precompile_extension/neon_token.rs index 4247acd0c..d1bafe6b5 100644 --- a/evm_loader/program/src/executor/precompile_extension/neon_token.rs +++ b/evm_loader/program/src/executor/precompile_extension/neon_token.rs @@ -3,10 +3,13 @@ use std::convert::TryInto; use arrayref::array_ref; use ethnum::U256; use maybe_async::maybe_async; -use solana_program::{program_pack::Pack, pubkey::Pubkey, rent::Rent, sysvar::Sysvar}; +use solana_program::{ + account_info::IntoAccountInfo, program_pack::Pack, pubkey::Pubkey, rent::Rent, sysvar::Sysvar, +}; use spl_associated_token_account::get_associated_token_address; use crate::{ + account::token, account_storage::AccountStorage, error::{Error, Result}, executor::ExecutorState, @@ -44,11 +47,13 @@ pub async fn neon_token( } let source = context.contract; + let chain_id = context.contract_chain_id; + let value = context.value; // owner of the associated token account let destination = array_ref![rest, 0, 32]; let destination = Pubkey::new_from_array(*destination); - withdraw(state, source, destination, context.value).await?; + withdraw(state, source, chain_id, destination, value).await?; let mut output = vec![0_u8; 32]; output[31] = 1; // return true @@ -64,6 +69,7 @@ pub async fn neon_token( async fn withdraw( state: &mut ExecutorState<'_, B>, source: Address, + chain_id: u64, target: Pubkey, value: U256, ) -> Result<()> { @@ -71,7 +77,17 @@ async fn withdraw( return Err(Error::Custom("Neon Withdraw: value == 0".to_string())); } - let additional_decimals: u32 = (18 - crate::config::token_mint::decimals()).into(); + let mint_address = state.backend.chain_id_to_token(chain_id); + + let mut mint_account = state.external_account(mint_address).await?; + let mint_data = { + let info = mint_account.into_account_info(); + token::Mint::from_account(&info)?.into_data() + }; + + assert!(mint_data.decimals < 18); + + let additional_decimals: u32 = (18 - mint_data.decimals).into(); let min_amount: u128 = u128::pow(10, additional_decimals); let spl_amount = value / min_amount; @@ -89,15 +105,15 @@ async fn withdraw( ))); } - let target_token = get_associated_token_address(&target, state.backend.neon_token_mint()); + let target_token = get_associated_token_address(&target, &mint_address); let account = state.external_account(target_token).await?; if !spl_token::check_id(&account.owner) { use spl_associated_token_account::instruction::create_associated_token_account; let create_associated = create_associated_token_account( - state.backend.operator(), + &state.backend.operator(), &target, - state.backend.neon_token_mint(), + &mint_address, &spl_token::ID, ); @@ -108,22 +124,22 @@ async fn withdraw( let (authority, bump_seed) = Pubkey::find_program_address(&[b"Deposit"], state.backend.program_id()); - let pool = get_associated_token_address(&authority, state.backend.neon_token_mint()); + let pool = get_associated_token_address(&authority, &mint_address); let transfer = spl_token::instruction::transfer_checked( &spl_token::ID, &pool, - state.backend.neon_token_mint(), + &mint_address, &target_token, &authority, &[], spl_amount.as_u64(), - crate::config::token_mint::decimals(), + mint_data.decimals, )?; let transfer_seeds = vec![b"Deposit".to_vec(), vec![bump_seed]]; state.queue_external_instruction(transfer, transfer_seeds, 0); - state.withdraw_neons(source, value); + state.burn(source, chain_id, value); Ok(()) } diff --git a/evm_loader/program/src/executor/precompile_extension/spl_token.rs b/evm_loader/program/src/executor/precompile_extension/spl_token.rs index 7d3502b33..86348d42c 100644 --- a/evm_loader/program/src/executor/precompile_extension/spl_token.rs +++ b/evm_loader/program/src/executor/precompile_extension/spl_token.rs @@ -270,8 +270,11 @@ fn create_account( let required_lamports = minimum_balance.saturating_sub(account.lamports); if required_lamports > 0 { - let transfer = - system_instruction::transfer(state.backend.operator(), &account.key, required_lamports); + let transfer = system_instruction::transfer( + &state.backend.operator(), + &account.key, + required_lamports, + ); state.queue_external_instruction(transfer, vec![], required_lamports); } @@ -294,7 +297,7 @@ async fn initialize_mint( freeze_authority: Option, ) -> Result> { let signer = context.caller; - let (signer_pubkey, _) = state.backend.solana_address(&signer); + let (signer_pubkey, _) = state.backend.contract_pubkey(signer); let (mint_key, bump_seed) = Pubkey::find_program_address( &[ @@ -342,7 +345,7 @@ async fn initialize_account( owner: Option, ) -> Result> { let signer = context.caller; - let (signer_pubkey, _) = state.backend.solana_address(&signer); + let (signer_pubkey, _) = state.backend.contract_pubkey(signer); let (account_key, bump_seed) = Pubkey::find_program_address( &[ @@ -386,7 +389,7 @@ fn close_account( account: Pubkey, ) -> Result> { let signer = context.caller; - let (signer_pubkey, bump_seed) = state.backend.solana_address(&signer); + let (signer_pubkey, bump_seed) = state.backend.contract_pubkey(signer); let seeds = vec![ vec![ACCOUNT_SEED_VERSION], @@ -397,7 +400,7 @@ fn close_account( let close_account = spl_token::instruction::close_account( &spl_token::ID, &account, - state.backend.operator(), + &state.backend.operator(), &signer_pubkey, &[], )?; @@ -414,7 +417,7 @@ fn approve( amount: u64, ) -> Result> { let signer = context.caller; - let (signer_pubkey, bump_seed) = state.backend.solana_address(&signer); + let (signer_pubkey, bump_seed) = state.backend.contract_pubkey(signer); let seeds = vec![ vec![ACCOUNT_SEED_VERSION], @@ -441,7 +444,7 @@ fn revoke( account: Pubkey, ) -> Result> { let signer = context.caller; - let (signer_pubkey, bump_seed) = state.backend.solana_address(&signer); + let (signer_pubkey, bump_seed) = state.backend.contract_pubkey(signer); let seeds = vec![ vec![ACCOUNT_SEED_VERSION], @@ -463,7 +466,7 @@ fn transfer( amount: u64, ) -> Result> { let signer = context.caller; - let (signer_pubkey, bump_seed) = state.backend.solana_address(&signer); + let (signer_pubkey, bump_seed) = state.backend.contract_pubkey(signer); let seeds = vec![ vec![ACCOUNT_SEED_VERSION], @@ -530,7 +533,7 @@ fn mint_to( amount: u64, ) -> Result> { let signer = context.caller; - let (signer_pubkey, bump_seed) = state.backend.solana_address(&signer); + let (signer_pubkey, bump_seed) = state.backend.contract_pubkey(signer); let seeds = vec![ vec![ACCOUNT_SEED_VERSION], @@ -559,7 +562,7 @@ fn burn( amount: u64, ) -> Result> { let signer = context.caller; - let (signer_pubkey, bump_seed) = state.backend.solana_address(&signer); + let (signer_pubkey, bump_seed) = state.backend.contract_pubkey(signer); let seeds = vec![ vec![ACCOUNT_SEED_VERSION], @@ -588,7 +591,7 @@ fn freeze( target: Pubkey, ) -> Result> { let signer = context.caller; - let (signer_pubkey, bump_seed) = state.backend.solana_address(&signer); + let (signer_pubkey, bump_seed) = state.backend.contract_pubkey(signer); let seeds = vec![ vec![ACCOUNT_SEED_VERSION], @@ -615,7 +618,7 @@ fn thaw( target: Pubkey, ) -> Result> { let signer = context.caller; - let (signer_pubkey, bump_seed) = state.backend.solana_address(&signer); + let (signer_pubkey, bump_seed) = state.backend.contract_pubkey(signer); let seeds = vec![ vec![ACCOUNT_SEED_VERSION], diff --git a/evm_loader/program/src/lib.rs b/evm_loader/program/src/lib.rs index 005757f81..5bb10e2a8 100644 --- a/evm_loader/program/src/lib.rs +++ b/evm_loader/program/src/lib.rs @@ -11,6 +11,8 @@ )] #![allow(missing_docs, clippy::missing_panics_doc, clippy::missing_errors_doc)] +solana_program::declare_id!(crate::config::PROGRAM_ID); + mod allocator; #[macro_use] mod debug; @@ -27,7 +29,6 @@ pub mod external_programs; pub mod gasometer; #[cfg(target_os = "solana")] pub mod instruction; -pub mod state_account; pub mod types; // Export current solana-sdk types for downstream users who may also be building with a different diff --git a/evm_loader/program/src/types/address.rs b/evm_loader/program/src/types/address.rs index 34aab8dfa..8d16b5c0c 100644 --- a/evm_loader/program/src/types/address.rs +++ b/evm_loader/program/src/types/address.rs @@ -1,3 +1,4 @@ +use ethnum::U256; use hex::FromHex; use serde::{Deserialize, Serialize}; use solana_program::pubkey::Pubkey; @@ -57,6 +58,14 @@ impl Address { let seeds: &[&[u8]] = &[&[ACCOUNT_SEED_VERSION], &self.0]; Pubkey::find_program_address(seeds, program_id) } + + #[must_use] + pub fn find_balance_address(&self, program_id: &Pubkey, chain_id: u64) -> (Pubkey, u8) { + let chain_id = U256::from(chain_id); + + let seeds: &[&[u8]] = &[&[ACCOUNT_SEED_VERSION], &self.0, &chain_id.to_be_bytes()]; + Pubkey::find_program_address(seeds, program_id) + } } impl FromStr for Address { diff --git a/evm_loader/program/src/types/transaction.rs b/evm_loader/program/src/types/transaction.rs index b6d1e202f..bae39cf34 100644 --- a/evm_loader/program/src/types/transaction.rs +++ b/evm_loader/program/src/types/transaction.rs @@ -20,12 +20,11 @@ impl rlp::Decodable for StorageKey { } } -#[cfg(not(target_os = "solana"))] -impl TryFrom for StorageKey { +impl TryFrom> for StorageKey { type Error = String; - fn try_from(hex: crate::types::hexbytes::HexBytes) -> Result { - let bytes = hex.0; + fn try_from(hex: Vec) -> Result { + let bytes = hex; if bytes.len() != 32 { return Err(String::from("Hex string must be 32 bytes")); @@ -38,6 +37,12 @@ impl TryFrom for StorageKey { } } +impl AsRef<[u8]> for StorageKey { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + #[derive(Debug, Clone)] pub enum TransactionEnvelope { Legacy, @@ -62,14 +67,14 @@ impl TransactionEnvelope { } } -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct LegacyTx { pub nonce: u64, pub gas_price: U256, pub gas_limit: U256, pub target: Option
, pub value: U256, - pub call_data: crate::evm::Buffer, + pub call_data: Vec, pub v: U256, pub r: U256, pub s: U256, @@ -104,7 +109,7 @@ impl rlp::Decodable for LegacyTx { } }; let value: U256 = u256(&rlp.at(4)?)?; - let call_data = crate::evm::Buffer::from_slice(rlp.at(5)?.data()?); + let call_data = rlp.val_at(5)?; let v: U256 = u256(&rlp.at(6)?)?; let r: U256 = u256(&rlp.at(7)?)?; let s: U256 = u256(&rlp.at(8)?)?; @@ -143,14 +148,14 @@ impl rlp::Decodable for LegacyTx { } } -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct AccessListTx { pub nonce: u64, pub gas_price: U256, pub gas_limit: U256, pub target: Option
, pub value: U256, - pub call_data: crate::evm::Buffer, + pub call_data: Vec, pub r: U256, pub s: U256, pub chain_id: U256, @@ -187,7 +192,7 @@ impl rlp::Decodable for AccessListTx { }; let value: U256 = u256(&rlp.at(5)?)?; - let call_data = crate::evm::Buffer::from_slice(rlp.at(6)?.data()?); + let call_data = rlp.val_at(6)?; let rlp_access_list = rlp.at(7)?; let mut access_list = vec![]; @@ -240,13 +245,13 @@ impl rlp::Decodable for AccessListTx { // TODO: Will be added as a part of EIP-1559 // struct DynamicFeeTx {} -#[derive(Debug, Clone)] +#[derive(Debug)] pub enum TransactionPayload { Legacy(LegacyTx), AccessList(AccessListTx), } -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct Transaction { pub transaction: TransactionPayload, pub byte_len: usize, @@ -503,23 +508,20 @@ impl Transaction { } #[must_use] - pub fn call_data(&self) -> &crate::evm::Buffer { + pub fn call_data(&self) -> &[u8] { match &self.transaction { TransactionPayload::Legacy(LegacyTx { call_data, .. }) | TransactionPayload::AccessList(AccessListTx { call_data, .. }) => call_data, } } - // Mem replace for call_data to avoid cloning it #[must_use] - pub fn extract_call_data(&mut self) -> crate::evm::Buffer { + pub fn into_call_data(self) -> crate::evm::Buffer { match self.transaction { - TransactionPayload::Legacy(LegacyTx { - ref mut call_data, .. - }) - | TransactionPayload::AccessList(AccessListTx { - ref mut call_data, .. - }) => std::mem::take(call_data), + TransactionPayload::Legacy(LegacyTx { call_data, .. }) + | TransactionPayload::AccessList(AccessListTx { call_data, .. }) => { + crate::evm::Buffer::from_vec(call_data) + } } } @@ -540,11 +542,14 @@ impl Transaction { } #[must_use] - pub fn chain_id(&self) -> Option { + pub fn chain_id(&self) -> Option { match self.transaction { TransactionPayload::Legacy(LegacyTx { chain_id, .. }) => chain_id, TransactionPayload::AccessList(AccessListTx { chain_id, .. }) => Some(chain_id), } + .map(std::convert::TryInto::try_into) + .transpose() + .expect("chain_id < u64::max") } #[must_use] From eea0da527b82b0b20b0a458ae50b39df08fdae91 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Tue, 14 Nov 2023 18:16:55 +0300 Subject: [PATCH 054/318] [Multi Tokens] NeonAPI commands --- .../handlers/get_ether_account_data.rs | 33 -- evm_loader/lib/src/commands/cancel_trx.rs | 34 +- .../lib/src/commands/collect_treasury.rs | 7 +- .../lib/src/commands/create_ether_account.rs | 62 ---- evm_loader/lib/src/commands/deposit.rs | 117 ------- evm_loader/lib/src/commands/emulate.rs | 328 +++++------------- evm_loader/lib/src/commands/get_balance.rs | 122 +++++++ evm_loader/lib/src/commands/get_contract.rs | 98 ++++++ .../src/commands/get_ether_account_data.rs | 70 ---- evm_loader/lib/src/commands/get_holder.rs | 154 ++++++++ evm_loader/lib/src/commands/get_storage_at.rs | 77 +--- .../lib/src/commands/init_environment.rs | 57 +-- evm_loader/lib/src/commands/mod.rs | 7 +- evm_loader/lib/src/commands/trace.rs | 60 ++-- evm_loader/program/src/evm/tracing/mod.rs | 31 +- .../src/evm/tracing/tracers/struct_logger.rs | 25 +- 16 files changed, 564 insertions(+), 718 deletions(-) delete mode 100644 evm_loader/api/src/api_server/handlers/get_ether_account_data.rs delete mode 100644 evm_loader/lib/src/commands/create_ether_account.rs delete mode 100644 evm_loader/lib/src/commands/deposit.rs create mode 100644 evm_loader/lib/src/commands/get_balance.rs create mode 100644 evm_loader/lib/src/commands/get_contract.rs delete mode 100644 evm_loader/lib/src/commands/get_ether_account_data.rs create mode 100644 evm_loader/lib/src/commands/get_holder.rs diff --git a/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs b/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs deleted file mode 100644 index bc4d9b70d..000000000 --- a/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs +++ /dev/null @@ -1,33 +0,0 @@ -use crate::api_server::handlers::process_error; -use crate::commands::get_ether_account_data as GetEtherAccountDataCommand; -use crate::{api_context, context::Context, types::request_models::GetEtherRequest, NeonApiState}; -use actix_request_identifier::RequestId; -use actix_web::{get, http::StatusCode, web::Query, Responder}; -use std::convert::Into; - -use super::process_result; - -#[tracing::instrument(skip(state, request_id), fields(id = request_id.as_str()))] -#[get("/get-ether-account-data")] -pub async fn get_ether_account_data( - state: NeonApiState, - request_id: RequestId, - Query(req_params): Query, -) -> impl Responder { - let rpc_client = match api_context::build_rpc_client(&state, req_params.slot, None).await { - Ok(rpc_client) => rpc_client, - Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), - }; - - let context = Context::new(&*rpc_client, &state.config); - - process_result( - &GetEtherAccountDataCommand::execute( - context.rpc_client, - &state.config.evm_loader, - &req_params.ether, - ) - .await - .map_err(Into::into), - ) -} diff --git a/evm_loader/lib/src/commands/cancel_trx.rs b/evm_loader/lib/src/commands/cancel_trx.rs index 1d3c47c84..5723a697f 100644 --- a/evm_loader/lib/src/commands/cancel_trx.rs +++ b/evm_loader/lib/src/commands/cancel_trx.rs @@ -1,17 +1,17 @@ +use evm_loader::account::StateAccount; use log::info; use serde::{Deserialize, Serialize}; use solana_sdk::{ - incinerator, instruction::{AccountMeta, Instruction}, pubkey::Pubkey, signature::Signature, signer::Signer, }; -use evm_loader::account::State; - -use crate::{account_storage::account_info, commands::send_transaction, rpc::Rpc, NeonResult}; +use crate::{ + account_storage::account_info, commands::send_transaction, rpc::Rpc, NeonError, NeonResult, +}; #[derive(Debug, Serialize, Deserialize)] pub struct CancelTrxReturn { @@ -24,20 +24,25 @@ pub async fn execute( evm_loader: Pubkey, storage_account: &Pubkey, ) -> NeonResult { - let mut acc = rpc_client.get_account(storage_account).await?; + let Some(mut acc) = rpc_client.get_account(storage_account).await?.value else { + return Err(NeonError::AccountNotFound(*storage_account)) + }; let storage_info = account_info(storage_account, &mut acc); - let storage = State::from_account(&evm_loader, &storage_info)?; + let storage = StateAccount::from_account(&evm_loader, storage_info)?; let operator = &signer.pubkey(); + let origin = storage.trx_origin(); + let chain_id: u64 = storage.trx_chain_id(); + let (origin_pubkey, _) = origin.find_balance_address(&evm_loader, chain_id); + let mut accounts_meta: Vec = vec![ - AccountMeta::new(*storage_account, false), // State account - AccountMeta::new(*operator, true), // Operator - AccountMeta::new(incinerator::id(), false), // Incinerator + AccountMeta::new(*storage_account, false), // State account + AccountMeta::new(*operator, true), // Operator + AccountMeta::new(origin_pubkey, false), ]; - let blocked_accounts = storage.read_blocked_accounts()?; - for blocked_account_meta in blocked_accounts { + for blocked_account_meta in storage.blocked_accounts().iter() { if blocked_account_meta.is_writable { accounts_meta.push(AccountMeta::new(blocked_account_meta.key, false)); } else { @@ -48,11 +53,8 @@ pub async fn execute( info!("\t{:?}", meta); } - let cancel_with_nonce_instruction = Instruction::new_with_bincode( - evm_loader, - &(0x23_u8, storage.transaction_hash), - accounts_meta, - ); + let cancel_with_nonce_instruction = + Instruction::new_with_bincode(evm_loader, &(0x23_u8, storage.trx_hash()), accounts_meta); let instructions = vec![cancel_with_nonce_instruction]; diff --git a/evm_loader/lib/src/commands/collect_treasury.rs b/evm_loader/lib/src/commands/collect_treasury.rs index ad9130c0b..8938e15d8 100644 --- a/evm_loader/lib/src/commands/collect_treasury.rs +++ b/evm_loader/lib/src/commands/collect_treasury.rs @@ -26,7 +26,7 @@ pub async fn execute(config: &Config, context: &Context<'_>) -> NeonResult) -> NeonResult NeonResult { - let (solana_address, nonce) = ether_address.find_solana_address(&evm_loader); - debug!("Create ethereum account {solana_address} <- {ether_address} {nonce}"); - - let create_account_v03_instruction = Instruction::new_with_bincode( - evm_loader, - &(0x28_u8, ether_address.as_bytes()), - vec![ - AccountMeta::new(signer.pubkey(), true), - AccountMeta::new_readonly(system_program::id(), false), - AccountMeta::new(solana_address, false), - ], - ); - - let instructions = vec![create_account_v03_instruction]; - - let mut finalize_message = Message::new(&instructions, Some(&signer.pubkey())); - let blockhash = rpc_client.get_latest_blockhash().await?; - finalize_message.recent_blockhash = blockhash; - - check_account_for_fee(rpc_client, &signer.pubkey(), &finalize_message).await?; - - let mut finalize_tx = Transaction::new_unsigned(finalize_message); - - finalize_tx.try_sign(&[signer], blockhash)?; - debug!("signed: {:x?}", finalize_tx); - - rpc_client - .send_and_confirm_transaction_with_spinner(&finalize_tx) - .await?; - - Ok(CreateEtherAccountReturn { - solana_address: solana_address.to_string(), - }) -} diff --git a/evm_loader/lib/src/commands/deposit.rs b/evm_loader/lib/src/commands/deposit.rs deleted file mode 100644 index ce5ed1669..000000000 --- a/evm_loader/lib/src/commands/deposit.rs +++ /dev/null @@ -1,117 +0,0 @@ -use log::debug; -use serde::{Deserialize, Serialize}; - -use crate::rpc::check_account_for_fee; -use crate::NeonResult; -use evm_loader::types::Address; -use solana_client::nonblocking::rpc_client::RpcClient; -use solana_sdk::signer::Signer; -use solana_sdk::{ - instruction::{AccountMeta, Instruction}, - message::Message, - pubkey::Pubkey, - signature::Signature, - system_program, - transaction::Transaction, -}; -use spl_associated_token_account::get_associated_token_address; - -#[derive(Debug, Serialize, Deserialize)] -pub struct DepositReturn { - pub transaction: Signature, -} - -/// Executes subcommand `deposit`. -pub async fn execute( - rpc_client: &RpcClient, - evm_loader: Pubkey, - signer: &dyn Signer, - amount: u64, - ether_address: &Address, -) -> NeonResult { - let (ether_pubkey, _) = ether_address.find_solana_address(&evm_loader); - - let token_mint_id = evm_loader::config::token_mint::id(); - - let signer_token_pubkey = get_associated_token_address(&signer.pubkey(), &token_mint_id); - let evm_token_authority = Pubkey::find_program_address(&[b"Deposit"], &evm_loader).0; - let evm_pool_pubkey = get_associated_token_address(&evm_token_authority, &token_mint_id); - - let instructions = vec![ - spl_approve_instruction(signer.pubkey(), signer_token_pubkey, ether_pubkey, amount)?, - deposit_instruction( - evm_loader, - signer.pubkey(), - signer_token_pubkey, - evm_pool_pubkey, - ether_address, - ether_pubkey, - ), - ]; - - let mut finalize_message = Message::new(&instructions, Some(&signer.pubkey())); - let blockhash = rpc_client.get_latest_blockhash().await?; - finalize_message.recent_blockhash = blockhash; - - check_account_for_fee(rpc_client, &signer.pubkey(), &finalize_message).await?; - - let mut finalize_tx = Transaction::new_unsigned(finalize_message); - - finalize_tx.try_sign(&[signer], blockhash)?; - debug!("signed: {:x?}", finalize_tx); - - let signature = rpc_client - .send_and_confirm_transaction_with_spinner(&finalize_tx) - .await?; - - Ok(DepositReturn { - transaction: signature, - }) -} - -/// Returns instruction to approve transfer of NEON tokens. -fn spl_approve_instruction( - signer: Pubkey, - source_pubkey: Pubkey, - delegate_pubkey: Pubkey, - amount: u64, -) -> NeonResult { - use spl_token::instruction::TokenInstruction; - - let accounts = vec![ - AccountMeta::new(source_pubkey, false), - AccountMeta::new_readonly(delegate_pubkey, false), - AccountMeta::new_readonly(signer, true), - ]; - - let data = TokenInstruction::Approve { amount }.pack(); - - Ok(Instruction { - program_id: spl_token::id(), - accounts, - data, - }) -} - -/// Returns instruction to deposit NEON tokens. -fn deposit_instruction( - evm_loader: Pubkey, - signer: Pubkey, - source_pubkey: Pubkey, - destination_pubkey: Pubkey, - ether_address: &Address, - ether_account_pubkey: Pubkey, -) -> Instruction { - Instruction::new_with_bincode( - evm_loader, - &(0x27_u8, ether_address.as_bytes()), - vec![ - AccountMeta::new(source_pubkey, false), - AccountMeta::new(destination_pubkey, false), - AccountMeta::new(ether_account_pubkey, false), - AccountMeta::new_readonly(spl_token::id(), false), - AccountMeta::new(signer, true), - AccountMeta::new_readonly(system_program::id(), false), - ], - ) -} diff --git a/evm_loader/lib/src/commands/emulate.rs b/evm_loader/lib/src/commands/emulate.rs index 79e2c6ffc..3a268a4d0 100644 --- a/evm_loader/lib/src/commands/emulate.rs +++ b/evm_loader/lib/src/commands/emulate.rs @@ -1,265 +1,86 @@ -use std::fmt::{Display, Formatter}; - -use ethnum::U256; +use evm_loader::account::ContractAccount; use log::{debug, info}; -use serde::{Deserialize, Serialize}; -use solana_sdk::{commitment_config::CommitmentConfig, pubkey::Pubkey}; +use serde::Serialize; +use solana_sdk::entrypoint::MAX_PERMITTED_DATA_INCREASE; +use solana_sdk::pubkey::Pubkey; -use evm_loader::evm::tracing::TracerTypeOpt; -use evm_loader::evm::tracing::{AccountOverrides, BlockOverrides}; +use crate::syscall_stubs::setup_emulator_syscall_stubs; +use crate::types::{EmulateRequest, TxParams}; +use crate::{ + account_storage::{EmulatorAccountStorage, SolanaAccount}, + errors::NeonError, + rpc::Rpc, + NeonResult, +}; +use evm_loader::evm::tracing::TracerType; use evm_loader::{ - account_storage::AccountStorage, config::{EVM_STEPS_MIN, PAYMENT_TO_TREASURE}, evm::{ExitStatus, Machine}, executor::{Action, ExecutorState}, gasometer::LAMPORTS_PER_SIGNATURE, - types::{Address, Transaction}, }; - -use crate::types::TxParams; -use crate::{ - account_storage::{EmulatorAccountStorage, NeonAccount, SolanaAccount}, - errors::NeonError, - rpc::Rpc, - syscall_stubs::Stubs, - NeonResult, -}; - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct EmulationResult { - #[serde(serialize_with = "serde_hex_serialize")] - #[serde(deserialize_with = "serde_hex_deserialize")] +use serde_with::{hex::Hex, serde_as, DisplayFromStr}; + +#[serde_as] +#[derive(Debug, Clone, Serialize)] +pub struct EmulateResponse { + #[serde_as(as = "DisplayFromStr")] + pub exit_status: ExitStatus, + #[serde_as(as = "Hex")] pub result: Vec, - pub exit_status: String, pub steps_executed: u64, pub used_gas: u64, - pub actions: Vec, -} - -impl Display for EmulationResult { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!( - f, - "{{ exit_status: {}, steps_executed: {}, used_gas: {}, actions: {}, result: {} }}", - self.exit_status, - self.steps_executed, - self.used_gas, - self.actions.len(), - hex::encode(&self.result), - ) - } -} - -impl From for EmulationResult { - fn from(value: evm_loader::evm::tracing::EmulationResult) -> Self { - Self { - exit_status: value.exit_status.status().to_string(), - result: value.exit_status.into_result().unwrap_or_default(), - steps_executed: value.steps_executed, - used_gas: value.used_gas, - actions: value.actions, - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct EmulationResultWithAccounts { - pub accounts: Vec, + pub iterations: u64, pub solana_accounts: Vec, - pub token_accounts: Vec, - #[serde(flatten)] - pub emulation_result: EmulationResult, -} - -impl Display for EmulationResultWithAccounts { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.emulation_result) - } -} - -fn serde_hex_serialize(value: &[u8], s: S) -> Result -where - S: serde::Serializer, -{ - s.serialize_str(&hex::encode(value)) -} - -fn serde_hex_deserialize<'de, D>(d: D) -> Result, D::Error> -where - D: serde::Deserializer<'de>, -{ - struct StringVisitor; - impl<'de> serde::de::Visitor<'de> for StringVisitor { - type Value = Vec; - - fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result { - write!(formatter, "a hex-encoded string with even length") - } - - fn visit_str(self, s: &str) -> Result - where - E: serde::de::Error, - { - hex::decode(s).map_err(|_err| { - serde::de::Error::invalid_value(serde::de::Unexpected::Str(s), &self) - }) - } - } - - d.deserialize_string(StringVisitor) } -#[allow(clippy::too_many_arguments)] pub async fn execute( rpc_client: &dyn Rpc, - evm_loader: Pubkey, - tx_params: TxParams, - token_mint: Pubkey, - chain_id: u64, - step_limit: u64, - commitment: CommitmentConfig, - accounts: &[Address], - solana_accounts: &[Pubkey], - block_overrides: &Option, - state_overrides: Option, -) -> NeonResult { - let (emulation_result, storage) = emulate_transaction( + program_id: Pubkey, + config: EmulateRequest, + tracer: Option, +) -> NeonResult { + let block_overrides = config + .trace_config + .as_ref() + .and_then(|t| t.block_overrides.clone()); + let state_overrides = config + .trace_config + .as_ref() + .and_then(|t| t.state_overrides.clone()); + + let mut storage = EmulatorAccountStorage::with_accounts( rpc_client, - evm_loader, - tx_params, - token_mint, - chain_id, - step_limit, - commitment, - accounts, - solana_accounts, + program_id, + &config.accounts, + config.chains, block_overrides, state_overrides, - None, ) .await?; - let accounts = storage.accounts.borrow().values().cloned().collect(); - let solana_accounts = storage.solana_accounts.borrow().values().cloned().collect(); - Ok(EmulationResultWithAccounts { - accounts, - solana_accounts, - token_accounts: vec![], - emulation_result: emulation_result.into(), - }) + let step_limit = config.step_limit.unwrap_or(100000); + + setup_emulator_syscall_stubs(rpc_client).await?; + emulate_trx(config.tx, &mut storage, step_limit, tracer).await } -#[allow(clippy::too_many_arguments)] -pub(crate) async fn emulate_transaction<'a>( - rpc_client: &'a dyn Rpc, - evm_loader: Pubkey, +async fn emulate_trx( tx_params: TxParams, - token_mint: Pubkey, - chain_id: u64, + storage: &mut EmulatorAccountStorage<'_>, step_limit: u64, - commitment: CommitmentConfig, - accounts: &[Address], - solana_accounts: &[Pubkey], - block_overrides: &Option, - state_overrides: Option, - tracer: TracerTypeOpt, -) -> Result< - ( - evm_loader::evm::tracing::EmulationResult, - EmulatorAccountStorage<'a>, - ), - NeonError, -> { - setup_syscall_stubs(rpc_client).await?; + tracer: Option, +) -> NeonResult { + info!("tx_params: {:?}", tx_params); - let storage = EmulatorAccountStorage::with_accounts( - rpc_client, - evm_loader, - token_mint, - chain_id, - commitment, - accounts, - solana_accounts, - block_overrides, - state_overrides, - ) - .await?; + let (origin, tx) = tx_params.into_transaction(storage).await; - emulate_trx(tx_params, &storage, chain_id, step_limit, tracer) - .await - .map(move |result| (result, storage)) -} + info!("origin: {:?}", origin); + info!("tx: {:?}", tx); -pub(crate) async fn emulate_trx<'a>( - tx_params: TxParams, - storage: &'a EmulatorAccountStorage<'a>, - chain_id: u64, - step_limit: u64, - tracer: TracerTypeOpt, -) -> Result { let (exit_status, actions, steps_executed) = { let mut backend = ExecutorState::new(storage); - let trx_payload = if tx_params.access_list.is_some() { - let access_list = tx_params - .access_list - .expect("access_list is present") - .into_iter() - .map(|item| { - ( - item.address, - item.storage_keys - .into_iter() - .map(|k| { - evm_loader::types::StorageKey::try_from(k) - .expect("key to be correct") - }) - .collect(), - ) - }) - .collect(); - evm_loader::types::TransactionPayload::AccessList(evm_loader::types::AccessListTx { - nonce: match tx_params.nonce { - Some(nonce) => nonce, - None => storage.nonce(&tx_params.from).await, - }, - gas_price: tx_params.gas_price.unwrap_or_default(), - gas_limit: tx_params.gas_limit.unwrap_or(U256::MAX), - target: tx_params.to, - value: tx_params.value.unwrap_or_default(), - call_data: evm_loader::evm::Buffer::from_slice(&tx_params.data.unwrap_or_default()), - r: U256::default(), - s: U256::default(), - chain_id: chain_id.into(), - recovery_id: u8::default(), - access_list, - }) - } else { - evm_loader::types::TransactionPayload::Legacy(evm_loader::types::LegacyTx { - nonce: match tx_params.nonce { - Some(nonce) => nonce, - None => storage.nonce(&tx_params.from).await, - }, - gas_price: tx_params.gas_price.unwrap_or_default(), - gas_limit: tx_params.gas_limit.unwrap_or(U256::MAX), - target: tx_params.to, - value: tx_params.value.unwrap_or_default(), - call_data: evm_loader::evm::Buffer::from_slice(&tx_params.data.unwrap_or_default()), - v: U256::default(), - r: U256::default(), - s: U256::default(), - chain_id: Some(chain_id.into()), - recovery_id: u8::default(), - }) - }; - - let mut trx = Transaction { - transaction: trx_payload, - byte_len: usize::default(), - hash: <[u8; 32]>::default(), - signed_hash: <[u8; 32]>::default(), - }; - - let mut evm = Machine::new(&mut trx, tx_params.from, &mut backend, tracer).await?; + let mut evm = Machine::new(tx, origin, &mut backend, tracer).await?; let (result, steps_executed) = evm.execute(step_limit, &mut backend).await?; if result == ExitStatus::StepLimit { @@ -270,29 +91,46 @@ pub(crate) async fn emulate_trx<'a>( (result, actions, steps_executed) }; + storage.apply_actions(actions.clone()).await?; + storage.mark_legacy_accounts().await?; + debug!("Execute done, result={exit_status:?}"); debug!("{steps_executed} steps executed"); - let accounts_operations = storage.calc_accounts_operations(&actions).await; + let steps_iterations = (steps_executed + (EVM_STEPS_MIN - 1)) / EVM_STEPS_MIN; + let treasury_gas = steps_iterations * PAYMENT_TO_TREASURE; + let cancel_gas = LAMPORTS_PER_SIGNATURE; - let max_iterations = (steps_executed + (EVM_STEPS_MIN - 1)) / EVM_STEPS_MIN; - let steps_gas = max_iterations * (LAMPORTS_PER_SIGNATURE + PAYMENT_TO_TREASURE); - let begin_end_gas = 2 * LAMPORTS_PER_SIGNATURE; - let actions_gas = storage.apply_actions(&actions).await; - let accounts_gas = storage.apply_accounts_operations(accounts_operations).await; - info!("Gas - steps: {steps_gas}, actions: {actions_gas}, accounts: {accounts_gas}"); + let begin_end_iterations = 2; + let iterations: u64 = steps_iterations + begin_end_iterations + realloc_iterations(&actions); + let iterations_gas = iterations * LAMPORTS_PER_SIGNATURE; - Ok(evm_loader::evm::tracing::EmulationResult { + let used_gas = storage.gas + iterations_gas + treasury_gas + cancel_gas; + + let solana_accounts = storage.accounts.borrow().values().cloned().collect(); + + let result = exit_status.clone().into_result().unwrap_or_default(); + + Ok(EmulateResponse { exit_status, steps_executed, - used_gas: steps_gas + begin_end_gas + actions_gas + accounts_gas, - actions, + used_gas, + solana_accounts, + result, + iterations, }) } -pub(crate) async fn setup_syscall_stubs(rpc_client: &dyn Rpc) -> Result<(), NeonError> { - let syscall_stubs = Stubs::new(rpc_client).await?; - solana_sdk::program_stubs::set_syscall_stubs(syscall_stubs); +fn realloc_iterations(actions: &[Action]) -> u64 { + let mut result = 0; + + for action in actions { + if let Action::EvmSetCode { code, .. } = action { + let size = ContractAccount::required_account_size(code); + let c = size / MAX_PERMITTED_DATA_INCREASE; + result = std::cmp::max(result, c); + } + } - Ok(()) + result as u64 } diff --git a/evm_loader/lib/src/commands/get_balance.rs b/evm_loader/lib/src/commands/get_balance.rs new file mode 100644 index 000000000..418e0a1ec --- /dev/null +++ b/evm_loader/lib/src/commands/get_balance.rs @@ -0,0 +1,122 @@ +use ethnum::U256; +use evm_loader::account::legacy::LegacyEtherData; +use evm_loader::account::BalanceAccount; +use serde::Serialize; +use solana_sdk::{account::Account, pubkey::Pubkey}; + +use crate::{account_storage::account_info, rpc::Rpc, types::BalanceAddress, NeonResult}; + +use serde_with::{serde_as, DisplayFromStr}; + +use super::get_config::ChainInfo; + +#[derive(Debug, Serialize)] +pub enum BalanceStatus { + Ok, + Legacy, + Empty, +} + +#[serde_as] +#[derive(Debug, Serialize)] +pub struct GetBalanceResponse { + #[serde_as(as = "DisplayFromStr")] + pub solana_address: Pubkey, + #[serde_as(as = "DisplayFromStr")] + pub contract_solana_address: Pubkey, + pub trx_count: u64, + pub balance: U256, + pub status: BalanceStatus, +} + +impl GetBalanceResponse { + pub fn empty(program_id: &Pubkey, address: &BalanceAddress) -> Self { + Self { + solana_address: address.find_pubkey(program_id), + contract_solana_address: address.find_contract_pubkey(program_id), + trx_count: 0, + balance: U256::ZERO, + status: BalanceStatus::Empty, + } + } +} + +fn read_account( + program_id: &Pubkey, + address: &BalanceAddress, + mut account: Account, +) -> NeonResult { + let solana_address = address.find_pubkey(program_id); + + let account_info = account_info(&solana_address, &mut account); + let balance_account = BalanceAccount::from_account(program_id, account_info, None)?; + + Ok(GetBalanceResponse { + solana_address, + contract_solana_address: address.find_contract_pubkey(program_id), + trx_count: balance_account.nonce(), + balance: balance_account.balance(), + status: BalanceStatus::Ok, + }) +} + +fn read_legacy_account( + program_id: &Pubkey, + address: &BalanceAddress, + mut account: Account, +) -> NeonResult { + let solana_address = address.find_pubkey(program_id); + let contract_solana_address = address.find_contract_pubkey(program_id); + + let account_info = account_info(&contract_solana_address, &mut account); + let balance_account = LegacyEtherData::from_account(program_id, &account_info)?; + + Ok(GetBalanceResponse { + solana_address, + contract_solana_address, + trx_count: balance_account.trx_count, + balance: balance_account.balance, + status: BalanceStatus::Legacy, + }) +} + +fn is_legacy_chain_id(id: u64, chains: &[ChainInfo]) -> bool { + for chain in chains { + if chain.name == "neon" { + return id == chain.id; + } + } + + false +} + +pub async fn execute( + rpc_client: &dyn Rpc, + program_id: &Pubkey, + address: &[BalanceAddress], +) -> NeonResult> { + let chain_ids = super::get_config::read_chains(rpc_client, *program_id).await?; + + let pubkeys: Vec<_> = address.iter().map(|a| a.find_pubkey(program_id)).collect(); + let accounts = rpc_client.get_multiple_accounts(&pubkeys).await?; + + let mut result = Vec::with_capacity(accounts.len()); + for (key, account) in address.iter().zip(accounts) { + let response = if let Some(account) = account { + read_account(program_id, key, account)? + } else if is_legacy_chain_id(key.chain_id, &chain_ids) { + let contract_pubkey = key.find_contract_pubkey(program_id); + if let Some(contract_account) = rpc_client.get_account(&contract_pubkey).await?.value { + read_legacy_account(program_id, key, contract_account)? + } else { + GetBalanceResponse::empty(program_id, key) + } + } else { + GetBalanceResponse::empty(program_id, key) + }; + + result.push(response); + } + + Ok(result) +} diff --git a/evm_loader/lib/src/commands/get_contract.rs b/evm_loader/lib/src/commands/get_contract.rs new file mode 100644 index 000000000..2619a35aa --- /dev/null +++ b/evm_loader/lib/src/commands/get_contract.rs @@ -0,0 +1,98 @@ +use evm_loader::{ + account::{legacy::LegacyEtherData, ContractAccount}, + types::Address, +}; +use serde::Serialize; +use solana_sdk::{account::Account, pubkey::Pubkey}; + +use crate::{account_storage::account_info, rpc::Rpc, NeonResult}; + +use serde_with::{hex::Hex, serde_as, DisplayFromStr}; + +use super::get_config::ChainInfo; + +#[serde_as] +#[derive(Debug, Serialize)] +pub struct GetContractResponse { + #[serde_as(as = "DisplayFromStr")] + pub solana_address: Pubkey, + pub chain_id: Option, + #[serde_as(as = "Hex")] + pub code: Vec, +} + +impl GetContractResponse { + pub fn empty(solana_address: Pubkey) -> Self { + Self { + solana_address, + chain_id: None, + code: vec![], + } + } +} + +fn find_legacy_chain_id(chains: &[ChainInfo]) -> u64 { + for chain in chains { + if chain.name == "neon" { + return chain.id; + } + } + + unreachable!() +} + +fn read_account( + program_id: &Pubkey, + legacy_chain_id: u64, + solana_address: Pubkey, + account: Option, +) -> NeonResult { + let Some(mut account) = account else { + return Ok(GetContractResponse::empty(solana_address)); + }; + + let account_info = account_info(&solana_address, &mut account); + let (chain_id, code) = + if let Ok(contract) = ContractAccount::from_account(program_id, account_info.clone()) { + (Some(contract.chain_id()), contract.code().to_vec()) + } else if let Ok(contract) = LegacyEtherData::from_account(program_id, &account_info) { + if contract.code_size > 0 || contract.generation > 0 { + let code = contract.read_code(&account_info); + (Some(legacy_chain_id), code) + } else { + (None, vec![]) + } + } else { + (None, vec![]) + }; + + Ok(GetContractResponse { + solana_address, + chain_id, + code, + }) +} + +pub async fn execute( + rpc_client: &dyn Rpc, + program_id: &Pubkey, + accounts: &[Address], +) -> NeonResult> { + let chain_ids = super::get_config::read_chains(rpc_client, *program_id).await?; + let legacy_chain_id = find_legacy_chain_id(&chain_ids); + + let pubkeys: Vec<_> = accounts + .iter() + .map(|a| a.find_solana_address(program_id).0) + .collect(); + + let accounts = rpc_client.get_multiple_accounts(&pubkeys).await?; + + let mut result = Vec::with_capacity(accounts.len()); + for (key, account) in pubkeys.into_iter().zip(accounts) { + let response = read_account(program_id, legacy_chain_id, key, account)?; + result.push(response); + } + + Ok(result) +} diff --git a/evm_loader/lib/src/commands/get_ether_account_data.rs b/evm_loader/lib/src/commands/get_ether_account_data.rs deleted file mode 100644 index 31b98506e..000000000 --- a/evm_loader/lib/src/commands/get_ether_account_data.rs +++ /dev/null @@ -1,70 +0,0 @@ -use evm_loader::{account::EthereumAccount, types::Address}; -use serde::{Deserialize, Serialize}; -use solana_sdk::pubkey::Pubkey; -use std::fmt::{Display, Formatter}; - -use crate::{ - account_storage::{account_info, EmulatorAccountStorage}, - errors::NeonError, - rpc::Rpc, - NeonResult, -}; - -#[derive(Debug, Serialize, Deserialize)] -pub struct GetEtherAccountDataReturn { - pub solana_address: String, - pub address: Address, - pub bump_seed: u8, - pub trx_count: u64, - pub rw_blocked: bool, - pub balance: String, - pub generation: u32, - pub code_size: u32, - pub code: String, -} - -impl Display for GetEtherAccountDataReturn { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!( - f, - "{{ address: {}, solana_address: {}, trx_count: {}, balance: {}, generation: {}, code_size: {} }}", - self.address, - self.solana_address, - self.trx_count, - self.balance, - self.generation, - self.code_size, - ) - } -} - -pub async fn execute( - rpc_client: &dyn Rpc, - evm_loader: &Pubkey, - ether_address: &Address, -) -> NeonResult { - match EmulatorAccountStorage::get_account_from_solana(rpc_client, evm_loader, ether_address) - .await - { - (solana_address, Some(mut acc)) => { - let acc_info = account_info(&solana_address, &mut acc); - let account_data = EthereumAccount::from_account(evm_loader, &acc_info).unwrap(); - let contract_code = account_data - .contract_data() - .map_or_else(Vec::new, |c| c.code().to_vec()); - - Ok(GetEtherAccountDataReturn { - solana_address: solana_address.to_string(), - address: account_data.address, - bump_seed: account_data.bump_seed, - trx_count: account_data.trx_count, - rw_blocked: account_data.rw_blocked, - balance: account_data.balance.to_string(), - generation: account_data.generation, - code_size: account_data.code_size, - code: hex::encode(contract_code), - }) - } - (solana_address, None) => Err(NeonError::AccountNotFound(solana_address)), - } -} diff --git a/evm_loader/lib/src/commands/get_holder.rs b/evm_loader/lib/src/commands/get_holder.rs new file mode 100644 index 000000000..fc3db7cbc --- /dev/null +++ b/evm_loader/lib/src/commands/get_holder.rs @@ -0,0 +1,154 @@ +use ethnum::U256; +use evm_loader::account::{ + legacy::{ + LegacyFinalizedData, LegacyHolderData, TAG_HOLDER_DEPRECATED, + TAG_STATE_FINALIZED_DEPRECATED, + }, + Holder, StateAccount, StateFinalizedAccount, TAG_HOLDER, TAG_STATE, TAG_STATE_FINALIZED, +}; +use serde::Serialize; +use solana_sdk::{account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey}; +use std::fmt::Display; + +use crate::{account_storage::account_info, rpc::Rpc, NeonResult}; + +use serde_with::{hex::Hex, serde_as, skip_serializing_none, DisplayFromStr}; + +#[derive(Debug, Default, Serialize)] +pub enum Status { + #[default] + Empty, + Error(String), + Holder, + Active, + Finalized, +} + +#[serde_as] +#[derive(Debug, Default, Serialize)] +pub struct AccountMeta { + pub is_writable: bool, + #[serde_as(as = "DisplayFromStr")] + pub key: Pubkey, +} + +#[serde_as] +#[skip_serializing_none] +#[derive(Debug, Default, Serialize)] +pub struct GetHolderResponse { + pub status: Status, + pub len: Option, + #[serde_as(as = "Option")] + pub owner: Option, + + #[serde_as(as = "Option")] + pub tx: Option<[u8; 32]>, + pub chain_id: Option, + + pub gas_price: Option, + pub gas_limit: Option, + pub gas_used: Option, + + pub accounts: Option>, +} + +impl GetHolderResponse { + pub fn empty() -> Self { + Self { + status: Status::Empty, + ..Self::default() + } + } + + pub fn error(error: T) -> Self { + Self { + status: Status::Error(error.to_string()), + ..Self::default() + } + } +} + +pub fn read_holder(program_id: &Pubkey, info: AccountInfo) -> NeonResult { + let data_len = info.data_len(); + + match evm_loader::account::tag(program_id, &info)? { + TAG_HOLDER => { + let holder = Holder::from_account(program_id, info)?; + Ok(GetHolderResponse { + status: Status::Holder, + len: Some(data_len), + owner: Some(holder.owner()), + tx: Some(holder.transaction_hash()), + ..GetHolderResponse::default() + }) + } + TAG_HOLDER_DEPRECATED => { + let holder = LegacyHolderData::from_account(program_id, &info)?; + Ok(GetHolderResponse { + status: Status::Holder, + len: Some(data_len), + owner: Some(holder.owner), + tx: Some([0u8; 32]), + ..GetHolderResponse::default() + }) + } + TAG_STATE_FINALIZED => { + let state = StateFinalizedAccount::from_account(program_id, info)?; + Ok(GetHolderResponse { + status: Status::Finalized, + len: Some(data_len), + owner: Some(state.owner()), + tx: Some(state.trx_hash()), + ..GetHolderResponse::default() + }) + } + TAG_STATE_FINALIZED_DEPRECATED => { + let state = LegacyFinalizedData::from_account(program_id, &info)?; + Ok(GetHolderResponse { + status: Status::Finalized, + len: Some(data_len), + owner: Some(state.owner), + tx: Some(state.transaction_hash), + ..GetHolderResponse::default() + }) + } + TAG_STATE => { + let state = StateAccount::from_account(program_id, info)?; + let accounts = state + .blocked_accounts() + .iter() + .map(|a| AccountMeta { + is_writable: a.is_writable, + key: a.key, + }) + .collect(); + + Ok(GetHolderResponse { + status: Status::Active, + len: Some(data_len), + owner: Some(state.owner()), + tx: Some(state.trx_hash()), + chain_id: Some(state.trx_chain_id()), + gas_limit: Some(state.trx_gas_limit()), + gas_price: Some(state.trx_gas_price()), + gas_used: Some(state.gas_used()), + accounts: Some(accounts), + }) + } + _ => Err(ProgramError::InvalidAccountData.into()), + } +} + +pub async fn execute( + rpc_client: &dyn Rpc, + program_id: &Pubkey, + address: Pubkey, +) -> NeonResult { + let response = rpc_client.get_account(&address).await?; + let Some(mut account) = response.value else { + return Ok(GetHolderResponse::empty()) + }; + + let info = account_info(&address, &mut account); + Ok(read_holder(program_id, info).unwrap_or_else(GetHolderResponse::error)) +} diff --git a/evm_loader/lib/src/commands/get_storage_at.rs b/evm_loader/lib/src/commands/get_storage_at.rs index bd8f02632..41fe16eee 100644 --- a/evm_loader/lib/src/commands/get_storage_at.rs +++ b/evm_loader/lib/src/commands/get_storage_at.rs @@ -1,81 +1,24 @@ -use std::convert::TryInto; -use std::fmt::{Display, Formatter}; - use ethnum::U256; use serde::{Deserialize, Serialize}; use solana_sdk::pubkey::Pubkey; -use evm_loader::account::EthereumAccount; -use evm_loader::{ - account::{ether_storage::EthereumStorageAddress, EthereumStorage}, - config::STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT, - types::Address, -}; +use evm_loader::{account_storage::AccountStorage, types::Address}; -use crate::{ - account_storage::{account_info, EmulatorAccountStorage}, - rpc::Rpc, - NeonResult, -}; +use crate::{account_storage::EmulatorAccountStorage, rpc::Rpc, NeonResult}; #[derive(Default, Serialize, Deserialize)] pub struct GetStorageAtReturn(pub [u8; 32]); -impl Display for GetStorageAtReturn { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "0x{}", hex::encode(self.0)) - } -} - pub async fn execute( rpc_client: &dyn Rpc, - evm_loader: &Pubkey, - ether_address: Address, - index: &U256, + program_id: &Pubkey, + address: Address, + index: U256, ) -> NeonResult { - let value = if let (solana_address, Some(mut account)) = - EmulatorAccountStorage::get_account_from_solana(rpc_client, evm_loader, ðer_address) - .await - { - let info = account_info(&solana_address, &mut account); - - let account_data = EthereumAccount::from_account(evm_loader, &info)?; - if let Some(contract) = account_data.contract_data() { - if *index < U256::from(STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT) { - let index: usize = index.as_usize() * 32; - GetStorageAtReturn(contract.storage()[index..index + 32].try_into().unwrap()) - } else { - let subindex = (*index & 0xFF).as_u8(); - let index = *index & !U256::new(0xFF); - - let address = - EthereumStorageAddress::new(evm_loader, account_data.info.key, &index); - - if let Ok(mut account) = rpc_client.get_account(address.pubkey()).await { - if solana_sdk::system_program::check_id(&account.owner) { - Default::default() - } else { - let account_info = account_info(address.pubkey(), &mut account); - let storage = EthereumStorage::from_account(evm_loader, &account_info)?; - if (storage.address != ether_address) - || (storage.index != index) - || (storage.generation != account_data.generation) - { - Default::default() - } else { - GetStorageAtReturn(storage.get(subindex)) - } - } - } else { - Default::default() - } - } - } else { - Default::default() - } - } else { - Default::default() - }; + let value = EmulatorAccountStorage::new(rpc_client, *program_id, None, None, None) + .await? + .storage(address, index) + .await; - Ok(value) + Ok(GetStorageAtReturn(value)) } diff --git a/evm_loader/lib/src/commands/init_environment.rs b/evm_loader/lib/src/commands/init_environment.rs index 028bf82b0..11bb8e6a6 100644 --- a/evm_loader/lib/src/commands/init_environment.rs +++ b/evm_loader/lib/src/commands/init_environment.rs @@ -186,8 +186,8 @@ pub async fn execute( Ok(Some(transaction)) }; - let neon_token_mint = program_parameters.get::("NEON_TOKEN_MINT")?; - let neon_token_mint_decimals = program_parameters.get::("NEON_TOKEN_MINT_DECIMALS")?; + let neon_token_mint: Pubkey = program_parameters.get("NEON_TOKEN_MINT")?; + let neon_token_mint_decimals = 9; executor .check_and_create_object( "NEON-token mint", @@ -209,41 +209,42 @@ pub async fn execute( //====================== Create 'Deposit' NEON-token balance ====================================================== let (deposit_authority, _) = Pubkey::find_program_address(&[b"Deposit"], &config.evm_loader); - let deposit_address = get_associated_token_address(&deposit_authority, &neon_token_mint); - executor - .check_and_create_object( - "NEON Deposit balance", - executor - .get_account_data_pack::( - &spl_token::id(), - &deposit_address, - ) - .await, - |account| async move { - if account.mint != neon_token_mint || account.owner != deposit_authority { - Err(EnvironmentError::InvalidSplTokenAccount(deposit_address).into()) - } else { - Ok(None) - } - }, - || async { - let transaction = executor + let chains = super::get_config::read_chains(context.rpc_client, config.evm_loader).await?; + for chain in chains { + let pool = get_associated_token_address(&deposit_authority, &chain.token); + + executor + .check_and_create_object( + "Token pool account", + executor + .get_account_data_pack::(&spl_token::id(), &pool) + .await, + |account| async move { + if account.mint != chain.token || account.owner != deposit_authority { + Err(EnvironmentError::InvalidSplTokenAccount(pool).into()) + } else { + Ok(None) + } + }, + || async { + let transaction = executor .create_transaction_with_payer_only(&[ spl_associated_token_account::instruction::create_associated_token_account( &executor.fee_payer.pubkey(), &deposit_authority, - &neon_token_mint, + &chain.token, &spl_token::id(), ), ]) .await?; - Ok(Some(transaction)) - }, - ) - .await?; + Ok(Some(transaction)) + }, + ) + .await?; + } //====================== Create main treasury balance ============================================================= - let treasury_pool_seed = program_parameters.get::("NEON_POOL_SEED")?; + let treasury_pool_seed = program_parameters.get::("NEON_TREASURY_POOL_SEED")?; if treasury_pool_seed != TREASURY_POOL_SEED { error!( "Treasury pool seed mismatch {} != {}", @@ -285,7 +286,7 @@ pub async fn execute( .await?; //====================== Create auxiliary treasury balances ======================================================= - let treasury_pool_count = program_parameters.get::("NEON_POOL_COUNT")?; + let treasury_pool_count = program_parameters.get::("NEON_TREASURY_POOL_COUNT")?; for i in 0..treasury_pool_count { let minimum_balance = context .rpc_client diff --git a/evm_loader/lib/src/commands/mod.rs b/evm_loader/lib/src/commands/mod.rs index e99c6dcdc..805071eb1 100644 --- a/evm_loader/lib/src/commands/mod.rs +++ b/evm_loader/lib/src/commands/mod.rs @@ -13,10 +13,11 @@ use solana_sdk::{ pub mod cancel_trx; pub mod collect_treasury; -pub mod create_ether_account; -pub mod deposit; pub mod emulate; -pub mod get_ether_account_data; +pub mod get_balance; +pub mod get_config; +pub mod get_contract; +pub mod get_holder; pub mod get_neon_elf; pub mod get_storage_at; pub mod init_environment; diff --git a/evm_loader/lib/src/commands/trace.rs b/evm_loader/lib/src/commands/trace.rs index 39aa1a680..233533663 100644 --- a/evm_loader/lib/src/commands/trace.rs +++ b/evm_loader/lib/src/commands/trace.rs @@ -1,46 +1,36 @@ -use serde_json::Value; -use solana_sdk::{commitment_config::CommitmentConfig, pubkey::Pubkey}; use std::rc::Rc; +use serde_json::Value; +use solana_sdk::pubkey::Pubkey; + use evm_loader::evm::tracing::tracers::new_tracer; -use evm_loader::evm::tracing::TraceCallConfig; -use evm_loader::types::Address; -use crate::{commands::emulate::emulate_transaction, errors::NeonError, rpc::Rpc, types::TxParams}; +use crate::types::EmulateRequest; +use crate::{errors::NeonError, rpc::Rpc}; -#[allow(clippy::too_many_arguments)] pub async fn trace_transaction( rpc_client: &dyn Rpc, - evm_loader: Pubkey, - tx: TxParams, - token: Pubkey, - chain_id: u64, - steps: u64, - commitment: CommitmentConfig, - accounts: &[Address], - solana_accounts: &[Pubkey], - trace_call_config: TraceCallConfig, + program_id: Pubkey, + config: EmulateRequest, ) -> Result { - let tracer = new_tracer(&trace_call_config.trace_config)?; - - let (emulation_result, _storage) = emulate_transaction( - rpc_client, - evm_loader, - tx, - token, - chain_id, - steps, - commitment, - accounts, - solana_accounts, - &trace_call_config.block_overrides, - trace_call_config.state_overrides, - Some(Rc::clone(&tracer)), - ) - .await?; - - Ok(Rc::try_unwrap(tracer) + let trace_config = config + .trace_config + .as_ref() + .map(|c| c.trace_config.clone()) + .unwrap_or_default(); + + let tracer = new_tracer(&trace_config)?; + + let emulation_tracer = Some(Rc::clone(&tracer)); + let r = super::emulate::execute(rpc_client, program_id, config, emulation_tracer).await?; + + let mut traces = Rc::try_unwrap(tracer) .expect("There is must be only one reference") .into_inner() - .into_traces(emulation_result)) + .into_traces(); + traces["failed"] = r.exit_status.is_succeed().unwrap().into(); + traces["gas"] = r.used_gas.into(); + traces["return_value"] = hex::encode(&r.result).into(); + + Ok(traces) } diff --git a/evm_loader/program/src/evm/tracing/mod.rs b/evm_loader/program/src/evm/tracing/mod.rs index aed26b2e6..7fd50bb60 100644 --- a/evm_loader/program/src/evm/tracing/mod.rs +++ b/evm_loader/program/src/evm/tracing/mod.rs @@ -3,8 +3,6 @@ use std::collections::HashMap; use std::fmt::Debug; use std::rc::Rc; -use crate::account::EthereumAccount; -use crate::executor::Action; use crate::types::hexbytes::HexBytes; use crate::types::Address; use ethnum::U256; @@ -14,17 +12,9 @@ use super::{Context, ExitStatus}; pub mod tracers; -#[derive(Debug, Clone)] -pub struct EmulationResult { - pub exit_status: ExitStatus, - pub steps_executed: u64, - pub used_gas: u64, - pub actions: Vec, -} - pub trait EventListener: Send + Sync + Debug { fn event(&mut self, event: Event); - fn into_traces(self: Box, emulation_result: EmulationResult) -> Value; + fn into_traces(self: Box) -> Value; } pub type TracerType = Rc>>; @@ -85,16 +75,15 @@ pub struct AccountOverride { } impl AccountOverride { - pub fn apply(&self, ether_account: &mut EthereumAccount) { - if let Some(nonce) = self.nonce { - ether_account.trx_count = nonce; - } - if let Some(balance) = self.balance { - ether_account.balance = balance; - } - #[allow(clippy::cast_possible_truncation)] - if let Some(code) = &self.code { - ether_account.code_size = code.len() as u32; + #[must_use] + pub fn storage(&self, index: U256) -> Option<[u8; 32]> { + match (&self.state, &self.state_diff) { + (None, None) => None, + (Some(_), Some(_)) => { + panic!("Account has both `state` and `stateDiff` overrides") + } + (Some(state), None) => return state.get(&index).map(|value| value.to_be_bytes()), + (None, Some(state_diff)) => state_diff.get(&index).map(|v| v.to_be_bytes()), } } } diff --git a/evm_loader/program/src/evm/tracing/tracers/struct_logger.rs b/evm_loader/program/src/evm/tracing/tracers/struct_logger.rs index 8687c7a17..1143f3909 100644 --- a/evm_loader/program/src/evm/tracing/tracers/struct_logger.rs +++ b/evm_loader/program/src/evm/tracing/tracers/struct_logger.rs @@ -2,11 +2,11 @@ use std::collections::BTreeMap; use ethnum::U256; use serde::Serialize; -use serde_json::Value; +use serde_json::{json, Value}; use crate::evm::opcode_table::OPNAMES; use crate::evm::tracing::TraceConfig; -use crate::evm::tracing::{EmulationResult, Event, EventListener}; +use crate::evm::tracing::{Event, EventListener}; use crate::types::hexbytes::HexBytes; /// `StructLoggerResult` groups all structured logs emitted by the EVM @@ -198,23 +198,10 @@ impl EventListener for StructLogger { }; } - fn into_traces(self: Box, emulation_result: EmulationResult) -> Value { - let result = StructLoggerResult { - failed: !emulation_result - .exit_status - .is_succeed() - .expect("Emulation is not completed"), - gas: emulation_result.used_gas, - return_value: hex::encode( - emulation_result - .exit_status - .into_result() - .unwrap_or_default(), - ), - struct_logs: self.logs, - }; - - serde_json::to_value(result).expect("Conversion error") + fn into_traces(self: Box) -> Value { + json!({ + "struct_logs": self.logs + }) } } From ded71067252c812ea045c0e42d6db97d1cd1ddf8 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Tue, 14 Nov 2023 18:17:46 +0300 Subject: [PATCH 055/318] [Multi Tokens] NeonAPI handlers --- .../api/src/api_server/handlers/emulate.rs | 34 +-- .../src/api_server/handlers/get_balance.rs | 32 +++ .../src/api_server/handlers/get_contract.rs | 33 +++ .../api/src/api_server/handlers/get_holder.rs | 33 +++ .../src/api_server/handlers/get_storage_at.rs | 20 +- evm_loader/api/src/api_server/handlers/mod.rs | 58 +----- .../api/src/api_server/handlers/trace.rs | 39 +--- evm_loader/api/src/main.rs | 10 +- evm_loader/lib/src/types/mod.rs | 194 ++++++++++++------ evm_loader/lib/src/types/request_models.rs | 115 ----------- 10 files changed, 270 insertions(+), 298 deletions(-) create mode 100644 evm_loader/api/src/api_server/handlers/get_balance.rs create mode 100644 evm_loader/api/src/api_server/handlers/get_contract.rs create mode 100644 evm_loader/api/src/api_server/handlers/get_holder.rs delete mode 100644 evm_loader/lib/src/types/request_models.rs diff --git a/evm_loader/api/src/api_server/handlers/emulate.rs b/evm_loader/api/src/api_server/handlers/emulate.rs index f2d2119bd..fc5f583a3 100644 --- a/evm_loader/api/src/api_server/handlers/emulate.rs +++ b/evm_loader/api/src/api_server/handlers/emulate.rs @@ -4,49 +4,31 @@ use std::convert::Into; use crate::api_server::handlers::process_error; use crate::{ - api_context, commands::emulate as EmulateCommand, context::Context, - types::request_models::EmulateRequestModel, NeonApiState, + api_context, commands::emulate as EmulateCommand, types::EmulateApiRequest, NeonApiState, }; -use super::{parse_emulation_params, process_result}; +use super::process_result; #[tracing::instrument(skip(state, request_id), fields(id = request_id.as_str()))] #[post("/emulate")] pub async fn emulate( state: NeonApiState, request_id: RequestId, - Json(emulate_request): Json, + Json(emulate_request): Json, ) -> impl Responder { - let tx = emulate_request.tx_params.into(); + let slot = emulate_request.slot; + let index = emulate_request.tx_index_in_block; - let rpc_client = match api_context::build_rpc_client( - &state, - emulate_request.slot, - emulate_request.tx_index_in_block, - ) - .await - { + let rpc_client = match api_context::build_rpc_client(&state, slot, index).await { Ok(rpc_client) => rpc_client, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; - let context = Context::new(&*rpc_client, &state.config); - - let (token, chain, steps, accounts, solana_accounts) = - parse_emulation_params(&state.config, &context, &emulate_request.emulation_params).await; - process_result( &EmulateCommand::execute( - context.rpc_client, + rpc_client.as_ref(), state.config.evm_loader, - tx, - token, - chain, - steps, - state.config.commitment, - &accounts, - &solana_accounts, - &None, + emulate_request.body, None, ) .await diff --git a/evm_loader/api/src/api_server/handlers/get_balance.rs b/evm_loader/api/src/api_server/handlers/get_balance.rs new file mode 100644 index 000000000..ef2574582 --- /dev/null +++ b/evm_loader/api/src/api_server/handlers/get_balance.rs @@ -0,0 +1,32 @@ +use crate::api_server::handlers::process_error; +use crate::commands::get_balance as GetBalanceCommand; +use crate::{api_context, types::GetBalanceRequest, NeonApiState}; +use actix_request_identifier::RequestId; +use actix_web::web::Json; +use actix_web::{http::StatusCode, post, Responder}; +use std::convert::Into; + +use super::process_result; + +#[tracing::instrument(skip(state, request_id), fields(id = request_id.as_str()))] +#[post("/balance")] +pub async fn get_balance( + state: NeonApiState, + request_id: RequestId, + Json(req_params): Json, +) -> impl Responder { + let rpc_client = match api_context::build_rpc_client(&state, req_params.slot, None).await { + Ok(rpc_client) => rpc_client, + Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), + }; + + process_result( + &GetBalanceCommand::execute( + rpc_client.as_ref(), + &state.config.evm_loader, + &req_params.account, + ) + .await + .map_err(Into::into), + ) +} diff --git a/evm_loader/api/src/api_server/handlers/get_contract.rs b/evm_loader/api/src/api_server/handlers/get_contract.rs new file mode 100644 index 000000000..ab5294196 --- /dev/null +++ b/evm_loader/api/src/api_server/handlers/get_contract.rs @@ -0,0 +1,33 @@ +use crate::api_server::handlers::process_error; +use crate::commands::get_contract as GetContractCommand; +use crate::{api_context, types::GetContractRequest, NeonApiState}; +use actix_request_identifier::RequestId; +use actix_web::post; +use actix_web::web::Json; +use actix_web::{http::StatusCode, Responder}; +use std::convert::Into; + +use super::process_result; + +#[tracing::instrument(skip(state, request_id), fields(id = request_id.as_str()))] +#[post("/contract")] +pub async fn get_contract( + state: NeonApiState, + request_id: RequestId, + Json(req_params): Json, +) -> impl Responder { + let rpc_client = match api_context::build_rpc_client(&state, req_params.slot, None).await { + Ok(rpc_client) => rpc_client, + Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), + }; + + process_result( + &GetContractCommand::execute( + rpc_client.as_ref(), + &state.config.evm_loader, + &req_params.contract, + ) + .await + .map_err(Into::into), + ) +} diff --git a/evm_loader/api/src/api_server/handlers/get_holder.rs b/evm_loader/api/src/api_server/handlers/get_holder.rs new file mode 100644 index 000000000..36385b1a6 --- /dev/null +++ b/evm_loader/api/src/api_server/handlers/get_holder.rs @@ -0,0 +1,33 @@ +use crate::api_server::handlers::process_error; +use crate::commands::get_holder as GetHolderCommand; +use crate::{api_context, types::GetHolderRequest, NeonApiState}; +use actix_request_identifier::RequestId; +use actix_web::post; +use actix_web::web::Json; +use actix_web::{http::StatusCode, Responder}; +use std::convert::Into; + +use super::process_result; + +#[tracing::instrument(skip(state, request_id), fields(id = request_id.as_str()))] +#[post("/holder")] +pub async fn get_holder_account_data( + state: NeonApiState, + request_id: RequestId, + Json(req_params): Json, +) -> impl Responder { + let rpc_client = match api_context::build_rpc_client(&state, req_params.slot, None).await { + Ok(rpc_client) => rpc_client, + Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), + }; + + process_result( + &GetHolderCommand::execute( + rpc_client.as_ref(), + &state.config.evm_loader, + req_params.pubkey, + ) + .await + .map_err(Into::into), + ) +} diff --git a/evm_loader/api/src/api_server/handlers/get_storage_at.rs b/evm_loader/api/src/api_server/handlers/get_storage_at.rs index 7e3d36d2a..71440e49b 100644 --- a/evm_loader/api/src/api_server/handlers/get_storage_at.rs +++ b/evm_loader/api/src/api_server/handlers/get_storage_at.rs @@ -1,9 +1,9 @@ use crate::api_server::handlers::process_error; -use crate::{ - api_context, context::Context, types::request_models::GetStorageAtRequest, NeonApiState, -}; +use crate::{api_context, types::GetStorageAtRequest, NeonApiState}; use actix_request_identifier::RequestId; -use actix_web::{get, http::StatusCode, web::Query, Responder}; +use actix_web::post; +use actix_web::web::Json; +use actix_web::{http::StatusCode, Responder}; use std::convert::Into; use crate::commands::get_storage_at as GetStorageAtCommand; @@ -11,25 +11,23 @@ use crate::commands::get_storage_at as GetStorageAtCommand; use super::process_result; #[tracing::instrument(skip(state, request_id), fields(id = request_id.as_str()))] -#[get("/get-storage-at")] +#[post("/storage")] pub async fn get_storage_at( state: NeonApiState, request_id: RequestId, - Query(req_params): Query, + Json(req_params): Json, ) -> impl Responder { let rpc_client = match api_context::build_rpc_client(&state, req_params.slot, None).await { Ok(rpc_client) => rpc_client, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; - let context = Context::new(&*rpc_client, &state.config); - process_result( &GetStorageAtCommand::execute( - context.rpc_client, + rpc_client.as_ref(), &state.config.evm_loader, - req_params.contract_id, - &req_params.index, + req_params.contract, + req_params.index, ) .await .map_err(Into::into), diff --git a/evm_loader/api/src/api_server/handlers/mod.rs b/evm_loader/api/src/api_server/handlers/mod.rs index 65b631bde..a54447a0c 100644 --- a/evm_loader/api/src/api_server/handlers/mod.rs +++ b/evm_loader/api/src/api_server/handlers/mod.rs @@ -1,22 +1,20 @@ use actix_web::http::StatusCode; use actix_web::web::Json; -use evm_loader::types::Address; use serde::Serialize; use serde_json::{json, Value}; -use solana_sdk::pubkey::Pubkey; -use crate::commands::get_neon_elf::CachedElfParams; use crate::errors::NeonError; -use crate::{Config, Context, NeonApiResult}; +use crate::NeonApiResult; -use crate::types::request_models::EmulationParamsRequestModel; use std::net::AddrParseError; -use std::str::FromStr; use tracing::error; pub mod build_info; pub mod emulate; -pub mod get_ether_account_data; +pub mod get_balance; +pub mod get_config; +pub mod get_contract; +pub mod get_holder; pub mod get_storage_at; pub mod trace; @@ -47,52 +45,6 @@ impl From for NeonApiError { } } -pub(crate) async fn parse_emulation_params( - config: &Config, - context: &Context<'_>, - params: &EmulationParamsRequestModel, -) -> (Pubkey, u64, u64, Vec
, Vec) { - // Read ELF params only if token_mint or chain_id is not set. - let mut token: Option = params.token_mint.map(Into::into); - let mut chain = params.chain_id; - if token.is_none() || chain.is_none() { - let cached_elf_params = CachedElfParams::new(config, context).await; - token = token.or_else(|| { - Some( - Pubkey::from_str( - cached_elf_params - .get("NEON_TOKEN_MINT") - .expect("NEON_TOKEN_MINT load error"), - ) - .expect("NEON_TOKEN_MINT Pubkey ctor error "), - ) - }); - chain = chain.or_else(|| { - Some( - u64::from_str( - cached_elf_params - .get("NEON_CHAIN_ID") - .expect("NEON_CHAIN_ID load error"), - ) - .expect("NEON_CHAIN_ID u64 ctor error"), - ) - }); - } - let token = token.expect("token_mint get error"); - let chain = chain.expect("chain_id get error"); - let max_steps = params.max_steps_to_execute; - - let accounts = params.cached_accounts.clone().unwrap_or_default(); - - let solana_accounts = params - .solana_accounts - .clone() - .map(|vec| vec.into_iter().map(Into::into).collect()) - .unwrap_or_default(); - - (token, chain, max_steps, accounts, solana_accounts) -} - fn process_result( result: &NeonApiResult, ) -> (Json, StatusCode) { diff --git a/evm_loader/api/src/api_server/handlers/trace.rs b/evm_loader/api/src/api_server/handlers/trace.rs index 1a707b8b5..586811a56 100644 --- a/evm_loader/api/src/api_server/handlers/trace.rs +++ b/evm_loader/api/src/api_server/handlers/trace.rs @@ -4,53 +4,30 @@ use std::convert::Into; use crate::api_server::handlers::process_error; use crate::commands::trace::trace_transaction; -use crate::{ - api_context, context::Context, types::request_models::TraceRequestModel, NeonApiState, -}; +use crate::{api_context, types::EmulateApiRequest, NeonApiState}; -use super::{parse_emulation_params, process_result}; +use super::process_result; #[tracing::instrument(skip(state, request_id), fields(id = request_id.as_str()))] #[post("/trace")] pub async fn trace( state: NeonApiState, request_id: RequestId, - Json(trace_request): Json, + Json(trace_request): Json, ) -> impl Responder { - let tx = trace_request.emulate_request.tx_params.into(); + let slot = trace_request.slot; + let index = trace_request.tx_index_in_block; - let rpc_client = match api_context::build_rpc_client( - &state, - trace_request.emulate_request.slot, - trace_request.emulate_request.tx_index_in_block, - ) - .await - { + let rpc_client = match api_context::build_rpc_client(&state, slot, index).await { Ok(rpc_client) => rpc_client, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; - let context = Context::new(&*rpc_client, &state.config); - - let (token, chain, steps, accounts, solana_accounts) = parse_emulation_params( - &state.config, - &context, - &trace_request.emulate_request.emulation_params, - ) - .await; - process_result( &trace_transaction( - context.rpc_client, + rpc_client.as_ref(), state.config.evm_loader, - tx, - token, - chain, - steps, - state.config.commitment, - &accounts, - &solana_accounts, - trace_request.trace_call_config.unwrap_or_default(), + trace_request.body, ) .await .map_err(Into::into), diff --git a/evm_loader/api/src/main.rs b/evm_loader/api/src/main.rs index fd0fad5a4..5aebb4978 100644 --- a/evm_loader/api/src/main.rs +++ b/evm_loader/api/src/main.rs @@ -23,7 +23,10 @@ use std::{env, net::SocketAddr, str::FromStr}; use crate::api_server::handlers::build_info::build_info_route; use crate::api_server::handlers::emulate::emulate; -use crate::api_server::handlers::get_ether_account_data::get_ether_account_data; +use crate::api_server::handlers::get_balance::get_balance; +use crate::api_server::handlers::get_config::get_config; +use crate::api_server::handlers::get_contract::get_contract; +use crate::api_server::handlers::get_holder::get_holder_account_data; use crate::api_server::handlers::get_storage_at::get_storage_at; use crate::api_server::handlers::trace::trace; use crate::build_info::get_build_info; @@ -69,8 +72,11 @@ async fn main() -> NeonApiResult<()> { .app_data(state.clone()) .service(build_info_route) .service(emulate) - .service(get_ether_account_data) + .service(get_balance) + .service(get_contract) .service(get_storage_at) + .service(get_config) + .service(get_holder_account_data) .service(trace) .wrap(RequestIdentifier::with_uuid()), ) diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index 0f8875b91..81ae9af1a 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -1,18 +1,23 @@ -pub mod request_models; pub mod tracer_ch_common; mod tracer_ch_db; pub use evm_loader::types::Address; +use evm_loader::types::{StorageKey, Transaction}; +use evm_loader::{ + account_storage::AccountStorage, + types::{AccessListTx, LegacyTx, TransactionPayload}, +}; +use serde_with::skip_serializing_none; use solana_sdk::pubkey::Pubkey; -use std::str::FromStr; pub use tracer_ch_db::ClickHouseDb as TracerDb; use evm_loader::evm::tracing::TraceCallConfig; -use evm_loader::types::hexbytes::HexBytes; -use { - ethnum::U256, - serde::{Deserialize, Deserializer, Serialize, Serializer}, -}; + +use ethnum::U256; +use serde::{Deserialize, Serialize}; +use serde_with::{hex::Hex, serde_as, DisplayFromStr, OneOrMany}; + +use crate::commands::get_config::ChainInfo; #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone, Default)] pub struct ChDbConfig { @@ -21,89 +26,158 @@ pub struct ChDbConfig { pub clickhouse_password: Option, } +#[serde_as] #[derive(Clone, Serialize, Deserialize, Debug)] pub struct AccessListItem { pub address: Address, - pub storage_keys: Vec, + #[serde(rename = "storageKeys")] + #[serde_as(as = "Vec")] + pub storage_keys: Vec, } -#[derive(Clone, Serialize, Deserialize, Debug)] +#[serde_as] +#[skip_serializing_none] +#[derive(Clone, Serialize, Deserialize)] pub struct TxParams { pub nonce: Option, pub from: Address, pub to: Option
, + #[serde_as(as = "Option")] pub data: Option>, pub value: Option, pub gas_limit: Option, pub gas_price: Option, pub access_list: Option>, + pub chain_id: Option, +} + +impl TxParams { + pub async fn into_transaction(self, backend: &impl AccountStorage) -> (Address, Transaction) { + let chain_id = self.chain_id.unwrap_or_else(|| backend.default_chain_id()); + + let origin_nonce = backend.nonce(self.from, chain_id).await; + let nonce = self.nonce.unwrap_or(origin_nonce); + + let payload = if let Some(access_list) = self.access_list { + let access_list: Vec<_> = access_list + .into_iter() + .map(|a| (a.address, a.storage_keys)) + .collect(); + + let access_list_tx = AccessListTx { + nonce, + gas_price: U256::ZERO, + gas_limit: self.gas_limit.unwrap_or(U256::MAX), + target: self.to, + value: self.value.unwrap_or_default(), + call_data: self.data.unwrap_or_default(), + chain_id: U256::from(chain_id), + access_list, + r: U256::ZERO, + s: U256::ZERO, + recovery_id: 0, + }; + TransactionPayload::AccessList(access_list_tx) + } else { + let legacy_tx = LegacyTx { + nonce, + gas_price: U256::ZERO, + gas_limit: self.gas_limit.unwrap_or(U256::MAX), + target: self.to, + value: self.value.unwrap_or_default(), + call_data: self.data.unwrap_or_default(), + chain_id: self.chain_id.map(U256::from), + v: U256::ZERO, + r: U256::ZERO, + s: U256::ZERO, + recovery_id: 0, + }; + TransactionPayload::Legacy(legacy_tx) + }; + + let tx = Transaction { + transaction: payload, + byte_len: 0, + hash: [0; 32], + signed_hash: [0; 32], + }; + + (self.from, tx) + } +} + +impl std::fmt::Debug for TxParams { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let json = serde_json::to_string(self).map_err(|_| std::fmt::Error)?; + + f.write_str(&json) + } } +#[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct TransactionParams { - pub data: Option, +pub struct EmulateRequest { + pub tx: TxParams, + pub step_limit: Option, + pub chains: Option>, pub trace_config: Option, + #[serde_as(as = "Vec")] + pub accounts: Vec, } -#[derive(Debug, Default, Clone, Copy)] -pub struct PubkeyBase58(pub Pubkey); +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct EmulateApiRequest { + #[serde(flatten)] + pub body: EmulateRequest, + pub slot: Option, + pub tx_index_in_block: Option, +} -impl AsRef for PubkeyBase58 { - fn as_ref(&self) -> &Pubkey { - &self.0 - } +#[derive(Deserialize, Serialize, Debug, Default)] +pub struct BalanceAddress { + pub address: Address, + pub chain_id: u64, } -impl From for PubkeyBase58 { - fn from(value: Pubkey) -> Self { - Self(value) +impl BalanceAddress { + pub fn find_pubkey(&self, program_id: &Pubkey) -> Pubkey { + self.address + .find_balance_address(program_id, self.chain_id) + .0 } -} -impl From<&Pubkey> for PubkeyBase58 { - fn from(value: &Pubkey) -> Self { - Self(*value) + pub fn find_contract_pubkey(&self, program_id: &Pubkey) -> Pubkey { + self.address.find_solana_address(program_id).0 } } -impl From for Pubkey { - fn from(value: PubkeyBase58) -> Self { - value.0 - } +#[serde_as] +#[derive(Deserialize, Debug, Default)] +pub struct GetBalanceRequest { + #[serde_as(as = "OneOrMany<_>")] + pub account: Vec, + pub slot: Option, } -impl Serialize for PubkeyBase58 { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let bs58 = bs58::encode(&self.0).into_string(); - serializer.serialize_str(&bs58) - } +#[serde_as] +#[derive(Deserialize, Debug, Default)] +pub struct GetContractRequest { + #[serde_as(as = "OneOrMany<_>")] + pub contract: Vec
, + pub slot: Option, } -impl<'de> Deserialize<'de> for PubkeyBase58 { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct StringVisitor; - - impl<'de> serde::de::Visitor<'de> for StringVisitor { - type Value = Pubkey; - - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("a string containing json data") - } - - fn visit_str(self, v: &str) -> Result - where - E: serde::de::Error, - { - Pubkey::from_str(v).map_err(E::custom) - } - } - - deserializer.deserialize_any(StringVisitor).map(Self) - } +#[derive(Deserialize, Debug, Default)] +pub struct GetStorageAtRequest { + pub contract: Address, + pub index: U256, + pub slot: Option, +} + +#[serde_as] +#[derive(Deserialize, Serialize, Debug, Default)] +pub struct GetHolderRequest { + #[serde_as(as = "DisplayFromStr")] + pub pubkey: Pubkey, + pub slot: Option, } diff --git a/evm_loader/lib/src/types/request_models.rs b/evm_loader/lib/src/types/request_models.rs deleted file mode 100644 index 31b07648f..000000000 --- a/evm_loader/lib/src/types/request_models.rs +++ /dev/null @@ -1,115 +0,0 @@ -use crate::types::{PubkeyBase58, TxParams}; -use ethnum::U256; -use evm_loader::evm::tracing::TraceCallConfig; -use evm_loader::types::Address; -use serde::{Deserialize, Serialize}; -use solana_sdk::debug_account_data::debug_account_data; -use solana_sdk::pubkey::Pubkey; -use std::fmt; - -use super::AccessListItem; - -#[derive(Deserialize, Serialize, Debug, Default)] -pub struct GetEtherRequest { - pub ether: Address, - pub slot: Option, -} - -#[derive(Deserialize, Serialize, Debug, Default)] -pub struct GetStorageAtRequest { - pub contract_id: Address, - pub index: U256, - pub slot: Option, -} - -#[derive(Deserialize, Serialize, Default)] -pub struct TxParamsRequestModel { - pub sender: Address, - pub contract: Option
, - pub data: Option>, - pub value: Option, - pub gas_limit: Option, - pub gas_price: Option, - pub access_list: Option>, -} - -impl fmt::Debug for TxParamsRequestModel { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut f = f.debug_struct("TxParamsRequestModel"); - - f.field("sender", &self.sender) - .field("contract", &self.contract); - - if let Some(data) = &self.data { - debug_account_data(&data[..], &mut f); - } - - f.field("value", &self.value) - .field("gas_limit", &self.gas_limit) - .field("access_list", &self.access_list) - .finish_non_exhaustive() - } -} - -impl From for TxParams { - fn from(model: TxParamsRequestModel) -> Self { - Self { - nonce: None, - from: model.sender, - to: model.contract, - data: model.data, - value: model.value, - gas_limit: model.gas_limit, - gas_price: model.gas_price, - access_list: model.access_list, - } - } -} - -#[derive(Deserialize, Serialize, Debug, Default)] -pub struct EmulationParamsRequestModel { - pub token_mint: Option, - pub chain_id: Option, - pub max_steps_to_execute: u64, - pub cached_accounts: Option>, - pub solana_accounts: Option>, -} - -impl EmulationParamsRequestModel { - #[allow(unused)] - pub fn new( - token_mint: Option, - chain_id: Option, - max_steps_to_execute: u64, - cached_accounts: Option>, - solana_accounts: Option>, - ) -> EmulationParamsRequestModel { - let token_mint = token_mint.map(Into::into); - let solana_accounts = solana_accounts.map(|vec| vec.into_iter().map(Into::into).collect()); - - Self { - token_mint, - chain_id, - max_steps_to_execute, - cached_accounts, - solana_accounts, - } - } -} - -#[derive(Deserialize, Serialize, Debug, Default)] -pub struct EmulateRequestModel { - #[serde(flatten)] - pub tx_params: TxParamsRequestModel, - #[serde(flatten)] - pub emulation_params: EmulationParamsRequestModel, - pub slot: Option, - pub tx_index_in_block: Option, -} - -#[derive(Deserialize, Serialize, Debug, Default)] -pub struct TraceRequestModel { - #[serde(flatten)] - pub emulate_request: EmulateRequestModel, - pub trace_call_config: Option, -} From fa467c0ecf7a647e26d98b4d6ca3be0ae6b35f83 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Tue, 14 Nov 2023 18:18:57 +0300 Subject: [PATCH 056/318] [Multi Tokens] Misc NeonAPI changes --- evm_loader/lib/src/errors.rs | 21 +++++++++++ evm_loader/lib/src/rpc/db_call_client.rs | 35 ++++++++++++++---- evm_loader/lib/src/rpc/mod.rs | 16 +++++++-- evm_loader/lib/src/rpc/validator_client.rs | 42 +++++++++++++++++++--- evm_loader/lib/src/syscall_stubs.rs | 19 +++++++--- 5 files changed, 115 insertions(+), 18 deletions(-) diff --git a/evm_loader/lib/src/errors.rs b/evm_loader/lib/src/errors.rs index d8c20a32e..3d21114c1 100644 --- a/evm_loader/lib/src/errors.rs +++ b/evm_loader/lib/src/errors.rs @@ -1,7 +1,9 @@ //! Error types #![allow(clippy::use_self)] +use std::array::TryFromSliceError; use std::net::AddrParseError; +use std::string::FromUtf8Error; use log::error; use solana_cli::cli::CliError as SolanaCliError; @@ -10,6 +12,7 @@ use solana_client::tpu_client::TpuSenderError as SolanaTpuSenderError; use solana_sdk::program_error::ProgramError as SolanaProgramError; use solana_sdk::pubkey::{Pubkey, PubkeyError as SolanaPubkeyError}; use solana_sdk::signer::SignerError as SolanaSignerError; +use solana_sdk::transaction::TransactionError; use thiserror::Error; use crate::commands::init_environment::EnvironmentError; @@ -97,6 +100,18 @@ pub enum NeonError { ClickHouse(ChError), #[error("Slot {0} is less than earliest_rooted_slot={1}")] EarlySlot(u64, u64), + #[error("Json Error. {0}")] + SerdeJson(#[from] serde_json::Error), + #[error("BanksClient Error. {0}")] + BanksClientError(#[from] Box), + #[error("Transaction Error. {0}")] + TransactionError(#[from] TransactionError), + #[error("Bincode Error. {0}")] + BincodeError(#[from] bincode::Error), + #[error("FromUtf8 Error. {0}")] + FromUtf8Error(#[from] FromUtf8Error), + #[error("TryFromSlice Error. {0}")] + TryFromSliceError(#[from] TryFromSliceError), } impl NeonError { @@ -132,6 +147,12 @@ impl NeonError { NeonError::TxParametersParsingError(_) => 250, NeonError::ClickHouse(_) => 252, NeonError::EarlySlot(_, _) => 253, + NeonError::SerdeJson(_) => 254, + NeonError::BanksClientError(_) => 255, + NeonError::TransactionError(_) => 256, + NeonError::BincodeError(_) => 257, + NeonError::FromUtf8Error(_) => 258, + NeonError::TryFromSliceError(_) => 259, } } } diff --git a/evm_loader/lib/src/rpc/db_call_client.rs b/evm_loader/lib/src/rpc/db_call_client.rs index aa3e9ab74..4db00cd22 100644 --- a/evm_loader/lib/src/rpc/db_call_client.rs +++ b/evm_loader/lib/src/rpc/db_call_client.rs @@ -6,13 +6,14 @@ use solana_client::{ client_error::Result as ClientResult, client_error::{ClientError, ClientErrorKind}, rpc_config::{RpcSendTransactionConfig, RpcTransactionConfig}, - rpc_response::{Response, RpcResponseContext, RpcResult}, + rpc_response::{Response, RpcResponseContext, RpcResult, RpcSimulateTransactionResult}, }; use solana_sdk::{ account::Account, clock::{Slot, UnixTimestamp}, commitment_config::CommitmentConfig, hash::Hash, + instruction::Instruction, pubkey::Pubkey, signature::Signature, transaction::Transaction, @@ -67,12 +68,9 @@ impl Rpc for CallDbClient { )) } - async fn get_account(&self, key: &Pubkey) -> ClientResult { - self.tracer_db - .get_account_at(key, self.slot, self.tx_index_in_block) + async fn get_account(&self, key: &Pubkey) -> RpcResult> { + self.get_account_with_commitment(key, self.commitment()) .await - .map_err(|e| e!("load account error", key, e))? - .ok_or_else(|| e!("account not found", key)) } async fn get_account_with_commitment( @@ -113,7 +111,12 @@ impl Rpc for CallDbClient { } async fn get_account_data(&self, key: &Pubkey) -> ClientResult> { - Ok(self.get_account(key).await?.data) + let response = self.get_account(key).await?; + if let Some(account) = response.value { + Ok(account.data) + } else { + Ok(Vec::new()) + } } async fn get_block(&self, _slot: Slot) -> ClientResult { @@ -201,6 +204,24 @@ impl Rpc for CallDbClient { )) } + fn can_simulate_transaction(&self) -> bool { + false + } + + async fn simulate_transaction( + &self, + _signer: Option, + _instructions: &[Instruction], + ) -> RpcResult { + Err(e!( + "simulate_transaction() not implemented for db_call_client" + )) + } + + async fn identity(&self) -> ClientResult { + Err(e!("identity() not implemented for db_call_client")) + } + fn as_any(&self) -> &dyn Any { self } diff --git a/evm_loader/lib/src/rpc/mod.rs b/evm_loader/lib/src/rpc/mod.rs index 30690ff19..8a23bb5dd 100644 --- a/evm_loader/lib/src/rpc/mod.rs +++ b/evm_loader/lib/src/rpc/mod.rs @@ -10,9 +10,8 @@ use solana_client::{ client_error::Result as ClientResult, nonblocking::rpc_client::RpcClient, rpc_config::{RpcSendTransactionConfig, RpcTransactionConfig}, - rpc_response::RpcResult, + rpc_response::{RpcResult, RpcSimulateTransactionResult}, }; -use solana_sdk::message::Message; use solana_sdk::native_token::lamports_to_sol; use solana_sdk::{ account::Account, @@ -23,6 +22,7 @@ use solana_sdk::{ signature::Signature, transaction::Transaction, }; +use solana_sdk::{instruction::Instruction, message::Message}; use solana_transaction_status::{ EncodedConfirmedBlock, EncodedConfirmedTransactionWithStatusMeta, TransactionStatus, }; @@ -37,7 +37,7 @@ pub trait Rpc { recent_blockhash: &Hash, commitment_config: CommitmentConfig, ) -> ClientResult<()>; - async fn get_account(&self, key: &Pubkey) -> ClientResult; + async fn get_account(&self, key: &Pubkey) -> RpcResult>; async fn get_account_with_commitment( &self, key: &Pubkey, @@ -81,6 +81,16 @@ pub trait Rpc { commitment: CommitmentConfig, ) -> ClientResult<(Hash, u64)>; + fn can_simulate_transaction(&self) -> bool; + + async fn simulate_transaction( + &self, + signer: Option, + instructions: &[Instruction], + ) -> RpcResult; + + async fn identity(&self) -> ClientResult; + fn as_any(&self) -> &dyn Any; } diff --git a/evm_loader/lib/src/rpc/validator_client.rs b/evm_loader/lib/src/rpc/validator_client.rs index 727698d83..48872c8e7 100644 --- a/evm_loader/lib/src/rpc/validator_client.rs +++ b/evm_loader/lib/src/rpc/validator_client.rs @@ -3,14 +3,15 @@ use async_trait::async_trait; use solana_client::{ client_error::Result as ClientResult, nonblocking::rpc_client::RpcClient, - rpc_config::{RpcSendTransactionConfig, RpcTransactionConfig}, - rpc_response::RpcResult, + rpc_config::{RpcSendTransactionConfig, RpcSimulateTransactionConfig, RpcTransactionConfig}, + rpc_response::{RpcResult, RpcSimulateTransactionResult}, }; use solana_sdk::{ account::Account, clock::{Slot, UnixTimestamp}, commitment_config::CommitmentConfig, hash::Hash, + instruction::Instruction, pubkey::Pubkey, signature::Signature, transaction::Transaction, @@ -36,8 +37,9 @@ impl Rpc for RpcClient { .await } - async fn get_account(&self, key: &Pubkey) -> ClientResult { - self.get_account(key).await + async fn get_account(&self, key: &Pubkey) -> RpcResult> { + self.get_account_with_commitment(key, self.commitment()) + .await } async fn get_account_with_commitment( @@ -132,6 +134,38 @@ impl Rpc for RpcClient { self.get_latest_blockhash_with_commitment(commitment).await } + fn can_simulate_transaction(&self) -> bool { + true + } + + async fn simulate_transaction( + &self, + signer: Option, + instructions: &[Instruction], + ) -> RpcResult { + let payer_pubkey = if let Some(signer) = signer { + signer + } else { + self.get_identity().await? + }; + + let tx = Transaction::new_with_payer(instructions, Some(&payer_pubkey)); + + self.simulate_transaction_with_config( + &tx, + RpcSimulateTransactionConfig { + sig_verify: false, + replace_recent_blockhash: true, + ..RpcSimulateTransactionConfig::default() + }, + ) + .await + } + + async fn identity(&self) -> ClientResult { + self.get_identity().await + } + fn as_any(&self) -> &dyn Any { self } diff --git a/evm_loader/lib/src/syscall_stubs.rs b/evm_loader/lib/src/syscall_stubs.rs index 3a724fb3b..37aa81852 100644 --- a/evm_loader/lib/src/syscall_stubs.rs +++ b/evm_loader/lib/src/syscall_stubs.rs @@ -3,12 +3,16 @@ use solana_sdk::{program_error::ProgramError, program_stubs::SyscallStubs, sysva use crate::{errors::NeonError, rpc::Rpc}; -pub struct Stubs { +pub struct DefaultStubs; + +impl SyscallStubs for DefaultStubs {} + +pub struct EmulatorStubs { rent: Rent, } -impl Stubs { - pub async fn new(rpc_client: &dyn Rpc) -> Result, NeonError> { +impl EmulatorStubs { + pub async fn new(rpc_client: &dyn Rpc) -> Result, NeonError> { let rent_pubkey = solana_sdk::sysvar::rent::id(); let data = rpc_client.get_account_data(&rent_pubkey).await?; let rent = bincode::deserialize(&data).map_err(|_| ProgramError::InvalidArgument)?; @@ -17,7 +21,7 @@ impl Stubs { } } -impl SyscallStubs for Stubs { +impl SyscallStubs for EmulatorStubs { fn sol_get_rent_sysvar(&self, pointer: *mut u8) -> u64 { unsafe { #[allow(clippy::cast_ptr_alignment)] @@ -46,3 +50,10 @@ impl SyscallStubs for Stubs { info!("Program Data: {}", messages.join(" ")); } } + +pub async fn setup_emulator_syscall_stubs(rpc_client: &dyn Rpc) -> Result<(), NeonError> { + let syscall_stubs = EmulatorStubs::new(rpc_client).await?; + solana_sdk::program_stubs::set_syscall_stubs(syscall_stubs); + + Ok(()) +} From 5cfc53df8717192bb4e81374dbad5b5c73d86c46 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Tue, 14 Nov 2023 18:22:18 +0300 Subject: [PATCH 057/318] [Multi Tokens] NeonCLI interface --- evm_loader/cli/src/logs.rs | 11 +- evm_loader/cli/src/main.rs | 236 +++++--------------------- evm_loader/cli/src/program_options.rs | 205 ++++++---------------- 3 files changed, 100 insertions(+), 352 deletions(-) diff --git a/evm_loader/cli/src/logs.rs b/evm_loader/cli/src/logs.rs index 91c2d2a99..500b2ae6b 100644 --- a/evm_loader/cli/src/logs.rs +++ b/evm_loader/cli/src/logs.rs @@ -29,13 +29,16 @@ pub fn init(options: &ArgMatches) -> Result<(), log::SetLoggerError> { fern::Dispatch::new() .filter(move |metadata| { - let target = metadata.target(); + const MODULES: [&str; 3] = ["neon_cli", "neon_lib", "evm_loader"]; - if target.starts_with("neon_cli") || target.starts_with("evm_loader") { - return metadata.level().to_level_filter() <= log_level; + let target = metadata.target(); + for module in MODULES { + if target.starts_with(module) { + return metadata.level().to_level_filter() <= log_level; + } } - metadata.level() <= log::Level::Warn + metadata.level() <= log::Level::Error }) .chain(fern::Output::call(|record| { let file: &str = record.file().unwrap_or("undefined"); diff --git a/evm_loader/cli/src/main.rs b/evm_loader/cli/src/main.rs index e810915f2..73b12a703 100644 --- a/evm_loader/cli/src/main.rs +++ b/evm_loader/cli/src/main.rs @@ -9,13 +9,11 @@ mod program_options; use neon_lib::{ commands::{ - cancel_trx, collect_treasury, create_ether_account, deposit, emulate, - get_ether_account_data, get_neon_elf, get_neon_elf::CachedElfParams, get_storage_at, - init_environment, trace, + cancel_trx, collect_treasury, emulate, get_balance, get_config, get_contract, get_holder, + get_neon_elf, get_storage_at, init_environment, trace, }, errors, rpc, - types::{self, AccessListItem}, - Context, + types::{BalanceAddress, EmulateRequest}, }; use clap::ArgMatches; @@ -23,23 +21,17 @@ pub use config::Config; use std::io::Read; use ethnum::U256; -use evm_loader::evm::tracing::TraceCallConfig; use log::debug; use serde_json::json; -use solana_clap_utils::input_parsers::{pubkey_of, value_of, values_of}; +use solana_clap_utils::input_parsers::{pubkey_of, value_of}; use solana_client::nonblocking::rpc_client::RpcClient; -use solana_sdk::pubkey::Pubkey; -use std::str::FromStr; use tokio::time::Instant; pub use neon_lib::context::*; use neon_lib::rpc::CallDbClient; use crate::build_info::get_build_info; -use crate::{ - errors::NeonError, - types::{TransactionParams, TxParams}, -}; +use crate::errors::NeonError; use evm_loader::types::Address; use neon_lib::types::TracerDb; @@ -129,82 +121,41 @@ async fn execute<'a>( context: &'a Context<'_>, ) -> NeonCliResult { match (cmd, params) { - ("emulate", Some(params)) => { - let (tx, trace_call_config) = parse_tx(params); - let (token, chain, steps, accounts, solana_accounts) = - parse_tx_params(config, context, params).await; - emulate::execute( - context.rpc_client, - config.evm_loader, - tx, - token, - chain, - steps, - config.commitment, - &accounts, - &solana_accounts, - &trace_call_config.block_overrides, - trace_call_config.state_overrides, - ) - .await - .map(|result| json!(result)) + ("emulate", Some(_)) => { + let request = read_tx_from_stdin()?; + emulate::execute(context.rpc_client, config.evm_loader, request, None) + .await + .map(|result| json!(result)) } - ("trace", Some(params)) => { - let (tx, trace_call_config) = parse_tx(params); - let (token, chain, steps, accounts, solana_accounts) = - parse_tx_params(config, context, params).await; - trace::trace_transaction( - context.rpc_client, - config.evm_loader, - tx, - token, - chain, - steps, - config.commitment, - &accounts, - &solana_accounts, - trace_call_config, - ) - .await - .map(|trace| json!(trace)) + ("trace", Some(_)) => { + let request = read_tx_from_stdin()?; + trace::trace_transaction(context.rpc_client, config.evm_loader, request) + .await + .map(|trace| json!(trace)) } - ("create-ether-account", Some(params)) => { - let ether = address_of(params, "ether").expect("ether parse error"); - let rpc_client = context - .rpc_client - .as_any() - .downcast_ref::() - .expect("cast to solana_client::nonblocking::rpc_client::RpcClient error"); - create_ether_account::execute( - rpc_client, - config.evm_loader, - context.signer()?.as_ref(), - ðer, - ) - .await - .map(|result| json!(result)) + ("get-ether-account-data", Some(params)) => { + let address = address_of(params, "ether").unwrap(); + let chain_id = value_of(params, "chain_id").unwrap(); + + let account = BalanceAddress { address, chain_id }; + let accounts = std::slice::from_ref(&account); + + get_balance::execute(context.rpc_client, &config.evm_loader, accounts) + .await + .map(|result| json!(result)) } - ("deposit", Some(params)) => { - let rpc_client = context - .rpc_client - .as_any() - .downcast_ref::() - .expect("cast to solana_client::nonblocking::rpc_client::RpcClient error"); - let amount = value_of(params, "amount").expect("amount parse error"); - let ether = address_of(params, "ether").expect("ether parse error"); - deposit::execute( - rpc_client, - config.evm_loader, - context.signer()?.as_ref(), - amount, - ðer, - ) - .await - .map(|result| json!(result)) + ("get-contract-account-data", Some(params)) => { + let account = address_of(params, "address").unwrap(); + let accounts = std::slice::from_ref(&account); + + get_contract::execute(context.rpc_client, &config.evm_loader, accounts) + .await + .map(|result| json!(result)) } - ("get-ether-account-data", Some(params)) => { - let ether = address_of(params, "ether").expect("ether parse error"); - get_ether_account_data::execute(context.rpc_client, &config.evm_loader, ðer) + ("get-holder-account-data", Some(params)) => { + let account = pubkey_of(params, "account").unwrap(); + + get_holder::execute(context.rpc_client, &config.evm_loader, account) .await .map(|result| json!(result)) } @@ -241,98 +192,22 @@ async fn execute<'a>( ("get-storage-at", Some(params)) => { let contract_id = address_of(params, "contract_id").expect("contract_it parse error"); let index = u256_of(params, "index").expect("index parse error"); - get_storage_at::execute(context.rpc_client, &config.evm_loader, contract_id, &index) + get_storage_at::execute(context.rpc_client, &config.evm_loader, contract_id, index) .await .map(|hash| json!(hex::encode(hash.0))) } + ("config", Some(_)) => get_config::execute(context.rpc_client, config.evm_loader) + .await + .map(|result| json!(result)), _ => unreachable!(), } } -fn parse_tx(params: &ArgMatches) -> (TxParams, TraceCallConfig) { - let from = address_of(params, "sender").expect("sender parse error"); - let to = address_or_deploy_of(params, "contract"); - let transaction_params: Option = read_from_stdin().unwrap_or_else(|err| { - panic!("Unable to parse `TransactionParams` from STDIN, error: {err:?}") - }); - let (data, trace_config) = transaction_params - .map(|params| { - ( - params.data.map(Into::into), - params.trace_config.unwrap_or_default(), - ) - }) - .unwrap_or_default(); - - let value = u256_of(params, "value"); - - let gas_limit = u256_of(params, "gas_limit"); +fn read_tx_from_stdin() -> Result { + let mut stdin_buffer = String::new(); + std::io::stdin().read_to_string(&mut stdin_buffer)?; - let gas_price = u256_of(params, "gas_price"); - - let access_list = access_list_of(params, "access_list"); - - let tx_params = TxParams { - nonce: None, - from, - to, - data, - value, - gas_limit, - gas_price, - access_list, - }; - - (tx_params, trace_config) -} - -pub async fn parse_tx_params<'a>( - config: &Config, - context: &Context<'_>, - params: &'a ArgMatches<'a>, -) -> (Pubkey, u64, u64, Vec
, Vec) { - // Read ELF params only if token_mint or chain_id is not set. - let mut token = pubkey_of(params, "token_mint"); - let mut chain = value_of(params, "chain_id"); - if token.is_none() || chain.is_none() { - let cached_elf_params = CachedElfParams::new(config, context).await; - token = token.or_else(|| { - Some( - Pubkey::from_str( - cached_elf_params - .get("NEON_TOKEN_MINT") - .expect("NEON_TOKEN_MINT load error"), - ) - .expect("NEON_TOKEN_MINT Pubkey ctor error "), - ) - }); - chain = chain.or_else(|| { - Some( - u64::from_str( - cached_elf_params - .get("NEON_CHAIN_ID") - .expect("NEON_CHAIN_ID load error"), - ) - .expect("NEON_CHAIN_ID u64 ctor error"), - ) - }); - } - let token = token.expect("token_mint get error"); - let chain = chain.expect("chain_id get error"); - let max_steps = - value_of::(params, "max_steps_to_execute").expect("max_steps_to_execute parse error"); - - let accounts = values_of::
(params, "cached_accounts").unwrap_or_default(); - let solana_accounts = values_of::(params, "solana_accounts").unwrap_or_default(); - - (token, chain, max_steps, accounts, solana_accounts) -} - -fn address_or_deploy_of(matches: &ArgMatches<'_>, name: &str) -> Option
{ - if matches.value_of(name) == Some("deploy") { - return None; - } - address_of(matches, name) + serde_json::from_str(&stdin_buffer).map_err(NeonError::from) } fn address_of(matches: &ArgMatches<'_>, name: &str) -> Option
{ @@ -341,18 +216,6 @@ fn address_of(matches: &ArgMatches<'_>, name: &str) -> Option
{ .map(|value| Address::from_hex(value).unwrap()) } -fn access_list_of(matches: &ArgMatches<'_>, name: &str) -> Option> { - matches.value_of(name).map(|value| { - let address = Address::from_hex(value).unwrap(); - let keys = vec![]; - let item = AccessListItem { - address, - storage_keys: keys, - }; - vec![item] - }) -} - fn u256_of(matches: &ArgMatches<'_>, name: &str) -> Option { matches.value_of(name).map(|value| { if value.is_empty() { @@ -362,14 +225,3 @@ fn u256_of(matches: &ArgMatches<'_>, name: &str) -> Option { U256::from_str_prefixed(value).unwrap() }) } - -fn read_from_stdin() -> serde_json::Result> { - let mut stdin = String::new(); - std::io::stdin() - .read_to_string(&mut stdin) - .map_err(serde_json::Error::io)?; - if stdin.trim().is_empty() { - return Ok(None); - } - serde_json::from_str(&stdin).map(Some) -} diff --git a/evm_loader/cli/src/program_options.rs b/evm_loader/cli/src/program_options.rs index ce0e2b39f..8da64a1dc 100644 --- a/evm_loader/cli/src/program_options.rs +++ b/evm_loader/cli/src/program_options.rs @@ -14,19 +14,6 @@ where .map_err(|e| e.to_string()) } -// Return an error if string cannot be parsed as a Address address -fn is_valid_address_or_deploy(string: T) -> Result<(), String> -where - T: AsRef, -{ - if string.as_ref() == "deploy" { - return Ok(()); - } - Address::from_hex(string.as_ref()) - .map(|_| ()) - .map_err(|e| e.to_string()) -} - // Return an error if string cannot be parsed as a U256 integer fn is_valid_u256(string: T) -> Result<(), String> where @@ -57,118 +44,6 @@ where } } -fn ether_arg<'a, 'b>(idx: u64) -> Arg<'a, 'b> { - Arg::with_name("ether") - .index(idx) - .value_name("ETHER") - .takes_value(true) - .required(true) - .validator(is_valid_address) - .help("Ethereum address") -} - -fn token_mint_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name("token_mint") - .long("token_mint") - .value_name("TOKEN_MINT") - .takes_value(true) - .global(true) - .validator(is_valid_pubkey) - .help("Pubkey for token_mint") -} - -fn chain_id_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name("chain_id") - .long("chain_id") - .value_name("CHAIN_ID") - .takes_value(true) - .required(false) - .help("Network chain_id") -} - -fn max_steps_arg<'a, 'b>() -> Arg<'a, 'b> { - Arg::with_name("max_steps_to_execute") - .long("max_steps_to_execute") - .value_name("NUMBER_OF_STEPS") - .takes_value(true) - .required(false) - .default_value("100000") - .help("Maximal number of steps to execute in a single run") -} - -fn trx_params<'a, 'b>(cmd: &'static str, desc: &'static str) -> App<'a, 'b> { - SubCommand::with_name(cmd) - .about(desc) - .arg( - Arg::with_name("sender") - .value_name("SENDER") - .takes_value(true) - .index(1) - .required(true) - .validator(is_valid_address) - .help("The sender of the transaction"), - ) - .arg( - Arg::with_name("contract") - .value_name("CONTRACT") - .takes_value(true) - .index(2) - .required(true) - .validator(is_valid_address_or_deploy) - .help("The contract that executes the transaction or 'deploy'"), - ) - .arg( - Arg::with_name("value") - .value_name("VALUE") - .takes_value(true) - .index(3) - .required(false) - .validator(is_valid_u256) - .help("Transaction value"), - ) - .arg(token_mint_arg()) - .arg(chain_id_arg()) - .arg(max_steps_arg()) - .arg( - Arg::with_name("gas_limit") - .short("G") - .long("gas_limit") - .value_name("GAS_LIMIT") - .takes_value(true) - .required(false) - .validator(is_valid_u256) - .help("Gas limit"), - ) - .arg( - Arg::with_name("access_list") - .long("access-list") - .takes_value(true) - .required(false) - .multiple(true) - .value_name("ADDRESS [STORAGE_KEYS ...]"), - ) - .arg( - Arg::with_name("cached_accounts") - .value_name("CACHED_ACCOUNTS") - .long("cached_accounts") - .takes_value(true) - .required(false) - .multiple(true) - .validator(is_valid_address) - .help("List of cached account addresses"), - ) - .arg( - Arg::with_name("solana_accounts") - .value_name("SOLANA_ACCOUNTS") - .long("solana_accounts") - .takes_value(true) - .required(false) - .multiple(true) - .validator(is_valid_address) - .help("List of cached solana account pubkeys"), - ) -} - #[allow(clippy::too_many_lines)] pub fn parse<'a>() -> ArgMatches<'a> { App::new(crate_name!()) @@ -208,15 +83,6 @@ pub fn parse<'a>() -> ArgMatches<'a> { .validator(is_amount::) .help("Slot number to work with archived data"), ) - .arg( - Arg::with_name("verbose") - .short("v") - .long("verbose") - .takes_value(false) - .global(true) - .multiple(true) - .help("Increase message verbosity"), - ) .arg( Arg::with_name("fee_payer") .long("fee-payer") @@ -280,40 +146,63 @@ pub fn parse<'a>() -> ArgMatches<'a> { .help("Logging level"), ) .subcommand( - trx_params( - "emulate", - "Emulation transaction. Additional `TransactionParams` can be provided via STDIN as a JSON object.", - ) + SubCommand::with_name("emulate") + .about("Emulation transaction. Parameters can be provided via STDIN as a JSON object.") ) .subcommand( - trx_params( - "trace", - "Emulation transaction to collecting traces. Additional `TransactionParams` can be provided via STDIN as a JSON object.", - ) + SubCommand::with_name("trace") + .about("Emulation transaction to collecting traces. Parameters can be provided via STDIN as a JSON object.") ) .subcommand( - SubCommand::with_name("create-ether-account") - .about("Create ethereum account") - .arg(ether_arg(1)) + SubCommand::with_name("get-ether-account-data") + .alias("balance") + .about("Get values stored in associated with given address account data") + .arg( + Arg::with_name("ether") + .value_name("ETHER") + .takes_value(true) + .index(1) + .required(true) + .validator(is_valid_address) + .help("Ethereum address") + ) + .arg( + Arg::with_name("chain_id") + .long("chain_id") + .value_name("CHAIN_ID") + .takes_value(true) + .index(2) + .required(true) + .help("Network chain_id") + ) ) .subcommand( - SubCommand::with_name("deposit") - .about("Deposit NEONs to ether account") + SubCommand::with_name("get-contract-account-data") + .alias("contract") + .about("Get values stored in associated with given contract") .arg( - Arg::with_name("amount") - .index(1) - .value_name("AMOUNT") + Arg::with_name("address") + .value_name("ADDRESS") .takes_value(true) + .index(1) .required(true) - .validator(is_amount::) - .help("Amount to deposit"), + .validator(is_valid_address) + .help("Ethereum address") ) - .arg(ether_arg(2)) ) .subcommand( - SubCommand::with_name("get-ether-account-data") - .about("Get values stored in associated with given address account data") - .arg(ether_arg(1)) + SubCommand::with_name("get-holder-account-data") + .alias("holder") + .about("Get values stored in a Holder acount") + .arg( + Arg::with_name("account") + .index(1) + .value_name("ACCOUNT") + .takes_value(true) + .required(true) + .validator(is_valid_pubkey) + .help("Public Key"), + ) ) .subcommand( SubCommand::with_name("cancel-trx") @@ -340,6 +229,10 @@ pub fn parse<'a>() -> ArgMatches<'a> { .help("/path/to/evm_loader.so"), ) ) + .subcommand( + SubCommand::with_name("config") + .about("Read configuration parameters from NeonEVM program.") + ) .subcommand( SubCommand::with_name("collect-treasury") .about("Collect lamports from auxiliary treasury accounts to the main treasury balance") From 446e6629832c6c12fe59768eb68324f9992e9770 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Tue, 14 Nov 2023 18:24:16 +0300 Subject: [PATCH 058/318] [Multi Tokens] Project files --- evm_loader/Cargo.lock | 788 ++++++++++++++++++++++++++-- evm_loader/cli/Cargo.toml | 2 +- evm_loader/lib/Cargo.toml | 9 +- evm_loader/program-macro/Cargo.toml | 7 +- evm_loader/program/Cargo.toml | 3 +- 5 files changed, 756 insertions(+), 53 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 934a9fd7f..4b2ac3410 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -25,7 +25,7 @@ dependencies = [ "memchr", "pin-project-lite", "tokio", - "tokio-util", + "tokio-util 0.7.7", "tracing", ] @@ -63,7 +63,7 @@ dependencies = [ "sha1", "smallvec", "tokio", - "tokio-util", + "tokio-util 0.7.7", "tracing", "zstd 0.12.4", ] @@ -269,13 +269,19 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.20" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab" dependencies = [ "memchr", ] +[[package]] +name = "aliasable" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" + [[package]] name = "alloc-no-stdlib" version = "2.0.4" @@ -338,7 +344,7 @@ dependencies = [ "ark-std", "derivative", "hashbrown 0.13.2", - "itertools", + "itertools 0.10.5", "num-traits", "zeroize", ] @@ -355,7 +361,7 @@ dependencies = [ "ark-std", "derivative", "digest 0.10.7", - "itertools", + "itertools 0.10.5", "num-bigint 0.4.3", "num-traits", "paste", @@ -904,6 +910,27 @@ dependencies = [ "bytes", ] +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "camino" version = "1.1.6" @@ -986,6 +1013,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "chrono-humanize" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799627e6b4d27827a814e837b9d8a504832086081806d45b1afa34dc982b023b" +dependencies = [ + "chrono", +] + [[package]] name = "cipher" version = "0.3.0" @@ -1420,6 +1456,17 @@ dependencies = [ "syn 2.0.28", ] +[[package]] +name = "dashmap" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" +dependencies = [ + "cfg-if", + "num_cpus", + "rayon", +] + [[package]] name = "data-encoding" version = "2.3.3" @@ -1517,6 +1564,15 @@ dependencies = [ "subtle", ] +[[package]] +name = "dir-diff" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2860407d7d7e2e004bb2128510ad9e8d669e76fa005ccf567977b5d71b8b4a0b" +dependencies = [ + "walkdir", +] + [[package]] name = "dirs-next" version = "2.0.0" @@ -1613,6 +1669,18 @@ dependencies = [ "sha2 0.10.6", ] +[[package]] +name = "educe" +version = "0.4.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f0042ff8246a363dbe77d2ceedb073339e85a804b9a47636c6e016a9a32c05f" +dependencies = [ + "enum-ordinalize", + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 1.0.109", +] + [[package]] name = "either" version = "1.8.1" @@ -1654,6 +1722,19 @@ dependencies = [ "syn 2.0.28", ] +[[package]] +name = "enum-ordinalize" +version = "3.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bf1fa3f06bbff1ea5b1a9c7b14aa992a39657db60a2759457328d7e058f49ee" +dependencies = [ + "num-bigint 0.4.3", + "num-traits", + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 2.0.28", +] + [[package]] name = "env_logger" version = "0.9.3" @@ -1711,14 +1792,13 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "evm-loader" -version = "1.5.0-dev" +version = "1.7.0-dev" dependencies = [ "arrayref", "async-trait", "bincode", "borsh 0.9.3", "cfg-if", - "const_format", "ethnum", "evm-loader-macro", "hex", @@ -1743,11 +1823,12 @@ name = "evm-loader-macro" version = "1.0.0" dependencies = [ "bs58", - "itertools", + "itertools 0.11.0", + "proc-macro2 1.0.66", "quote 1.0.32", "serde", "syn 1.0.109", - "toml", + "toml 0.8.0", ] [[package]] @@ -1774,11 +1855,23 @@ dependencies = [ "log", ] +[[package]] +name = "filetime" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.3.5", + "windows-sys 0.48.0", +] + [[package]] name = "flate2" -version = "1.0.25" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" dependencies = [ "crc32fast", "miniz_oxide", @@ -2012,7 +2105,7 @@ dependencies = [ "indexmap 1.9.3", "slab", "tokio", - "tokio-util", + "tokio-util 0.7.7", "tracing", ] @@ -2039,6 +2132,9 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.6", +] [[package]] name = "hashbrown" @@ -2064,6 +2160,12 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -2093,6 +2195,9 @@ name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] [[package]] name = "hidapi" @@ -2289,6 +2394,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "index_list" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a9d968042a4902e08810946fc7cd5851eb75e80301342305af755ca06cb82ce" + [[package]] name = "indexmap" version = "1.9.3" @@ -2297,6 +2408,7 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", + "serde", ] [[package]] @@ -2307,6 +2419,7 @@ checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" dependencies = [ "equivalent", "hashbrown 0.14.0", + "serde", ] [[package]] @@ -2357,6 +2470,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.6" @@ -2552,6 +2674,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "lru" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999beba7b6e8345721bd280141ed958096a2e4abdf74f67ff4ce49b4b54e47a" +dependencies = [ + "hashbrown 0.12.3", +] + [[package]] name = "lz4" version = "1.24.0" @@ -2589,7 +2720,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ - "regex-automata", + "regex-automata 0.1.10", ] [[package]] @@ -2671,9 +2802,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.6.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" dependencies = [ "adler", ] @@ -2690,6 +2821,27 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "modular-bitfield" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a53d79ba8304ac1c4f9eb3b9d281f21f7be9d4626f72ce7df4ad8fbde4f38a74" +dependencies = [ + "modular-bitfield-impl", + "static_assertions", +] + +[[package]] +name = "modular-bitfield-impl" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a7d5f7076603ebc68de2dc6a650ec331a062a13abaa346975be747bbfa4b789" +dependencies = [ + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 1.0.109", +] + [[package]] name = "mpl-token-auth-rules" version = "1.4.3-beta.1" @@ -2804,7 +2956,7 @@ dependencies = [ [[package]] name = "neon-cli" -version = "1.5.0-dev" +version = "1.7.0-dev" dependencies = [ "build-info", "build-info-build", @@ -2830,6 +2982,7 @@ version = "0.1.0" dependencies = [ "anyhow", "async-trait", + "base64 0.21.4", "bincode", "bs58", "build-info", @@ -2844,10 +2997,12 @@ dependencies = [ "scroll", "serde", "serde_json", + "serde_with 3.3.0", "solana-clap-utils", "solana-cli", "solana-cli-config", "solana-client", + "solana-program-test", "solana-sdk", "solana-transaction-status", "spl-associated-token-account 1.1.3", @@ -3156,12 +3311,54 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "opentelemetry" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6105e89802af13fdf48c49d7646d3b533a70e536d818aae7e78ba0433d01acb8" +dependencies = [ + "async-trait", + "crossbeam-channel", + "futures-channel", + "futures-executor", + "futures-util", + "js-sys", + "lazy_static", + "percent-encoding", + "pin-project", + "rand 0.8.5", + "thiserror", +] + [[package]] name = "os_str_bytes" version = "6.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" +[[package]] +name = "ouroboros" +version = "0.15.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1358bd1558bd2a083fed428ffeda486fbfb323e698cdda7794259d592ca72db" +dependencies = [ + "aliasable", + "ouroboros_macro", +] + +[[package]] +name = "ouroboros_macro" +version = "0.15.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f7d21ccd03305a674437ee1248f3ab5d4b1db095cf1caf49f1713ddf61956b7" +dependencies = [ + "Inflector", + "proc-macro-error", + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 1.0.109", +] + [[package]] name = "overload" version = "0.1.1" @@ -3239,6 +3436,26 @@ dependencies = [ "num", ] +[[package]] +name = "pin-project" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +dependencies = [ + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 2.0.28", +] + [[package]] name = "pin-project-lite" version = "0.2.9" @@ -3320,7 +3537,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" dependencies = [ - "toml", + "toml 0.5.11", ] [[package]] @@ -3330,7 +3547,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ "once_cell", - "toml_edit", + "toml_edit 0.19.8", ] [[package]] @@ -3634,13 +3851,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.7.3" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" +checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-automata 0.3.7", + "regex-syntax 0.7.5", ] [[package]] @@ -3649,7 +3867,18 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" dependencies = [ - "regex-syntax", + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.7.5", ] [[package]] @@ -3658,6 +3887,12 @@ version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" +[[package]] +name = "regex-syntax" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" + [[package]] name = "reqwest" version = "0.11.20" @@ -3689,7 +3924,7 @@ dependencies = [ "serde_urlencoded", "tokio", "tokio-rustls 0.24.1", - "tokio-util", + "tokio-util 0.7.7", "tower-service", "url", "wasm-bindgen", @@ -3893,6 +4128,15 @@ version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schannel" version = "0.1.21" @@ -3950,7 +4194,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b5e421024b5e5edfbaa8e60ecf90bda9dbffc602dbb230e6028763f85f0c68c" dependencies = [ - "heck", + "heck 0.3.3", "proc-macro2 1.0.66", "quote 1.0.32", "syn 1.0.109", @@ -4040,6 +4284,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -4059,7 +4312,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe" dependencies = [ "serde", - "serde_with_macros", + "serde_with_macros 2.3.3", +] + +[[package]] +name = "serde_with" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ca3b16a3d82c4088f343b7480a93550b3eabe1a358569c2dfe38bbcead07237" +dependencies = [ + "base64 0.21.4", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.0.0", + "serde", + "serde_json", + "serde_with_macros 3.3.0", + "time 0.3.20", ] [[package]] @@ -4074,6 +4344,18 @@ dependencies = [ "syn 2.0.28", ] +[[package]] +name = "serde_with_macros" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e6be15c453eb305019bfa438b1593c731f36a289a7853f7707ee29e870b3b3c" +dependencies = [ + "darling", + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 2.0.28", +] + [[package]] name = "serde_yaml" version = "0.9.25" @@ -4310,6 +4592,53 @@ dependencies = [ "thiserror", ] +[[package]] +name = "solana-banks-client" +version = "1.16.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f375ffcef8cd5ee12a2324a2e3887c99c54c50f3b9f2bb7a43b23ba13f77fd" +dependencies = [ + "borsh 0.10.3", + "futures", + "solana-banks-interface", + "solana-program", + "solana-sdk", + "tarpc", + "thiserror", + "tokio", + "tokio-serde", +] + +[[package]] +name = "solana-banks-interface" +version = "1.16.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a07ac3b05f89f26f7ff41541f82a53a3252f60f2313bd608da7b59c14fdbc3c2" +dependencies = [ + "serde", + "solana-sdk", + "tarpc", +] + +[[package]] +name = "solana-banks-server" +version = "1.16.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13027d9e0bedf46b921783b7b99ff4c6be6f202546b534ee1132c6e737fe2d78" +dependencies = [ + "bincode", + "crossbeam-channel", + "futures", + "solana-banks-interface", + "solana-client", + "solana-runtime", + "solana-sdk", + "solana-send-transaction-service", + "tarpc", + "tokio", + "tokio-serde", +] + [[package]] name = "solana-bpf-loader-program" version = "1.16.18" @@ -4330,17 +4659,34 @@ dependencies = [ ] [[package]] -name = "solana-clap-utils" +name = "solana-bucket-map" version = "1.16.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe15843171a435eed014e7180f62c0d5e7e8178f7eaf4da0077ea21354506e2a" +checksum = "6d0f77fbc9836e4f87ebf9b92cc5083172bd7eadf050a5255b3276be925f6347" dependencies = [ - "chrono", - "clap 2.34.0", - "rpassword", - "solana-perf", - "solana-remote-wallet", - "solana-sdk", + "bv", + "log", + "memmap2", + "modular-bitfield", + "num_enum 0.6.1", + "rand 0.7.3", + "solana-measure", + "solana-sdk", + "tempfile", +] + +[[package]] +name = "solana-clap-utils" +version = "1.16.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe15843171a435eed014e7180f62c0d5e7e8178f7eaf4da0077ea21354506e2a" +dependencies = [ + "chrono", + "clap 2.34.0", + "rpassword", + "solana-perf", + "solana-remote-wallet", + "solana-sdk", "thiserror", "tiny-bip39", "uriparse", @@ -4474,6 +4820,16 @@ dependencies = [ "tokio", ] +[[package]] +name = "solana-compute-budget-program" +version = "1.16.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14bddd710a43491be07ac493703617290e8781a9bd92fc33fcc9a8e4345928dd" +dependencies = [ + "solana-program-runtime", + "solana-sdk", +] + [[package]] name = "solana-config-program" version = "1.16.18" @@ -4578,6 +4934,20 @@ dependencies = [ "syn 2.0.28", ] +[[package]] +name = "solana-loader-v4-program" +version = "1.16.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5af55ee96c942cf4f3d088621c7a265b1a0a3558fafd0f5851c8637b7e1170a9" +dependencies = [ + "log", + "rand 0.7.3", + "solana-measure", + "solana-program-runtime", + "solana-sdk", + "solana_rbpf", +] + [[package]] name = "solana-logger" version = "1.16.18" @@ -4687,7 +5057,7 @@ dependencies = [ "console_log", "curve25519-dalek", "getrandom 0.2.9", - "itertools", + "itertools 0.10.5", "js-sys", "lazy_static", "libc", @@ -4727,7 +5097,7 @@ dependencies = [ "bincode", "eager", "enum-iterator", - "itertools", + "itertools 0.10.5", "libc", "log", "num-derive 0.3.3", @@ -4745,6 +5115,33 @@ dependencies = [ "thiserror", ] +[[package]] +name = "solana-program-test" +version = "1.16.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2971fc318678d5be14bf33356f0eff69f6d39fd75385d0f33db68d15cb1eb7c8" +dependencies = [ + "assert_matches", + "async-trait", + "base64 0.21.4", + "bincode", + "chrono-humanize", + "crossbeam-channel", + "log", + "serde", + "solana-banks-client", + "solana-banks-interface", + "solana-banks-server", + "solana-bpf-loader-program", + "solana-logger", + "solana-program-runtime", + "solana-runtime", + "solana-sdk", + "solana-vote-program", + "thiserror", + "tokio", +] + [[package]] name = "solana-pubsub-client" version = "1.16.18" @@ -4779,7 +5176,7 @@ dependencies = [ "async-mutex", "async-trait", "futures", - "itertools", + "itertools 0.10.5", "lazy_static", "log", "quinn", @@ -4889,6 +5286,75 @@ dependencies = [ "thiserror", ] +[[package]] +name = "solana-runtime" +version = "1.16.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0da45b4f58bb45ae1d92b5980ddf90bfabc52342eba4d0f5c1ecacab3a87fb2e" +dependencies = [ + "arrayref", + "bincode", + "blake3", + "bv", + "bytemuck", + "byteorder", + "bzip2", + "crossbeam-channel", + "dashmap", + "dir-diff", + "flate2", + "fnv", + "im", + "index_list", + "itertools 0.10.5", + "lazy_static", + "log", + "lru", + "lz4", + "memmap2", + "modular-bitfield", + "num-derive 0.3.3", + "num-traits", + "num_cpus", + "num_enum 0.6.1", + "once_cell", + "ouroboros", + "percentage", + "rand 0.7.3", + "rayon", + "regex", + "rustc_version", + "serde", + "serde_derive", + "solana-address-lookup-table-program", + "solana-bpf-loader-program", + "solana-bucket-map", + "solana-compute-budget-program", + "solana-config-program", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-loader-v4-program", + "solana-measure", + "solana-metrics", + "solana-perf", + "solana-program-runtime", + "solana-rayon-threadlimit", + "solana-sdk", + "solana-stake-program", + "solana-system-program", + "solana-vote-program", + "solana-zk-token-proof-program", + "solana-zk-token-sdk", + "static_assertions", + "strum", + "strum_macros", + "symlink", + "tar", + "tempfile", + "thiserror", + "zstd 0.11.2+zstd.1.5.2", +] + [[package]] name = "solana-sdk" version = "1.16.18" @@ -4910,7 +5376,7 @@ dependencies = [ "ed25519-dalek-bip32", "generic-array", "hmac 0.12.1", - "itertools", + "itertools 0.10.5", "js-sys", "lazy_static", "libsecp256k1", @@ -4929,7 +5395,7 @@ dependencies = [ "serde_bytes", "serde_derive", "serde_json", - "serde_with", + "serde_with 2.3.3", "sha2 0.10.6", "sha3 0.10.7", "solana-frozen-abi", @@ -4955,6 +5421,37 @@ dependencies = [ "syn 2.0.28", ] +[[package]] +name = "solana-send-transaction-service" +version = "1.16.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e41bc95062870f354eb1e66b7eec5f00cea3d1769fc887b6631b35ddff70db7" +dependencies = [ + "crossbeam-channel", + "log", + "solana-client", + "solana-measure", + "solana-metrics", + "solana-runtime", + "solana-sdk", + "solana-tpu-client", +] + +[[package]] +name = "solana-stake-program" +version = "1.16.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b127ba7a3419335051e84ed6d46c1597a6eeaa741831e25e6f0588c72a6e3cc2" +dependencies = [ + "bincode", + "log", + "rustc_version", + "solana-config-program", + "solana-program-runtime", + "solana-sdk", + "solana-vote-program", +] + [[package]] name = "solana-streamer" version = "1.16.18" @@ -4967,7 +5464,7 @@ dependencies = [ "futures-util", "histogram", "indexmap 1.9.3", - "itertools", + "itertools 0.10.5", "libc", "log", "nix 0.26.2", @@ -4988,6 +5485,20 @@ dependencies = [ "x509-parser", ] +[[package]] +name = "solana-system-program" +version = "1.16.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "599877167e03e4da09e2eff42efed7720615d1f2f5e8b9c52a057dc1d7067ee4" +dependencies = [ + "bincode", + "log", + "serde", + "serde_derive", + "solana-program-runtime", + "solana-sdk", +] + [[package]] name = "solana-thin-client" version = "1.16.18" @@ -5107,6 +5618,21 @@ dependencies = [ "thiserror", ] +[[package]] +name = "solana-zk-token-proof-program" +version = "1.16.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d3db5213b9dc063e95f94bc0b66748942786e48ed5e259bcf617897f1b86087" +dependencies = [ + "bytemuck", + "getrandom 0.1.16", + "num-derive 0.3.3", + "num-traits", + "solana-program-runtime", + "solana-sdk", + "solana-zk-token-sdk", +] + [[package]] name = "solana-zk-token-sdk" version = "1.16.18" @@ -5120,7 +5646,7 @@ dependencies = [ "byteorder", "curve25519-dalek", "getrandom 0.1.16", - "itertools", + "itertools 0.10.5", "lazy_static", "merlin", "num-derive 0.3.3", @@ -5439,12 +5965,40 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck 0.4.1", + "proc-macro2 1.0.66", + "quote 1.0.32", + "rustversion", + "syn 1.0.109", +] + [[package]] name = "subtle" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +[[package]] +name = "symlink" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" + [[package]] name = "syn" version = "0.15.44" @@ -5490,6 +6044,52 @@ dependencies = [ "unicode-xid 0.2.4", ] +[[package]] +name = "tar" +version = "0.4.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "tarpc" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c38a012bed6fb9681d3bf71ffaa4f88f3b4b9ed3198cda6e4c8462d24d4bb80" +dependencies = [ + "anyhow", + "fnv", + "futures", + "humantime", + "opentelemetry", + "pin-project", + "rand 0.8.5", + "serde", + "static_assertions", + "tarpc-plugins", + "thiserror", + "tokio", + "tokio-serde", + "tokio-util 0.6.10", + "tracing", + "tracing-opentelemetry", +] + +[[package]] +name = "tarpc-plugins" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee42b4e559f17bce0385ebf511a7beb67d5cc33c12c96b7f4e9789919d9c10f" +dependencies = [ + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 1.0.109", +] + [[package]] name = "tempfile" version = "3.5.0" @@ -5696,6 +6296,22 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-serde" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "911a61637386b789af998ee23f50aa30d5fd7edcec8d6d3dedae5e5815205466" +dependencies = [ + "bincode", + "bytes", + "educe", + "futures-core", + "futures-sink", + "pin-project", + "serde", + "serde_json", +] + [[package]] name = "tokio-stream" version = "0.1.12" @@ -5723,6 +6339,21 @@ dependencies = [ "webpki-roots 0.22.6", ] +[[package]] +name = "tokio-util" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "slab", + "tokio", +] + [[package]] name = "tokio-util" version = "0.7.7" @@ -5746,11 +6377,26 @@ dependencies = [ "serde", ] +[[package]] +name = "toml" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c226a7bba6d859b63c92c4b4fe69c5b6b72d0cb897dbc8e6012298e6154cb56e" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.20.0", +] + [[package]] name = "toml_datetime" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +dependencies = [ + "serde", +] [[package]] name = "toml_edit" @@ -5760,7 +6406,20 @@ checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" dependencies = [ "indexmap 1.9.3", "toml_datetime", - "winnow", + "winnow 0.4.1", +] + +[[package]] +name = "toml_edit" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ff63e60a958cefbb518ae1fd6566af80d9d4be430a33f3723dfc47d1d411d95" +dependencies = [ + "indexmap 2.0.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.5.15", ] [[package]] @@ -5845,6 +6504,19 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-opentelemetry" +version = "0.17.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbbe89715c1dbbb790059e2565353978564924ee85017b5fff365c872ff6721f" +dependencies = [ + "once_cell", + "opentelemetry", + "tracing", + "tracing-core", + "tracing-subscriber", +] + [[package]] name = "tracing-subscriber" version = "0.3.17" @@ -6039,6 +6711,16 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +[[package]] +name = "walkdir" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.0" @@ -6364,6 +7046,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "winnow" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.50.0" @@ -6392,6 +7083,15 @@ dependencies = [ "time 0.3.20", ] +[[package]] +name = "xattr" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4686009f71ff3e5c4dbcf1a282d0a44db3f021ba69350cd42086b3e5f1c6985" +dependencies = [ + "libc", +] + [[package]] name = "xz2" version = "0.1.7" diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index 36f2544d8..4f2b552e7 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "neon-cli" -version = "1.5.0-dev" +version = "1.7.0-dev" authors = ["NeonLabs Maintainers "] edition = "2021" diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index b2432d552..5de90dcd3 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -16,12 +16,15 @@ solana-clap-utils = "=1.16.18" solana-cli-config = "=1.16.18" solana-cli = "=1.16.18" solana-transaction-status = "=1.16.18" +solana-program-test = "=1.16.18" spl-token = { version = "~3.5", default-features = false, features = ["no-entrypoint"] } spl-associated-token-account = { version = "~1.1", default-features = false, features = ["no-entrypoint"] } bs58 = "0.4.0" -hex = "0.4.2" -serde = "1.0.186" -serde_json = { version = "1.0.107", features = ["preserve_order"] } +base64 = "0.21" +hex = { version = "0.4", features = ["serde"] } +serde = "1.0" +serde_json = { version = "1.0", features = ["preserve_order"] } +serde_with = { version = "3.3", features = ["hex"] } log = "0.4.17" rand = "0.8" ethnum = { version = "1.4", default-features = false, features = ["serde"] } diff --git a/evm_loader/program-macro/Cargo.toml b/evm_loader/program-macro/Cargo.toml index 422086822..2ac895935 100644 --- a/evm_loader/program-macro/Cargo.toml +++ b/evm_loader/program-macro/Cargo.toml @@ -10,8 +10,9 @@ proc-macro = true [dependencies] syn = "1" +proc-macro2 = "1" quote = "1" -itertools = "0.10.5" +itertools = "0.11" bs58 = "0.4" -serde = { version = "1.0.186", features = [ "derive" ] } -toml = "0.5" +serde = { version = "1.0", features = [ "derive" ] } +toml = "0.8" diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 117c7295f..8c6ef2093 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "evm-loader" -version = "1.5.0-dev" +version = "1.7.0-dev" description = "Neon EVM loader" authors = ["NeonLabs Maintainers "] edition = "2021" @@ -53,7 +53,6 @@ serde_bytes = "0.11.12" serde = { version = "1.0.186", default-features = false, features = ["derive", "rc"] } serde_json = { version = "1.0.107", features = ["preserve_order"], optional = true } ethnum = { version = "1.4", default-features = false, features = ["serde"] } -const_format = { version = "0.2.21" } cfg-if = { version = "1.0" } log = { version = "0.4", default-features = false, optional = true } maybe-async = "0.2.7" From 8aafc74613e94ef94ce60305a7d799cf75143669 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Tue, 14 Nov 2023 18:24:38 +0300 Subject: [PATCH 059/318] [Multi Tokens] Python Tests --- tests/conftest.py | 15 +- tests/requirements.txt | 4 +- tests/solana_utils.py | 207 ++++++++-------- tests/test_cancel_trx.py | 20 +- tests/test_cli.py | 39 +-- tests/test_execute_trx_from_instruction.py | 226 +++++++++--------- tests/test_holder_account.py | 29 ++- tests/test_neon_core_api.py | 3 +- tests/test_parallel.py | 59 +++-- tests/test_step_instructions_work_the_same.py | 22 +- tests/test_transaction_step_from_account.py | 224 +++++++++-------- ...ransaction_step_from_account_no_chainid.py | 39 +-- .../test_transaction_step_from_instruction.py | 222 ++++++++++------- tests/utils/assert_messages.py | 5 +- tests/utils/constants.py | 13 +- tests/utils/contract.py | 19 +- tests/utils/ethereum.py | 30 +-- tests/utils/instructions.py | 40 ++-- tests/utils/layouts.py | 25 +- tests/utils/neon_api_client.py | 48 ++-- tests/utils/types.py | 5 +- 21 files changed, 681 insertions(+), 613 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index b19051ee0..26e18a31e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -34,7 +34,7 @@ def pytest_configure(): @pytest.fixture(scope="session") -def evm_loader(operator_keypair) -> EvmLoader: +def evm_loader(operator_keypair: Keypair) -> EvmLoader: loader = EvmLoader(operator_keypair) return loader @@ -43,17 +43,20 @@ def prepare_operator(key_file): with open(key_file, "r") as key: secret_key = json.load(key)[:32] account = Keypair.from_secret_key(secret_key) + tx = solana_client.request_airdrop(account.public_key, 1000000 * 10 ** 9, commitment=Confirmed) wait_confirm_transaction(solana_client, tx.value) - caller_ether = eth_keys.PrivateKey(account.secret_key[:32]).public_key.to_canonical_address() + + operator_ether = eth_keys.PrivateKey(account.secret_key[:32]).public_key.to_canonical_address() + evm_loader = EvmLoader(account) - evm_loader.ether2program(caller_ether) - caller, caller_nonce = evm_loader.ether2program(caller_ether) - acc_info = solana_client.get_account_info(PublicKey(caller), commitment=Confirmed) + ether_balance_pubkey = evm_loader.ether2balance(operator_ether) + acc_info = solana_client.get_account_info(ether_balance_pubkey, commitment=Confirmed) if acc_info.value is None: token = spl_cli.create_token_account(NEON_TOKEN_MINT_ID, account.public_key, fee_payer=key_file) spl_cli.mint(NEON_TOKEN_MINT_ID, token, 5000000, fee_payer=key_file) - evm_loader.create_ether_account(caller_ether) + evm_loader.create_balance_account(operator_ether) + return account diff --git a/tests/requirements.txt b/tests/requirements.txt index 2b75f361a..43f7744b9 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -3,8 +3,8 @@ typing-extensions==4.2.0 ecdsa==0.17.0 pysha3==1.0.2 eth-keys==0.4.0 -rlp==2.0.1 -web3==5.29.1 +rlp==3.0.0 +web3==6.9.0 solana==0.28.0 solders==0.10.0 pytest-xdist==2.5.0 diff --git a/tests/solana_utils.py b/tests/solana_utils.py index 385e721c3..83f9388f9 100644 --- a/tests/solana_utils.py +++ b/tests/solana_utils.py @@ -28,12 +28,14 @@ from spl.token.constants import TOKEN_PROGRAM_ID from spl.token.instructions import get_associated_token_address, ApproveParams +from .utils.constants import CHAIN_ID + from .utils.constants import EVM_LOADER, SOLANA_URL, SYSTEM_ADDRESS, NEON_TOKEN_MINT_ID, \ ACCOUNT_SEED_VERSION, TREASURY_POOL_SEED from .utils.instructions import make_DepositV03, make_Cancel, make_WriteHolder, make_ExecuteTrxFromInstruction, \ TransactionWithComputeBudget, make_PartialCallOrContinueFromRawEthereumTX, \ make_ExecuteTrxFromAccountDataIterativeOrContinue -from .utils.layouts import ACCOUNT_INFO_LAYOUT, CREATE_ACCOUNT_LAYOUT +from .utils.layouts import BALANCE_ACCOUNT_LAYOUT, CONTRACT_ACCOUNT_LAYOUT from .utils.types import Caller, Contract EVM_LOADER_SO = os.environ.get("EVM_LOADER_SO", 'target/bpfel-unknown-unknown/release/evm_loader.so') @@ -57,7 +59,6 @@ # account storage overhead for calculation of base rent ACCOUNT_STORAGE_OVERHEAD = 128 - class SplToken: def __init__(self, url): self.url = url @@ -188,7 +189,7 @@ def __init__(self, verbose_flags=''): self.verbose_flags = verbose_flags def call(self, arguments): - cmd = 'neon-cli {} --commitment=processed --url {} {} -vvv'.format(self.verbose_flags, SOLANA_URL, arguments) + cmd = 'neon-cli {} --loglevel debug --commitment=processed --url {} {}'.format(self.verbose_flags, SOLANA_URL, arguments) proc_result = subprocess.run(cmd, shell=True, text=True, stdout=subprocess.PIPE, universal_newlines=True) result = json.loads(proc_result.stdout) if result["result"] == "error": @@ -203,20 +204,26 @@ def emulate(self, loader_id, sender, contract, data): "--commitment=recent", "--url", SOLANA_URL, f"--evm_loader={loader_id}", - "emulate", - sender, - contract + "emulate" ] print('cmd:', cmd) print("data:", data) - data_json = "" - if data: - data_json = f'{{"data": "0x{data}"}}' + body = json.dumps({ + "tx": { + "from": sender, + "to": contract, + "data": data + }, + "accounts": [] + }) - proc_result = subprocess.run(cmd, input=data_json, text=True, stdout=subprocess.PIPE, universal_newlines=True) + proc_result = subprocess.run(cmd, input=body, text=True, stdout=subprocess.PIPE, universal_newlines=True) result = json.loads(proc_result.stdout) + print("EMULATOR RESULT: ") + print(json.dumps(result)) + if result["result"] == "error": error = result["error"] raise Exception(f"ERR: neon-cli error {error}") @@ -288,7 +295,7 @@ def __init__(self, path): class EvmLoader: - def __init__(self, acc, program_id=EVM_LOADER): + def __init__(self, acc: Keypair, program_id=EVM_LOADER): if program_id is None: print(f"EVM Loader program address is empty, deploy it") result = json.loads(solana_cli(acc).call('deploy {}'.format(EVM_LOADER_SO))) @@ -300,23 +307,25 @@ def __init__(self, acc, program_id=EVM_LOADER): self.acc = acc print("Evm loader program: {}".format(self.loader_id)) - def deploy(self, contract_path, config=None): - print(f'Deploy contract from path: {contract_path}') - if config is None: - output = neon_cli().call("deploy --evm_loader {} {}".format(self.loader_id, contract_path)) - else: - output = neon_cli().call("deploy --evm_loader {} --config {} {}".format(self.loader_id, config, - contract_path)) - print(f"Deploy output: {output}") - result = json.loads(output.splitlines()[-1]) - return result - - def create_ether_account(self, ether): - (trx, sol) = self.create_ether_account_trx(ether) - signer = self.acc - self.check_account(signer.public_key) - send_transaction(solana_client, trx, signer) - return sol + def create_balance_account(self, ether: Union[str, bytes]) -> PublicKey: + account_pubkey = self.ether2balance(ether) + contract_pubkey = PublicKey(self.ether2program(ether)[0]) + print('createBalanceAccount: {} => {}'.format(ether, account_pubkey)) + + data = bytes.fromhex('2D') + self.ether2bytes(ether) + CHAIN_ID.to_bytes(8, 'little') + trx = Transaction() + trx.add(TransactionInstruction( + program_id=self.loader_id, + data=data, + keys=[ + AccountMeta(pubkey=self.acc.public_key, is_signer=True, is_writable=True), + AccountMeta(pubkey=PublicKey(SYSTEM_ADDRESS), is_signer=False, is_writable=False), + AccountMeta(pubkey=account_pubkey, is_signer=False, is_writable=True), + AccountMeta(pubkey=contract_pubkey, is_signer=False, is_writable=True), + ])) + + send_transaction(solana_client, trx, self.acc) + return account_pubkey @staticmethod def ether2hex(ether: Union[str, bytes]): @@ -343,57 +352,47 @@ def ether2seed(self, ether: Union[str, bytes]): def ether2program(self, ether: Union[str, bytes]) -> Tuple[str, int]: items = PublicKey.find_program_address([ACCOUNT_SEED_VERSION, self.ether2bytes(ether)], PublicKey(EVM_LOADER)) return str(items[0]), items[1] + + def ether2balance(self, address: Union[str, bytes]) -> PublicKey: + address_bytes = self.ether2bytes(address) + chain_id_bytes = CHAIN_ID.to_bytes(32, 'big') + return PublicKey.find_program_address( + [ACCOUNT_SEED_VERSION, address_bytes, chain_id_bytes], + PublicKey(EVM_LOADER) + )[0] def check_account(self, solana): info = solana_client.get_account_info(solana) print("checkAccount({}): {}".format(solana, info)) + + def get_neon_nonce(self, account: Union[str, bytes, Caller]) -> int: + if isinstance(account, Caller): + return self.get_neon_nonce(account.eth_address) - def deploy_checked(self, location, caller, caller_ether): - trx_count = get_transaction_count(solana_client, caller) - ether = keccak_256(rlp.encode((caller_ether, trx_count))).digest()[-20:] - - program = self.ether2program(ether) - info = solana_client.get_account_info(PublicKey(program[0])) - if info.value is None: - res = self.deploy(location) - return res['programId'], bytes.fromhex(res['ethereum'][2:]) - elif info.value.owner != self.loader_id: - raise Exception("Invalid owner for account {}".format(program)) - else: - return program[0], ether + solana_address = self.ether2balance(account) - def create_ether_account_trx(self, ether: Union[str, bytes]) -> Tuple[Transaction, str]: - (sol, nonce) = self.ether2program(ether) - print('createEtherAccount: {} {} => {}'.format(ether, nonce, sol)) - base = self.acc.public_key - data = bytes.fromhex('28') + CREATE_ACCOUNT_LAYOUT.build(dict(ether=self.ether2bytes(ether))) - trx = Transaction() - trx.add(TransactionInstruction( - program_id=self.loader_id, - data=data, - keys=[ - AccountMeta(pubkey=base, is_signer=True, is_writable=True), - AccountMeta(pubkey=PublicKey(SYSTEM_ADDRESS), is_signer=False, is_writable=False), - AccountMeta(pubkey=PublicKey(sol), is_signer=False, is_writable=True), - ])) - return trx, sol + info: bytes = get_solana_account_data(solana_client, solana_address, BALANCE_ACCOUNT_LAYOUT.sizeof()) + layout = BALANCE_ACCOUNT_LAYOUT.parse(info) + return layout.trx_count -def get_solana_balance(account): - return solana_client.get_balance(account, commitment=Confirmed).value + def get_neon_balance(self, account: Union[str, bytes, Caller]) -> int: + if isinstance(account, Caller): + return self.get_neon_balance(account.eth_address) + + solana_address = self.ether2balance(account) + info: bytes = get_solana_account_data(solana_client, solana_address, BALANCE_ACCOUNT_LAYOUT.sizeof()) + layout = BALANCE_ACCOUNT_LAYOUT.parse(info) -class AccountInfo(NamedTuple): - ether: eth_keys.PublicKey - trx_count: int + return int.from_bytes(layout.balance, byteorder="little") - @staticmethod - def from_bytes(data: bytes): - cont = ACCOUNT_INFO_LAYOUT.parse(data) - return AccountInfo(cont.ether, cont.trx_count) + +def get_solana_balance(account): + return solana_client.get_balance(account, commitment=Confirmed).value -def get_account_data(solana_client: Client, account: Union[str, PublicKey, Keypair], expected_length: int) -> bytes: +def get_solana_account_data(solana_client: Client, account: Union[str, PublicKey, Keypair], expected_length: int) -> bytes: if isinstance(account, Keypair): account = account.public_key print(f"Get account data for {account}") @@ -407,23 +406,6 @@ def get_account_data(solana_client: Client, account: Union[str, PublicKey, Keypa raise Exception("Wrong data length for account data {}".format(account)) return info.data - -def get_transaction_count(solana_client: Client, sol_account: Union[str, PublicKey]) -> int: - info = get_account_data(solana_client, sol_account, ACCOUNT_INFO_LAYOUT.sizeof()) - acc_info = AccountInfo.from_bytes(info) - res = int.from_bytes(acc_info.trx_count, 'little') - print('getTransactionCount {}: {}'.format(sol_account, res)) - return res - - -def get_neon_balance(solana_client: Client, sol_account: Union[str, PublicKey]) -> int: - info = get_account_data(solana_client, sol_account, ACCOUNT_INFO_LAYOUT.sizeof()) - account = ACCOUNT_INFO_LAYOUT.parse(info) - balance = int.from_bytes(account.balance, byteorder="little") - print('getNeonBalance {}: {}'.format(sol_account, balance)) - return balance - - def send_transaction(client: Client, trx, acc, wait_status=Confirmed): print("Send trx") result = client.send_transaction(trx, acc, opts=TxOpts(skip_confirmation=True, preflight_commitment=wait_status)) @@ -445,27 +427,30 @@ def evm_step_cost(): return math.floor(operator_expences / EVM_STEPS) -def make_new_user(evm_loader: EvmLoader): +def make_new_user(evm_loader: EvmLoader) -> Caller: key = Keypair.generate() if get_solana_balance(key.public_key) == 0: tx = solana_client.request_airdrop(key.public_key, 1000000 * 10 ** 9, commitment=Confirmed) wait_confirm_transaction(solana_client, tx.value) + caller_ether = eth_keys.PrivateKey(key.secret_key[:32]).public_key.to_canonical_address() - caller, caller_nonce = evm_loader.ether2program(caller_ether) - caller_token = get_associated_token_address(PublicKey(caller), NEON_TOKEN_MINT_ID) + caller_solana = evm_loader.ether2program(caller_ether)[0] + caller_balance = evm_loader.ether2balance(caller_ether) + caller_token = get_associated_token_address(caller_balance, NEON_TOKEN_MINT_ID) - if get_solana_balance(PublicKey(caller)) == 0: - print(f"Create Neon account {caller_ether} for user {caller}") - evm_loader.create_ether_account(caller_ether) + if get_solana_balance(caller_balance) == 0: + print(f"Create Neon account {caller_ether} for user {caller_balance}") + evm_loader.create_balance_account(caller_ether) print('Account solana address:', key.public_key) - print(f'Account ether address: {caller_ether.hex()} {caller_nonce}', ) - print(f'Account solana address: {caller}') - return Caller(key, PublicKey(caller), caller_ether, caller_nonce, caller_token) + print(f'Account ether address: {caller_ether.hex()}', ) + print(f'Account solana address: {caller_balance}') + return Caller(key, PublicKey(caller_solana), caller_balance, caller_ether, caller_token) def deposit_neon(evm_loader: EvmLoader, operator_keypair: Keypair, ether_address: Union[str, bytes], amount: int): - ether_pubkey, _ether_bump_seed = evm_loader.ether2program(ether_address) + balance_pubkey = evm_loader.ether2balance(ether_address) + contract_pubkey = PublicKey(evm_loader.ether2program(ether_address)[0]) evm_token_authority, _auth_bump_seed = \ PublicKey.find_program_address([bytes("Deposit", encoding='utf-8')], evm_loader.loader_id) @@ -478,7 +463,7 @@ def deposit_neon(evm_loader: EvmLoader, operator_keypair: Keypair, ether_address ApproveParams( spl.token.constants.TOKEN_PROGRAM_ID, signer_token_pubkey, - PublicKey(ether_pubkey), + balance_pubkey, operator_keypair.public_key, amount, ) @@ -487,7 +472,10 @@ def deposit_neon(evm_loader: EvmLoader, operator_keypair: Keypair, ether_address trx.add( make_DepositV03( evm_loader.ether2bytes(ether_address), - PublicKey(ether_pubkey), + CHAIN_ID, + balance_pubkey, + contract_pubkey, + NEON_TOKEN_MINT_ID, signer_token_pubkey, evm_pool_key, spl.token.constants.TOKEN_PROGRAM_ID, @@ -501,6 +489,7 @@ def deposit_neon(evm_loader: EvmLoader, operator_keypair: Keypair, ether_address def cancel_transaction( + evm_loader: EvmLoader, tx_hash: HexBytes, holder_acc: PublicKey, operator_keypair: Keypair, @@ -510,6 +499,7 @@ def cancel_transaction( trx = Transaction() trx.add( make_Cancel( + evm_loader, holder_acc, operator_keypair, tx_hash, @@ -549,36 +539,35 @@ def write_transaction_to_holder_account( wait_confirm_transaction(solana_client, rcpt.value) -def execute_trx_from_instruction(operator: Keypair, evm_loader, treasury_address: PublicKey, treasury_buffer: bytes, +def execute_trx_from_instruction(operator: Keypair, evm_loader: EvmLoader, treasury_address: PublicKey, treasury_buffer: bytes, instruction: SignedTransaction, - additional_accounts, signer: Keypair, system_program=sp.SYS_PROGRAM_ID, - evm_loader_public_key=PublicKey(EVM_LOADER)) -> SendTransactionResp: + additional_accounts, signer: Keypair, + system_program=sp.SYS_PROGRAM_ID) -> SendTransactionResp: trx = TransactionWithComputeBudget(operator) trx.add(make_ExecuteTrxFromInstruction(operator, evm_loader, treasury_address, treasury_buffer, instruction.rawTransaction, additional_accounts, - system_program, evm_loader_public_key)) + system_program)) return solana_client.send_transaction(trx, signer, opts=TxOpts(skip_preflight=False, skip_confirmation=False)) -def send_transaction_step_from_instruction(operator: Keypair, evm_loader, treasury, storage_account, +def send_transaction_step_from_instruction(operator: Keypair, evm_loader: EvmLoader, treasury, storage_account, instruction: SignedTransaction, additional_accounts, steps_count, signer: Keypair, - system_program=sp.SYS_PROGRAM_ID, - evm_loader_public_key=PublicKey(EVM_LOADER)) -> SendTransactionResp: + system_program=sp.SYS_PROGRAM_ID) -> SendTransactionResp: trx = TransactionWithComputeBudget(operator) trx.add( make_PartialCallOrContinueFromRawEthereumTX( instruction.rawTransaction, operator, evm_loader, storage_account, treasury.account, treasury.buffer, steps_count, - additional_accounts, system_program, evm_loader_public_key + additional_accounts, system_program ) ) return solana_client.send_transaction(trx, signer, opts=TxOpts(skip_preflight=False, skip_confirmation=False)) -def execute_transaction_steps_from_instruction(operator: Keypair, evm_loader, treasury, storage_account, +def execute_transaction_steps_from_instruction(operator: Keypair, evm_loader: EvmLoader, treasury, storage_account, instruction: SignedTransaction, additional_accounts, steps_count=EVM_STEPS, signer: Keypair = None) -> SendTransactionResp: @@ -596,21 +585,21 @@ def execute_transaction_steps_from_instruction(operator: Keypair, evm_loader, tr additional_accounts, 1, signer) -def send_transaction_step_from_account(operator: Keypair, evm_loader, treasury, storage_account, +def send_transaction_step_from_account(operator: Keypair, evm_loader: EvmLoader, treasury, storage_account, additional_accounts, steps_count, signer: Keypair, system_program=sp.SYS_PROGRAM_ID, - evm_loader_public_key=PublicKey(EVM_LOADER), tag=33) -> GetTransactionResp: + tag=33) -> GetTransactionResp: trx = TransactionWithComputeBudget(operator) trx.add( make_ExecuteTrxFromAccountDataIterativeOrContinue( operator, evm_loader, storage_account, treasury.account, treasury.buffer, steps_count, - additional_accounts, system_program, evm_loader_public_key, tag + additional_accounts, system_program, tag ) ) return send_transaction(solana_client, trx, signer) -def execute_transaction_steps_from_account(operator: Keypair, evm_loader, treasury, storage_account, +def execute_transaction_steps_from_account(operator: Keypair, evm_loader: EvmLoader, treasury, storage_account, additional_accounts, steps_count=EVM_STEPS, signer: Keypair = None) -> GetTransactionResp: signer = operator if signer is None else signer @@ -626,7 +615,7 @@ def execute_transaction_steps_from_account(operator: Keypair, evm_loader, treasu signer) -def execute_transaction_steps_from_account_no_chain_id(operator: Keypair, evm_loader, treasury, storage_account, +def execute_transaction_steps_from_account_no_chain_id(operator: Keypair, evm_loader: EvmLoader, treasury, storage_account, additional_accounts, steps_count=EVM_STEPS, signer: Keypair = None) -> GetTransactionResp: signer = operator if signer is None else signer diff --git a/tests/test_cancel_trx.py b/tests/test_cancel_trx.py index 3356a10d2..cbb683a9a 100644 --- a/tests/test_cancel_trx.py +++ b/tests/test_cancel_trx.py @@ -1,6 +1,6 @@ from solana.transaction import Transaction -from .solana_utils import send_transaction, solana_client, get_transaction_count, \ +from .solana_utils import send_transaction, solana_client, \ send_transaction_step_from_instruction from .utils.constants import TAG_FINALIZED_STATE, TAG_STATE from .utils.contract import make_contract_call_trx @@ -21,22 +21,22 @@ def test_cancel_trx(self, operator_keypair, rw_lock_contract, user_account, trea trx = send_transaction_step_from_instruction(operator_keypair, evm_loader, treasury_pool, storage_account, signed_tx, [rw_lock_contract.solana_address, - user_account.solana_account_address], 1, operator_keypair) + rw_lock_contract.balance_account_address, + user_account.balance_account_address], + 1, operator_keypair) receipt = solana_client.get_transaction(trx.value) assert receipt.value.transaction.meta.err is None check_holder_account_tag(storage_account, STORAGE_ACCOUNT_INFO_LAYOUT, TAG_STATE) - user_nonce = get_transaction_count(solana_client, user_account.solana_account_address) + user_nonce = evm_loader.get_neon_nonce(user_account.eth_address) trx = Transaction() trx.add( - make_Cancel(storage_account, operator_keypair, signed_tx.hash, - [ - rw_lock_contract.solana_address, - user_account.solana_account_address, - ] - ) + make_Cancel(evm_loader, storage_account, operator_keypair, signed_tx.hash, + [rw_lock_contract.solana_address, + rw_lock_contract.balance_account_address, + user_account.balance_account_address]) ) send_transaction(solana_client, trx, operator_keypair) check_holder_account_tag(storage_account, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) - assert user_nonce < get_transaction_count(solana_client, user_account.solana_account_address) + assert user_nonce < evm_loader.get_neon_nonce(user_account.eth_address) diff --git a/tests/test_cli.py b/tests/test_cli.py index a5887bf76..075643575 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -6,9 +6,9 @@ from solana.publickey import PublicKey from solana.rpc.commitment import Confirmed -from .solana_utils import neon_cli, create_treasury_pool_address, get_neon_balance, get_transaction_count +from .solana_utils import neon_cli, create_treasury_pool_address from .solana_utils import solana_client, wait_confirm_transaction, get_solana_balance, send_transaction -from .utils.constants import SOLANA_URL +from .utils.constants import CHAIN_ID, SOLANA_URL from .utils.contract import deploy_contract from .utils.ethereum import make_eth_transaction from eth_utils import abi, to_text @@ -48,7 +48,7 @@ def test_emulate_contract_deploy(user_account, evm_loader): result = neon_cli().emulate( evm_loader.loader_id, user_account.eth_address.hex(), - 'deploy', + None, contract_code.hex() ) assert result['exit_status'] == 'succeed', f"The 'exit_status' field is not succeed. Result: {result}" @@ -105,33 +105,13 @@ def test_init_environment(evm_loader): def test_get_ether_account_data(evm_loader, user_account): - result = neon_cli().call( - f"get-ether-account-data --evm_loader {evm_loader.loader_id} {user_account.eth_address.hex()}") + result = neon_cli().call(f"get-ether-account-data --evm_loader {evm_loader.loader_id} {user_account.eth_address.hex()} {CHAIN_ID}") - assert f"0x{user_account.eth_address.hex()}" == result["address"] - assert str(user_account.solana_account_address) == result["solana_address"] + assert str(user_account.balance_account_address) == result[0]["solana_address"] assert solana_client.get_account_info(user_account.solana_account.public_key).value is not None -def test_create_ether_account(evm_loader): - acc = gen_hash_of_block(20) - result = neon_cli().call( - f"create-ether-account --evm_loader {evm_loader.loader_id} {acc}") - - acc_info = solana_client.get_account_info(PublicKey(result['solana_address']), commitment=Confirmed) - assert acc_info.value is not None - - -def test_deposit(evm_loader, user_account): - amount = random.randint(1, 100000) - result = neon_cli().call( - f"deposit --evm_loader {evm_loader.loader_id} {amount} {user_account.eth_address.hex()}") - balance_after = get_neon_balance(solana_client, user_account.solana_account_address) - assert result["transaction"] is not None - assert balance_after == amount * 1000000000 - - def test_get_storage_at(evm_loader, operator_keypair, user_account, treasury_pool): contract = deploy_contract(operator_keypair, user_account, "hello_world.binary", evm_loader, treasury_pool) expected_storage = '0000000000000000000000000000000000000000000000000000000000000005' @@ -147,8 +127,7 @@ def test_cancel_trx(evm_loader, user_account, rw_lock_contract, operator_keypair eth_transaction = make_eth_transaction( rw_lock_contract.eth_address, data, - user_account.solana_account, - user_account.solana_account_address, + user_account ) storage_account = create_holder(operator_keypair) instruction = eth_transaction.rawTransaction @@ -159,7 +138,7 @@ def test_cancel_trx(evm_loader, user_account, rw_lock_contract, operator_keypair operator_keypair, evm_loader, storage_account, treasury_pool.account, treasury_pool.buffer, 1, [ rw_lock_contract.solana_address, - user_account.solana_account_address, + user_account.balance_account_address, ] ) ) @@ -167,8 +146,8 @@ def test_cancel_trx(evm_loader, user_account, rw_lock_contract, operator_keypair receipt = send_transaction(solana_client, trx, operator_keypair) assert receipt.value.transaction.meta.err is None - user_nonce = get_transaction_count(solana_client, user_account.solana_account_address) + user_nonce = evm_loader.get_neon_nonce(user_account.eth_address) result = neon_cli().call(f"cancel-trx --evm_loader={evm_loader.loader_id} {storage_account}") assert result["transaction"] is not None - assert user_nonce < get_transaction_count(solana_client, user_account.solana_account_address) + assert user_nonce < evm_loader.get_neon_nonce(user_account.eth_address) diff --git a/tests/test_execute_trx_from_instruction.py b/tests/test_execute_trx_from_instruction.py index 9af502aeb..46a4a07bb 100644 --- a/tests/test_execute_trx_from_instruction.py +++ b/tests/test_execute_trx_from_instruction.py @@ -13,64 +13,69 @@ from solana.rpc.commitment import Confirmed from spl.token.instructions import get_associated_token_address -from .solana_utils import execute_trx_from_instruction, solana_client, get_neon_balance, neon_cli +from .solana_utils import execute_trx_from_instruction, solana_client, neon_cli from .utils.assert_messages import InstructionAsserts from .utils.constants import NEON_TOKEN_MINT_ID from .utils.contract import deploy_contract, make_contract_call_trx from .utils.ethereum import make_eth_transaction from .utils.transaction_checks import check_transaction_logs_have_text -from .utils.types import Caller +from .utils.types import Caller, Contract class TestExecuteTrxFromInstruction: - def test_simple_transfer_transaction(self, operator_keypair, treasury_pool, sender_with_tokens, session_user, + def test_simple_transfer_transaction(self, operator_keypair, treasury_pool, + sender_with_tokens: Caller, session_user: Caller, evm_loader): amount = 10 - sender_balance_before = get_neon_balance(solana_client, sender_with_tokens.solana_account_address) - recipient_balance_before = get_neon_balance(solana_client, session_user.solana_account_address) + sender_balance_before = evm_loader.get_neon_balance(sender_with_tokens) + recipient_balance_before = evm_loader.get_neon_balance(session_user) - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, amount) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, amount) resp = execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, signed_tx, - [sender_with_tokens.solana_account_address, - session_user.solana_account_address], + [sender_with_tokens.balance_account_address, + session_user.balance_account_address, + session_user.solana_account_address], operator_keypair) - sender_balance_after = get_neon_balance(solana_client, sender_with_tokens.solana_account_address) - recipient_balance_after = get_neon_balance(solana_client, session_user.solana_account_address) + sender_balance_after = evm_loader.get_neon_balance(sender_with_tokens) + recipient_balance_after = evm_loader.get_neon_balance(session_user) assert sender_balance_before - amount == sender_balance_after assert recipient_balance_before + amount == recipient_balance_after check_transaction_logs_have_text(resp.value, "exit_status=0x11") - def test_transfer_transaction_with_non_existing_recipient(self, operator_keypair, treasury_pool, sender_with_tokens, + def test_transfer_transaction_with_non_existing_recipient(self, operator_keypair, treasury_pool, + sender_with_tokens: Caller, evm_loader): # recipient account should be created recipient = Keypair.generate() recipient_ether = eth_keys.PrivateKey(recipient.secret_key[:32]).public_key.to_canonical_address() recipient_solana_address, _ = evm_loader.ether2program(recipient_ether) + recipient_balance_address = evm_loader.ether2balance(recipient_ether) amount = 10 - signed_tx = make_eth_transaction(recipient_ether, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, amount) + signed_tx = make_eth_transaction(recipient_ether, None, sender_with_tokens, amount) resp = execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, signed_tx, - [sender_with_tokens.solana_account_address, + [sender_with_tokens.balance_account_address, + recipient_balance_address, PublicKey(recipient_solana_address)], operator_keypair) - recipient_balance_after = get_neon_balance(solana_client, PublicKey(recipient_solana_address)) + + recipient_balance_after = evm_loader.get_neon_balance(recipient_ether) check_transaction_logs_have_text(resp.value, "exit_status=0x11") assert recipient_balance_after == amount - def test_call_contract_function_without_neon_transfer(self, operator_keypair, treasury_pool, sender_with_tokens, - evm_loader, string_setter_contract): + def test_call_contract_function_without_neon_transfer(self, operator_keypair, treasury_pool, + sender_with_tokens: Caller, string_setter_contract: Contract, + evm_loader): text = ''.join(random.choice(string.ascii_letters) for _ in range(10)) signed_tx = make_contract_call_trx(sender_with_tokens, string_setter_contract, "set(string)", [text]) resp = execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, signed_tx, - [sender_with_tokens.solana_account_address, + [sender_with_tokens.balance_account_address, string_setter_contract.solana_address], operator_keypair) @@ -79,24 +84,25 @@ def test_call_contract_function_without_neon_transfer(self, operator_keypair, tr neon_cli().call_contract_get_function(evm_loader, sender_with_tokens, string_setter_contract, "get()")) - def test_call_contract_function_with_neon_transfer(self, operator_keypair, treasury_pool, sender_with_tokens, + def test_call_contract_function_with_neon_transfer(self, operator_keypair, treasury_pool, + sender_with_tokens: Caller, evm_loader): transfer_amount = random.randint(1, 1000) - contract = deploy_contract(operator_keypair, sender_with_tokens, "string_setter.binary", evm_loader, + contract: Contract = deploy_contract(operator_keypair, sender_with_tokens, "string_setter.binary", evm_loader, treasury_pool) - sender_balance_before = get_neon_balance(solana_client, sender_with_tokens.solana_account_address) - contract_balance_before = get_neon_balance(solana_client, contract.solana_address) + sender_balance_before = evm_loader.get_neon_balance(sender_with_tokens) + contract_balance_before = evm_loader.get_neon_balance(contract.eth_address) text = ''.join(random.choice(string.ascii_letters) for i in range(10)) func_name = abi.function_signature_to_4byte_selector('set(string)') data = func_name + eth_abi.encode(['string'], [text]) - signed_tx = make_eth_transaction(contract.eth_address, data, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, transfer_amount) + signed_tx = make_eth_transaction(contract.eth_address, data, sender_with_tokens, transfer_amount) resp = execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, signed_tx, - [sender_with_tokens.solana_account_address, + [sender_with_tokens.balance_account_address, + contract.balance_account_address, contract.solana_address], operator_keypair) @@ -104,177 +110,177 @@ def test_call_contract_function_with_neon_transfer(self, operator_keypair, treas assert text in to_text(neon_cli().call_contract_get_function(evm_loader, sender_with_tokens, contract, "get()")) - sender_balance_after = get_neon_balance(solana_client, sender_with_tokens.solana_account_address) - contract_balance_after = get_neon_balance(solana_client, contract.solana_address) + sender_balance_after = evm_loader.get_neon_balance(sender_with_tokens) + contract_balance_after = evm_loader.get_neon_balance(contract.eth_address) assert sender_balance_before - transfer_amount == sender_balance_after assert contract_balance_before + transfer_amount == contract_balance_after - def test_incorrect_chain_id(self, operator_keypair, treasury_pool, sender_with_tokens, evm_loader, session_user): + def test_incorrect_chain_id(self, operator_keypair, treasury_pool, + sender_with_tokens: Caller, session_user: Caller, + evm_loader): amount = 1 - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, amount, chain_id=1) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, amount, chain_id=1) with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.INVALID_CHAIN_ID): execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, signed_tx, - [sender_with_tokens.solana_account_address, + [sender_with_tokens.balance_account_address, + session_user.balance_account_address, session_user.solana_account_address], operator_keypair) - def test_incorrect_nonce(self, operator_keypair, treasury_pool, sender_with_tokens, evm_loader, session_user): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) + def test_incorrect_nonce(self, operator_keypair, treasury_pool, + sender_with_tokens: Caller, session_user: Caller, + evm_loader): + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, signed_tx, - [sender_with_tokens.solana_account_address, + [sender_with_tokens.balance_account_address, + session_user.balance_account_address, session_user.solana_account_address], operator_keypair) with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.INVALID_NONCE): execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, signed_tx, - [sender_with_tokens.solana_account_address, - session_user.solana_account_address], + [sender_with_tokens.balance_account_address, + session_user.balance_account_address, + session_user.solana_account_address], operator_keypair) - def test_insufficient_funds(self, operator_keypair, treasury_pool, evm_loader, sender_with_tokens, session_user): - user_balance = get_neon_balance(solana_client, session_user.solana_account_address) + def test_insufficient_funds(self, operator_keypair, treasury_pool, evm_loader, + sender_with_tokens: Caller, session_user: Caller): + user_balance = evm_loader.get_neon_balance(session_user) - signed_tx = make_eth_transaction(sender_with_tokens.eth_address, None, session_user.solana_account, - session_user.solana_account_address, user_balance + 1) + signed_tx = make_eth_transaction(sender_with_tokens.eth_address, None, session_user, user_balance + 1) with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.INSUFFICIENT_FUNDS): execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, signed_tx, - [sender_with_tokens.solana_account_address, + [sender_with_tokens.balance_account_address, + session_user.balance_account_address, session_user.solana_account_address], operator_keypair) - def test_gas_limit_reached(self, operator_keypair, treasury_pool, session_user, evm_loader, sender_with_tokens): + def test_gas_limit_reached(self, operator_keypair, treasury_pool, + session_user: Caller, sender_with_tokens: Caller, + evm_loader): amount = 10 - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, amount, gas=1) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, amount, gas=1) with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.OUT_OF_GAS): execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, signed_tx, - [session_user.solana_account_address, - sender_with_tokens.solana_account_address], + [sender_with_tokens.balance_account_address, + session_user.balance_account_address, + session_user.solana_account_address], operator_keypair) - def test_sender_missed_in_remaining_accounts(self, operator_keypair, treasury_pool, session_user, - sender_with_tokens, evm_loader): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) + def test_sender_missed_in_remaining_accounts(self, operator_keypair, treasury_pool, + session_user: Caller, sender_with_tokens: Caller, + evm_loader): + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.ADDRESS_MUST_BE_PRESENT): execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, signed_tx, - [session_user.solana_account_address], + [session_user.balance_account_address, + session_user.solana_account_address], operator_keypair) - def test_recipient_missed_in_remaining_accounts(self, operator_keypair, treasury_pool, sender_with_tokens, - evm_loader, session_user): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) + def test_recipient_missed_in_remaining_accounts(self, operator_keypair, treasury_pool, + sender_with_tokens: Caller, session_user: Caller, + evm_loader): + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.ADDRESS_MUST_BE_PRESENT): execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, signed_tx, - [sender_with_tokens.solana_account_address], + [sender_with_tokens.balance_account_address], operator_keypair) - def test_incorrect_treasure_pool(self, operator_keypair, sender_with_tokens, evm_loader, session_user): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) + def test_incorrect_treasure_pool(self, operator_keypair, + sender_with_tokens: Caller, session_user: Caller, + evm_loader): + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) + treasury_buffer = b'\x02\x00\x00\x00' - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.INVALID_TREASURE_ACC): - execute_trx_from_instruction(operator_keypair, evm_loader, Keypair().public_key, treasury_buffer, + treasury_pool = Keypair().public_key + + error = str.format(InstructionAsserts.INVALID_ACCOUNT, treasury_pool) + with pytest.raises(solana.rpc.core.RPCException, match=error): + execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool, treasury_buffer, signed_tx, - [sender_with_tokens.solana_account_address, - session_user.solana_account_address], + [], operator_keypair) - def test_incorrect_treasure_index(self, operator_keypair, sender_with_tokens, evm_loader, treasury_pool, - session_user): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) + def test_incorrect_treasure_index(self, operator_keypair, treasury_pool, + sender_with_tokens: Caller, session_user: Caller, + evm_loader): + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) treasury_buffer = b'\x03\x00\x00\x00' - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.INVALID_TREASURE_ACC): + + error = str.format(InstructionAsserts.INVALID_ACCOUNT, treasury_pool.account) + with pytest.raises(solana.rpc.core.RPCException, match=error): execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_buffer, signed_tx, - [sender_with_tokens.solana_account_address, - session_user.solana_account_address], + [], operator_keypair) - def test_incorrect_operator_account(self, sender_with_tokens, evm_loader, treasury_pool, session_user): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) + def test_incorrect_operator_account(self, evm_loader, treasury_pool, + session_user: Caller, sender_with_tokens: Caller): + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) fake_operator = Keypair() with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.ACC_NOT_FOUND): execute_trx_from_instruction(fake_operator, evm_loader, treasury_pool.account, treasury_pool.buffer, signed_tx, - [sender_with_tokens.solana_account_address, + [sender_with_tokens.balance_account_address, + session_user.balance_account_address, session_user.solana_account_address], fake_operator) - def test_operator_is_not_in_white_list(self, sender_with_tokens, operator_keypair, evm_loader, treasury_pool, + def test_operator_is_not_in_white_list(self, sender_with_tokens, evm_loader, treasury_pool, session_user): # now any user can send transactions through "execute transaction from instruction" instruction - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) - resp = execute_trx_from_instruction(sender_with_tokens.solana_account, evm_loader, treasury_pool.account, + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) + resp = execute_trx_from_instruction(sender_with_tokens.solana_account, evm_loader, + treasury_pool.account, treasury_pool.buffer, signed_tx, - [sender_with_tokens.solana_account_address, + [sender_with_tokens.balance_account_address, + session_user.balance_account_address, session_user.solana_account_address], sender_with_tokens.solana_account) check_transaction_logs_have_text(resp.value, "exit_status=0x11") def test_incorrect_system_program(self, sender_with_tokens, operator_keypair, evm_loader, treasury_pool, session_user): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) fake_sys_program_id = Keypair().public_key with pytest.raises(solana.rpc.core.RPCException, match=str.format(InstructionAsserts.NOT_SYSTEM_PROGRAM, fake_sys_program_id)): execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, signed_tx, - [sender_with_tokens.solana_account_address, - session_user.solana_account_address], + [], operator_keypair, system_program=fake_sys_program_id) - def test_incorrect_neon_program(self, sender_with_tokens, operator_keypair, evm_loader, treasury_pool, - session_user): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) - fake_neon_program_id = Keypair().public_key - with pytest.raises(solana.rpc.core.RPCException, - match=str.format(InstructionAsserts.NOT_NEON_PROGRAM, fake_neon_program_id)): - execute_trx_from_instruction(sender_with_tokens.solana_account, evm_loader, treasury_pool.account, - treasury_pool.buffer, - signed_tx, - [sender_with_tokens.solana_account_address, - session_user.solana_account_address], - sender_with_tokens.solana_account, evm_loader_public_key=fake_neon_program_id) - - def test_operator_does_not_have_enough_founds(self, sender_with_tokens, evm_loader, treasury_pool, - session_user): + def test_operator_does_not_have_enough_founds(self, evm_loader, treasury_pool, + session_user: Caller, sender_with_tokens: Caller): key = Keypair.generate() caller_ether = eth_keys.PrivateKey(key.secret_key[:32]).public_key.to_canonical_address() caller, caller_nonce = evm_loader.ether2program(caller_ether) caller_token = get_associated_token_address(PublicKey(caller), NEON_TOKEN_MINT_ID) - evm_loader.create_ether_account(caller_ether) + evm_loader.create_balance_account(caller_ether) operator_without_money = Caller(key, PublicKey(caller), caller_ether, caller_nonce, caller_token) - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) with pytest.raises(solana.rpc.core.RPCException, match="Attempt to debit an account but found no record of a prior credit"): execute_trx_from_instruction(operator_without_money.solana_account, evm_loader, treasury_pool.account, treasury_pool.buffer, signed_tx, - [sender_with_tokens.solana_account_address, + [sender_with_tokens.balance_account_address, + session_user.balance_account_address, session_user.solana_account_address], operator_without_money.solana_account) @@ -294,7 +300,7 @@ def test_transaction_with_access_list(self, operator_keypair, treasury_pool, sen resp = execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, signed_tx, - [sender_with_tokens.solana_account_address, + [sender_with_tokens.balance_account_address, calculator_caller_contract.solana_address, calculator_contract.solana_address], operator_keypair) @@ -302,10 +308,10 @@ def test_transaction_with_access_list(self, operator_keypair, treasury_pool, sen check_transaction_logs_have_text(resp.value, "exit_status=0x12") def test_old_trx_type_with_leading_zeros(self, sender_with_tokens, operator_keypair, evm_loader, - calculator_caller_contract, calculator_contract, treasury_pool, - holder_acc): + calculator_caller_contract, calculator_contract, treasury_pool): signed_tx = make_contract_call_trx(sender_with_tokens, calculator_caller_contract, "callCalculator()", []) - new_raw_trx = HexBytes('0x' + (b'\x00' + bytes.fromhex(signed_tx.rawTransaction.hex()[2:])).hex()) + new_raw_trx = HexBytes(bytes([0]) + signed_tx.rawTransaction) + signed_tx_new = SignedTransaction( rawTransaction=new_raw_trx, hash=signed_tx.hash, @@ -316,7 +322,7 @@ def test_old_trx_type_with_leading_zeros(self, sender_with_tokens, operator_keyp resp = execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, signed_tx_new, - [sender_with_tokens.solana_account_address, + [sender_with_tokens.balance_account_address, calculator_caller_contract.solana_address, calculator_contract.solana_address], operator_keypair) diff --git a/tests/test_holder_account.py b/tests/test_holder_account.py index 23e74a2e4..a0ec3198b 100644 --- a/tests/test_holder_account.py +++ b/tests/test_holder_account.py @@ -47,14 +47,14 @@ def test_create_the_same_holder_account_by_another_user(operator_keypair, sessio solana_utils.create_holder_account(storage, session_user.solana_account.public_key, bytes(seed, 'utf8')) ) - with pytest.raises(solana.rpc.core.RPCException, match="Holder doesn't match seeds"): + error = str.format(InstructionAsserts.INVALID_ACCOUNT, storage) + with pytest.raises(solana.rpc.core.RPCException, match=error): solana_utils.send_transaction(solana_client, trx, session_user.solana_account) def test_write_tx_to_holder(operator_keypair, session_user, second_session_user, evm_loader): holder_acc = create_holder(operator_keypair) - signed_tx = make_eth_transaction(second_session_user.eth_address, None, session_user.solana_account, - session_user.solana_account_address, 10) + signed_tx = make_eth_transaction(second_session_user.eth_address, None, session_user, 10) write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) assert signed_tx.rawTransaction == transaction_from_holder(holder_acc), \ "Account data is not correct" @@ -73,8 +73,7 @@ def test_write_tx_to_holder_in_parts(operator_keypair, session_user): def test_write_tx_to_holder_by_no_owner(operator_keypair, session_user, second_session_user, evm_loader): holder_acc = create_holder(operator_keypair) - signed_tx = make_eth_transaction(second_session_user.eth_address, None, session_user.solana_account, - session_user.solana_account_address, 10) + signed_tx = make_eth_transaction(second_session_user.eth_address, None, session_user, 10) with pytest.raises(solana.rpc.core.RPCException, match="invalid owner"): write_transaction_to_holder_account(signed_tx, holder_acc, session_user.solana_account) @@ -112,6 +111,7 @@ def test_write_to_not_finalized_holder(rw_lock_contract, user_account, evm_loade send_transaction_step_from_account(operator_keypair, evm_loader, treasury_pool, new_holder_acc, [user_account.solana_account_address, + user_account.balance_account_address, rw_lock_contract.solana_address], 1, operator_keypair) account_data = solana_client.get_account_info(new_holder_acc, commitment=Confirmed).value.data parsed_data = STORAGE_ACCOUNT_INFO_LAYOUT.parse(account_data) @@ -130,6 +130,7 @@ def test_write_to_finalized_holder(rw_lock_contract, session_user, evm_loader, o execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, new_holder_acc, [session_user.solana_account_address, + session_user.balance_account_address, rw_lock_contract.solana_address]) signed_tx2 = make_contract_call_trx(session_user, rw_lock_contract, "unchange_storage(uint8,uint8)", [1, 1]) @@ -138,9 +139,9 @@ def test_write_to_finalized_holder(rw_lock_contract, session_user, evm_loader, o "Account data is not correct" -@pytest.mark.parametrize("overflow_offset", [int(0xFFFFFFFFFFFFFFFF - 64), int(0xFFFFFFFFFFFFFFFF - 65)]) -def test_holder_write_overflow(operator_keypair, treasury_pool, evm_loader, - sender_with_tokens, session_user, holder_acc, overflow_offset): +def test_holder_write_integer_overflow(operator_keypair, holder_acc): + overflow_offset = int(0xFFFFFFFFFFFFFFFF) + trx = Transaction() trx.add(make_WriteHolder(operator_keypair.public_key, holder_acc, b"\x00" * 32, overflow_offset, b"\x00" * 1)) with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.HOLDER_OVERFLOW): @@ -149,3 +150,15 @@ def test_holder_write_overflow(operator_keypair, treasury_pool, evm_loader, operator_keypair, opts=TxOpts(skip_confirmation=True, preflight_commitment=Confirmed), ) + +def test_holder_write_account_size_overflow(operator_keypair, holder_acc): + overflow_offset = int(0xFFFFFFFF) + + trx = Transaction() + trx.add(make_WriteHolder(operator_keypair.public_key, holder_acc, b"\x00" * 32, overflow_offset, b"\x00" * 1)) + with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.HOLDER_INSUFFICIENT_SIZE): + solana_client.send_transaction( + trx, + operator_keypair, + opts=TxOpts(skip_confirmation=True, preflight_commitment=Confirmed), + ) diff --git a/tests/test_neon_core_api.py b/tests/test_neon_core_api.py index 65106132a..740b34d4e 100644 --- a/tests/test_neon_core_api.py +++ b/tests/test_neon_core_api.py @@ -17,8 +17,7 @@ def test_get_storage_at(neon_api_client, operator_keypair, user_account, evm_loa def test_get_ether_account_data(neon_api_client, user_account): result = neon_api_client.get_ether_account_data(user_account.eth_address.hex())['value'] - assert f"0x{user_account.eth_address.hex()}" == result["address"] - assert str(user_account.solana_account_address) == result["solana_address"] + assert str(user_account.balance_account_address) == result[0]["solana_address"] assert solana_client.get_account_info(user_account.solana_account.public_key).value is not None diff --git a/tests/test_parallel.py b/tests/test_parallel.py index 1a747f04c..ae277b695 100644 --- a/tests/test_parallel.py +++ b/tests/test_parallel.py @@ -6,11 +6,11 @@ from solana.publickey import PublicKey from solana.rpc.core import RPCException -from .solana_utils import EvmLoader, solana_client, get_account_data, make_new_user, deposit_neon, \ +from .solana_utils import EvmLoader, solana_client, get_solana_account_data, make_new_user, deposit_neon, \ cancel_transaction, send_transaction_step_from_account, execute_trx_from_instruction from .utils.contract import write_transaction_to_holder_account, make_deployment_transaction from .utils.ethereum import create_contract_address, make_eth_transaction -from .utils.layouts import ACCOUNT_INFO_LAYOUT +from .utils.layouts import CONTRACT_ACCOUNT_LAYOUT from .utils.storage import create_holder from .utils.types import Caller, TreasuryPool @@ -37,18 +37,17 @@ def prepare_fixture( def test_create_same_accounts(self): cases = [ - [2, ACCOUNT_INFO_LAYOUT.sizeof()], - [3, MAX_PERMITTED_DATA_INCREASE], - [4, MAX_PERMITTED_DATA_INCREASE * 2], + [2], + [3], + [4], ] for case in cases: iterations = case[0] - expected_length = case[1] - with self.subTest(iterations=iterations, expected_length=expected_length): - self.create_same_accounts_subtest(iterations, expected_length) + with self.subTest(iterations=iterations): + self.create_same_accounts_subtest(iterations) - def create_same_accounts_subtest(self, iterations: int, expected_length: int): + def create_same_accounts_subtest(self, iterations: int): deposit_neon(self.evm_loader, self.operator_keypair, self.user_account.eth_address, ONE_TOKEN) deposit_neon(self.evm_loader, self.operator_keypair, self.second_account.eth_address, ONE_TOKEN) @@ -63,7 +62,9 @@ def create_same_accounts_subtest(self, iterations: int, expected_length: int): self.evm_loader, self.treasury_pool, holder_acc, - [contract.solana_address, + [contract.balance_account_address, + contract.solana_address, + self.user_account.balance_account_address, self.user_account.solana_account_address], EVM_STEPS_COUNT, self.operator_keypair) @@ -75,7 +76,6 @@ def create_same_accounts_subtest(self, iterations: int, expected_length: int): self.second_account, contract.eth_address, ONE_TOKEN, - contract.solana_address, self.evm_loader, self.operator_keypair, self.treasury_pool, @@ -87,31 +87,29 @@ def create_same_accounts_subtest(self, iterations: int, expected_length: int): self.evm_loader, self.treasury_pool, holder_acc, - [contract.solana_address, + [contract.balance_account_address, + contract.solana_address, + self.user_account.balance_account_address, self.user_account.solana_account_address], EVM_STEPS_COUNT, self.operator_keypair) assert False, 'Deployment expected to fail' except RPCException as e: - ParallelTransactionsTest.check_account_initialized_in_another_trx_exception(e, contract.solana_address) + ParallelTransactionsTest.check_account_initialized_in_another_trx_exception(e, contract.balance_account_address) # Cancel deployment transaction: cancel_transaction( + self.evm_loader, deployment_tx.hash, holder_acc, self.operator_keypair, - [contract.solana_address, self.user_account.solana_account_address], + [contract.balance_account_address, + contract.solana_address, + self.user_account.balance_account_address, + self.user_account.solana_account_address], ) - data = get_account_data(solana_client, contract.solana_address, expected_length) - assert len(data) == expected_length - - account = ACCOUNT_INFO_LAYOUT.parse(data) - assert account.code_size == 0 - balance = int.from_bytes(account.balance, byteorder="little") - assert balance == ONE_TOKEN - @staticmethod def check_iteration_deployed(receipt: Any) -> bool: if receipt.value.transaction.meta.err: @@ -129,7 +127,6 @@ def transfer( src_account: Caller, dst_addr: bytes, value: int, - dst_solana_addr: PublicKey, evm_loader: EvmLoader, operator_keypair: Keypair, treasury_pool: TreasuryPool, @@ -137,15 +134,18 @@ def transfer( message = make_eth_transaction( dst_addr, bytes(), - src_account.solana_account, - src_account.solana_account_address, + src_account, value, ) + dst_solana_account, _ = evm_loader.ether2program(dst_addr) + dst_balance_account = evm_loader.ether2balance(dst_addr) + trx = execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, message, - [dst_solana_addr, - src_account.solana_account_address], + [dst_balance_account, + PublicKey(dst_solana_account), + src_account.balance_account_address], operator_keypair) receipt = solana_client.get_transaction(trx.value) print("Transfer receipt:", receipt) @@ -157,10 +157,9 @@ def transfer( def check_account_initialized_in_another_trx_exception(exception: RPCException, solana_address: PublicKey): error = exception.args[0] print("error:", error) - assert 'instruction requires an uninitialized account' in error.message - + for log in error.data.logs: - if f'Blocked nonexistent account {solana_address} was created/initialized outside' in log: + if f'Account {solana_address} - was empty, created by another transaction' in log: return assert False, "Search string not found in Solana logs" diff --git a/tests/test_step_instructions_work_the_same.py b/tests/test_step_instructions_work_the_same.py index d9ed80e23..e7e4cacbb 100644 --- a/tests/test_step_instructions_work_the_same.py +++ b/tests/test_step_instructions_work_the_same.py @@ -12,17 +12,19 @@ def test_simple_transfer_transaction(self, operator_keypair, treasury_pool, evm_ sender_with_tokens, session_user, holder_acc): amount = 10 - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, amount) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, amount) write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) resp_from_acc = execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, [session_user.solana_account_address, - sender_with_tokens.solana_account_address], 0).value - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, amount) + session_user.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address], 0).value + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, amount) signature = execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, signed_tx, [session_user.solana_account_address, - sender_with_tokens.solana_account_address], + session_user.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address], 0) resp_from_inst = solana_client.get_transaction(signature.value).value assert resp_from_acc.transaction.meta.fee == resp_from_inst.transaction.meta.fee @@ -40,14 +42,18 @@ def test_deploy_contract(self, operator_keypair, holder_acc, treasury_pool, evm_ resp_from_acc = execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, [contract.solana_address, - sender_with_tokens.solana_account_address]).value + contract.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address]).value signed_tx = make_deployment_transaction(sender_with_tokens, contract_filename) holder_acc = create_holder(operator_keypair) contract = create_contract_address(sender_with_tokens, evm_loader) signature = execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, signed_tx, [contract.solana_address, - sender_with_tokens.solana_account_address]) + contract.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address]) resp_from_inst = solana_client.get_transaction(signature.value).value assert resp_from_acc.transaction.meta.fee == resp_from_inst.transaction.meta.fee assert len(resp_from_acc.transaction.meta.inner_instructions) == len( diff --git a/tests/test_transaction_step_from_account.py b/tests/test_transaction_step_from_account.py index 09ccf8322..bbc010164 100644 --- a/tests/test_transaction_step_from_account.py +++ b/tests/test_transaction_step_from_account.py @@ -12,7 +12,7 @@ from solana.rpc.commitment import Processed, Confirmed from solana.rpc.types import TxOpts -from .solana_utils import get_neon_balance, solana_client, neon_cli, execute_transaction_steps_from_account, \ +from .solana_utils import solana_client, neon_cli, execute_transaction_steps_from_account, \ write_transaction_to_holder_account, create_treasury_pool_address, send_transaction_step_from_account from .test_cli import gen_hash_of_block from .utils.assert_messages import InstructionAsserts @@ -42,18 +42,19 @@ class TestTransactionStepFromAccount: def test_simple_transfer_transaction(self, operator_keypair, treasury_pool, evm_loader, sender_with_tokens, session_user, holder_acc): amount = 10 - sender_balance_before = get_neon_balance(solana_client, sender_with_tokens.solana_account_address) - recipient_balance_before = get_neon_balance(solana_client, session_user.solana_account_address) + sender_balance_before = evm_loader.get_neon_balance(sender_with_tokens) + recipient_balance_before = evm_loader.get_neon_balance(session_user) - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, amount) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, amount) write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) resp = execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, [session_user.solana_account_address, - sender_with_tokens.solana_account_address], 0) + session_user.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address], 0) - sender_balance_after = get_neon_balance(solana_client, sender_with_tokens.solana_account_address) - recipient_balance_after = get_neon_balance(solana_client, session_user.solana_account_address) + sender_balance_after = evm_loader.get_neon_balance(sender_with_tokens) + recipient_balance_after = evm_loader.get_neon_balance(session_user) check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) check_transaction_logs_have_text(resp.value.transaction.transaction.signatures[0], "exit_status=0x11") @@ -71,10 +72,12 @@ def test_deploy_contract(self, operator_keypair, holder_acc, treasury_pool, evm_ with open(contract_path, 'rb') as f: contract_code = f.read() - steps_count = neon_cli().get_steps_count(evm_loader, sender_with_tokens, "deploy", contract_code.hex()) + steps_count = neon_cli().get_steps_count(evm_loader, sender_with_tokens, None, contract_code.hex()) resp = execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, [contract.solana_address, - sender_with_tokens.solana_account_address], + contract.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address], steps_count) check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) check_transaction_logs_have_text(resp.value.transaction.transaction.signatures[0], "exit_status=0x12") @@ -87,7 +90,8 @@ def test_call_contract_function_without_neon_transfer(self, operator_keypair, ho resp = execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, [string_setter_contract.solana_address, - sender_with_tokens.solana_account_address]) + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address]) check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) check_transaction_logs_have_text(resp.value.transaction.transaction.signatures[0], "exit_status=0x11") @@ -101,8 +105,8 @@ def test_call_contract_function_with_neon_transfer(self, operator_keypair, treas evm_loader): transfer_amount = random.randint(1, 1000) - sender_balance_before = get_neon_balance(solana_client, sender_with_tokens.solana_account_address) - contract_balance_before = get_neon_balance(solana_client, string_setter_contract.solana_address) + sender_balance_before = evm_loader.get_neon_balance(sender_with_tokens) + contract_balance_before = evm_loader.get_neon_balance(string_setter_contract.eth_address) text = ''.join(random.choice(string.ascii_letters) for _ in range(10)) @@ -112,14 +116,15 @@ def test_call_contract_function_with_neon_transfer(self, operator_keypair, treas resp = execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, [string_setter_contract.solana_address, - sender_with_tokens.solana_account_address] - ) + string_setter_contract.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address]) check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) check_transaction_logs_have_text(resp.value.transaction.transaction.signatures[0], "exit_status=0x11") - sender_balance_after = get_neon_balance(solana_client, sender_with_tokens.solana_account_address) - contract_balance_after = get_neon_balance(solana_client, string_setter_contract.solana_address) + sender_balance_after = evm_loader.get_neon_balance(sender_with_tokens) + contract_balance_after = evm_loader.get_neon_balance(string_setter_contract.eth_address) assert sender_balance_before - transfer_amount == sender_balance_after assert contract_balance_before + transfer_amount == contract_balance_after @@ -133,190 +138,182 @@ def test_transfer_transaction_with_non_existing_recipient(self, operator_keypair recipient = Keypair.generate() recipient_ether = eth_keys.PrivateKey(recipient.secret_key[:32]).public_key.to_canonical_address() recipient_solana_address, _ = evm_loader.ether2program(recipient_ether) + recipient_balance_address = evm_loader.ether2balance(recipient_ether) amount = 10 - signed_tx = make_eth_transaction(recipient_ether, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, amount) + signed_tx = make_eth_transaction(recipient_ether, None, sender_with_tokens, amount) write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) resp = execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, [PublicKey(recipient_solana_address), - sender_with_tokens.solana_account_address], 0) + recipient_balance_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address], 0) - recipient_balance_after = get_neon_balance(solana_client, PublicKey(recipient_solana_address)) + recipient_balance_after = evm_loader.get_neon_balance(recipient_ether) check_transaction_logs_have_text(resp.value.transaction.transaction.signatures[0], "exit_status=0x11") assert recipient_balance_after == amount def test_incorrect_chain_id(self, operator_keypair, holder_acc, treasury_pool, sender_with_tokens, session_user, evm_loader): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1, chain_id=1) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1, chain_id=1) write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.INVALID_CHAIN_ID): execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, [session_user.solana_account_address, - sender_with_tokens.solana_account_address], 0) + session_user.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address], 0) def test_incorrect_nonce(self, operator_keypair, treasury_pool, sender_with_tokens, evm_loader, session_user, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, [session_user.solana_account_address, - sender_with_tokens.solana_account_address], 0) + session_user.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address], 0) write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.INVALID_NONCE): execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, [session_user.solana_account_address, - sender_with_tokens.solana_account_address], 0) + session_user.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address], 0) def test_run_finalized_transaction(self, operator_keypair, treasury_pool, sender_with_tokens, evm_loader, session_user, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, [session_user.solana_account_address, - sender_with_tokens.solana_account_address], 0) + session_user.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address], 0) with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.TRX_ALREADY_FINALIZED): execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, [session_user.solana_account_address, - sender_with_tokens.solana_account_address], 0) + session_user.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address], 0) def test_insufficient_funds(self, operator_keypair, treasury_pool, evm_loader, session_user, holder_acc, sender_with_tokens): - user_balance = get_neon_balance(solana_client, session_user.solana_account_address) + user_balance = evm_loader.get_neon_balance(session_user) - signed_tx = make_eth_transaction(sender_with_tokens.eth_address, None, session_user.solana_account, - session_user.solana_account_address, user_balance + 1) + signed_tx = make_eth_transaction(sender_with_tokens.eth_address, None, session_user, user_balance + 1) write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.INSUFFICIENT_FUNDS): execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, [session_user.solana_account_address, - sender_with_tokens.solana_account_address], 0) + session_user.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address], 0) def test_gas_limit_reached(self, operator_keypair, treasury_pool, session_user, evm_loader, sender_with_tokens, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 10, gas=1) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 10, gas=1) write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.OUT_OF_GAS): execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, [session_user.solana_account_address, - sender_with_tokens.solana_account_address], 0) + session_user.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address], 0) def test_sender_missed_in_remaining_accounts(self, operator_keypair, treasury_pool, session_user, sender_with_tokens, evm_loader, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.ADDRESS_MUST_BE_PRESENT): execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, - [session_user.solana_account_address], 0) + [session_user.solana_account_address, + session_user.balance_account_address], 0) def test_recipient_missed_in_remaining_accounts(self, operator_keypair, treasury_pool, session_user, sender_with_tokens, evm_loader, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.ADDRESS_MUST_BE_PRESENT): execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, - [sender_with_tokens.solana_account_address], 0) + [sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address], 0) def test_incorrect_treasure_pool(self, operator_keypair, sender_with_tokens, evm_loader, session_user, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) index = 2 treasury = TreasuryPool(index, Keypair().generate().public_key, index.to_bytes(4, 'little')) - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.INVALID_TREASURE_ACC): - execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury, holder_acc, - [sender_with_tokens.solana_account_address, - session_user.solana_account_address], 0) + error = str.format(InstructionAsserts.INVALID_ACCOUNT, treasury.account) + with pytest.raises(solana.rpc.core.RPCException, match=error): + execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury, holder_acc, [], 0) def test_incorrect_treasure_index(self, operator_keypair, sender_with_tokens, evm_loader, session_user, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) index = 2 treasury = TreasuryPool(index, create_treasury_pool_address(index), (index + 1).to_bytes(4, 'little')) - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.INVALID_TREASURE_ACC): - execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury, holder_acc, - [sender_with_tokens.solana_account_address, - session_user.solana_account_address], 0) + + error = str.format(InstructionAsserts.INVALID_ACCOUNT, treasury.account) + with pytest.raises(solana.rpc.core.RPCException, match=error): + execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury, holder_acc, [], 0) def test_incorrect_operator_account(self, operator_keypair, sender_with_tokens, evm_loader, treasury_pool, session_user, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) fake_operator = Keypair() with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.ACC_NOT_FOUND): execute_transaction_steps_from_account(fake_operator, evm_loader, treasury_pool, holder_acc, [sender_with_tokens.solana_account_address, - session_user.solana_account_address], 0) + sender_with_tokens.balance_account_address, + session_user.solana_account_address, + session_user.balance_account_address], 0) def test_operator_is_not_in_white_list(self, sender_with_tokens, operator_keypair, evm_loader, treasury_pool, session_user, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.NOT_AUTHORIZED_OPERATOR): execute_transaction_steps_from_account(sender_with_tokens.solana_account, evm_loader, treasury_pool, holder_acc, [sender_with_tokens.solana_account_address, - session_user.solana_account_address], 0, + sender_with_tokens.balance_account_address, + session_user.solana_account_address, + session_user.balance_account_address], 0, signer=sender_with_tokens.solana_account) def test_incorrect_system_program(self, sender_with_tokens, operator_keypair, evm_loader, treasury_pool, session_user, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) fake_sys_program_id = Keypair().public_key write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - with pytest.raises(solana.rpc.core.RPCException, - match=str.format(InstructionAsserts.NOT_SYSTEM_PROGRAM, fake_sys_program_id)): + error = str.format(InstructionAsserts.NOT_SYSTEM_PROGRAM, fake_sys_program_id) + with pytest.raises(solana.rpc.core.RPCException, match=error): send_transaction_step_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, - [sender_with_tokens.solana_account_address, - session_user.solana_account_address], 1, operator_keypair, - system_program=fake_sys_program_id) - - def test_incorrect_neon_program(self, sender_with_tokens, operator_keypair, evm_loader, treasury_pool, - session_user, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) - fake_neon_program_id = Keypair().public_key - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) + [], 1, operator_keypair, system_program=fake_sys_program_id) - with pytest.raises(solana.rpc.core.RPCException, - match=str.format(InstructionAsserts.NOT_NEON_PROGRAM, fake_neon_program_id)): - send_transaction_step_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, - [sender_with_tokens.solana_account_address, - session_user.solana_account_address], 1, operator_keypair, - evm_loader_public_key=fake_neon_program_id) - def test_incorrect_holder_account(self, sender_with_tokens, operator_keypair, evm_loader, treasury_pool, - session_user): + def test_incorrect_holder_account(self, operator_keypair, evm_loader, treasury_pool): fake_holder_acc = Keypair.generate().public_key - with pytest.raises(solana.rpc.core.RPCException, - match=str.format(InstructionAsserts.NOT_PROGRAM_OWNED, fake_holder_acc)): - send_transaction_step_from_account(operator_keypair, evm_loader, treasury_pool, fake_holder_acc, - [sender_with_tokens.solana_account_address, - session_user.solana_account_address], 1, operator_keypair) + + error = str.format(InstructionAsserts.NOT_PROGRAM_OWNED, fake_holder_acc) + with pytest.raises(solana.rpc.core.RPCException, match=error): + send_transaction_step_from_account(operator_keypair, evm_loader, treasury_pool, fake_holder_acc, [], 1, operator_keypair) def test_transaction_with_access_list(self, operator_keypair, holder_acc, treasury_pool, sender_with_tokens, evm_loader, calculator_contract, @@ -337,7 +334,8 @@ def test_transaction_with_access_list(self, operator_keypair, holder_acc, treasu resp = execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, [calculator_caller_contract.solana_address, calculator_contract.solana_address, - sender_with_tokens.solana_account_address]) + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address]) check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) check_transaction_logs_have_text(resp.value.transaction.transaction.signatures[0], "exit_status=0x12") @@ -352,7 +350,9 @@ def test_access_list_structure(self, operator_keypair, holder_acc, treasury_pool write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) resp = execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, [string_setter_contract.solana_address, - sender_with_tokens.solana_account_address]) + string_setter_contract.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address]) check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) check_transaction_logs_have_text(resp.value.transaction.transaction.signatures[0], "exit_status=0x11") @@ -370,7 +370,8 @@ def test_contract_call_unchange_storage_function(self, rw_lock_contract, rw_lock resp = execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, [rw_lock_caller.solana_address, rw_lock_contract.solana_address, - session_user.solana_account_address]) + session_user.solana_account_address, + session_user.balance_account_address]) check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) check_transaction_logs_have_text(resp.value.transaction.transaction.signatures[0], "exit_status=0x12") @@ -382,7 +383,8 @@ def test_contract_call_set_function(self, rw_lock_contract, session_user, evm_lo resp = execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, [rw_lock_caller.solana_address, rw_lock_contract.solana_address, - session_user.solana_account_address], 1000) + session_user.solana_account_address, + session_user.balance_account_address], 1000) check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) check_transaction_logs_have_text(resp.value.transaction.transaction.signatures[0], "exit_status=0x11") @@ -398,7 +400,8 @@ def test_contract_call_get_function(self, rw_lock_contract, session_user, evm_lo resp = execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, [rw_lock_caller.solana_address, rw_lock_contract.solana_address, - session_user.solana_account_address], 1000) + session_user.solana_account_address, + session_user.balance_account_address], 1000) check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) check_transaction_logs_have_text(resp.value.transaction.transaction.signatures[0], "exit_status=0x12") @@ -415,7 +418,9 @@ def test_contract_call_update_storage_map_function(self, rw_lock_contract, sessi session_user.eth_address.hex(), rw_lock_caller.eth_address.hex(), data.hex()) - additional_accounts = [session_user.solana_account_address, rw_lock_contract.solana_address, + additional_accounts = [session_user.solana_account_address, + session_user.balance_account_address, + rw_lock_contract.solana_address, rw_lock_caller.solana_address] for acc in result['solana_accounts']: additional_accounts.append(PublicKey(acc['pubkey'])) @@ -440,7 +445,8 @@ def test_one_user_call_2_contracts(self, rw_lock_contract, string_setter_contrac write_transaction_to_holder_account(signed_tx, new_holder_acc, operator_keypair) send_transaction_step_from_account(operator_keypair, evm_loader, treasury_pool, new_holder_acc, - [user_account.solana_account_address, + [user_account.balance_account_address, + user_account.solana_account_address, rw_lock_contract.solana_address], 1, operator_keypair) signed_tx2 = make_contract_call_trx(user_account, string_setter_contract, 'get()') @@ -450,7 +456,8 @@ def test_one_user_call_2_contracts(self, rw_lock_contract, string_setter_contrac with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.LOCKED_ACC): send_transaction_step_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc2, - [user_account.solana_account_address, + [user_account.balance_account_address, + user_account.solana_account_address, string_setter_contract.solana_address], 1, operator_keypair) def test_2_users_call_the_same_contract(self, rw_lock_contract, user_account, @@ -461,6 +468,7 @@ def test_2_users_call_the_same_contract(self, rw_lock_contract, user_account, send_transaction_step_from_account(operator_keypair, evm_loader, treasury_pool, new_holder_acc, [user_account.solana_account_address, + user_account.balance_account_address, rw_lock_contract.solana_address], 1, operator_keypair) signed_tx2 = make_contract_call_trx(session_user, rw_lock_contract, 'get_text()') @@ -471,6 +479,7 @@ def test_2_users_call_the_same_contract(self, rw_lock_contract, user_account, with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.LOCKED_ACC): send_transaction_step_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc2, [session_user.solana_account_address, + session_user.balance_account_address, rw_lock_contract.solana_address], 1, operator_keypair) def test_two_contracts_call_same_contract(self, rw_lock_contract, user_account, @@ -489,6 +498,7 @@ def test_two_contracts_call_same_contract(self, rw_lock_contract, user_account, send_transaction_step_from_account(operator_keypair, evm_loader, treasury_pool, new_holder_acc, [user_account.solana_account_address, + user_account.balance_account_address, rw_lock_contract.solana_address, contract1.solana_address], 1, operator_keypair) @@ -498,6 +508,7 @@ def test_two_contracts_call_same_contract(self, rw_lock_contract, user_account, with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.LOCKED_ACC): send_transaction_step_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc2, [session_user.solana_account_address, + session_user.balance_account_address, rw_lock_contract.solana_address, contract2.solana_address], 1, operator_keypair) @@ -515,6 +526,7 @@ def test_next_operator_can_continue_trx_after_some_time(self, rw_lock_contract, make_ExecuteTrxFromAccountDataIterativeOrContinue( operator_keypair, evm_loader, new_holder_acc, treasury_pool.account, treasury_pool.buffer, 1, [user_account.solana_account_address, + user_account.balance_account_address, rw_lock_contract.solana_address] ) ) @@ -522,17 +534,23 @@ def test_next_operator_can_continue_trx_after_some_time(self, rw_lock_contract, opts=TxOpts(skip_confirmation=True, preflight_commitment=Confirmed)) # next operator can't continue trx during OPERATOR_PRIORITY_SLOTS*0.4 - with pytest.raises(solana.rpc.core.RPCException, - match=rf"{InstructionAsserts.INVALID_OPERATOR_KEY}|{InstructionAsserts.INVALID_HOLDER_OWNER}"): send_transaction_step_from_account( - second_operator_keypair, evm_loader, treasury_pool, new_holder_acc, - [user_account.solana_account_address, - rw_lock_contract.solana_address], 500, second_operator_keypair) + error = rf"{InstructionAsserts.INVALID_OPERATOR_KEY}|{InstructionAsserts.INVALID_HOLDER_OWNER}" + with pytest.raises(solana.rpc.core.RPCException, match=error): + send_transaction_step_from_account( + second_operator_keypair, evm_loader, treasury_pool, new_holder_acc, + [user_account.solana_account_address, + user_account.balance_account_address, + rw_lock_contract.solana_address], + 500, second_operator_keypair + ) time.sleep(15) send_transaction_step_from_account(second_operator_keypair, evm_loader, treasury_pool, new_holder_acc, [user_account.solana_account_address, + user_account.balance_account_address, rw_lock_contract.solana_address], 500, second_operator_keypair) resp = send_transaction_step_from_account(second_operator_keypair, evm_loader, treasury_pool, new_holder_acc, [user_account.solana_account_address, + user_account.balance_account_address, rw_lock_contract.solana_address], 1, second_operator_keypair) check_transaction_logs_have_text(resp.value.transaction.transaction.signatures[0], "exit_status=0x11") diff --git a/tests/test_transaction_step_from_account_no_chainid.py b/tests/test_transaction_step_from_account_no_chainid.py index f51399942..160d666be 100644 --- a/tests/test_transaction_step_from_account_no_chainid.py +++ b/tests/test_transaction_step_from_account_no_chainid.py @@ -1,11 +1,12 @@ import random +import re import string import solana import pytest from eth_utils import to_text -from .solana_utils import write_transaction_to_holder_account, get_neon_balance, solana_client, \ +from .solana_utils import write_transaction_to_holder_account, solana_client, \ execute_transaction_steps_from_account_no_chain_id, neon_cli from .utils.assert_messages import InstructionAsserts from .utils.constants import TAG_FINALIZED_STATE @@ -20,19 +21,20 @@ class TestTransactionStepFromAccountNoChainId: def test_simple_transfer_transaction(self, operator_keypair, treasury_pool, evm_loader, sender_with_tokens, session_user, holder_acc): amount = 10 - sender_balance_before = get_neon_balance(solana_client, sender_with_tokens.solana_account_address) - recipient_balance_before = get_neon_balance(solana_client, session_user.solana_account_address) + sender_balance_before = evm_loader.get_neon_balance(sender_with_tokens) + recipient_balance_before = evm_loader.get_neon_balance(session_user) - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, amount, chain_id=None) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, amount, chain_id=None) write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) resp = execute_transaction_steps_from_account_no_chain_id(operator_keypair, evm_loader, treasury_pool, holder_acc, [session_user.solana_account_address, + session_user.balance_account_address, + sender_with_tokens.balance_account_address, sender_with_tokens.solana_account_address], 0) - sender_balance_after = get_neon_balance(solana_client, sender_with_tokens.solana_account_address) - recipient_balance_after = get_neon_balance(solana_client, session_user.solana_account_address) + sender_balance_after = evm_loader.get_neon_balance(sender_with_tokens) + recipient_balance_after = evm_loader.get_neon_balance(session_user) check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) check_transaction_logs_have_text(resp.value.transaction.transaction.signatures[0], "exit_status=0x11") @@ -50,10 +52,12 @@ def test_deploy_contract(self, operator_keypair, holder_acc, treasury_pool, evm_ with open(contract_path, 'rb') as f: contract_code = f.read() - steps_count = neon_cli().get_steps_count(evm_loader, sender_with_tokens, "deploy", contract_code.hex()) + steps_count = neon_cli().get_steps_count(evm_loader, sender_with_tokens, None, contract_code.hex()) resp = execute_transaction_steps_from_account_no_chain_id(operator_keypair, evm_loader, treasury_pool, holder_acc, [contract.solana_address, + contract.balance_account_address, + sender_with_tokens.balance_account_address, sender_with_tokens.solana_account_address], steps_count) check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) @@ -64,8 +68,8 @@ def test_call_contract_function_with_neon_transfer(self, operator_keypair, treas evm_loader): transfer_amount = random.randint(1, 1000) - sender_balance_before = get_neon_balance(solana_client, sender_with_tokens.solana_account_address) - contract_balance_before = get_neon_balance(solana_client, string_setter_contract.solana_address) + sender_balance_before = evm_loader.get_neon_balance(sender_with_tokens) + contract_balance_before = evm_loader.get_neon_balance(string_setter_contract.eth_address) text = ''.join(random.choice(string.ascii_letters) for _ in range(10)) @@ -76,20 +80,22 @@ def test_call_contract_function_with_neon_transfer(self, operator_keypair, treas resp = execute_transaction_steps_from_account_no_chain_id(operator_keypair, evm_loader, treasury_pool, holder_acc, [string_setter_contract.solana_address, + string_setter_contract.balance_account_address, + sender_with_tokens.balance_account_address, sender_with_tokens.solana_account_address] ) check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) check_transaction_logs_have_text(resp.value.transaction.transaction.signatures[0], "exit_status=0x11") - sender_balance_after = get_neon_balance(solana_client, sender_with_tokens.solana_account_address) - contract_balance_after = get_neon_balance(solana_client, string_setter_contract.solana_address) + sender_balance_after = evm_loader.get_neon_balance(sender_with_tokens) + contract_balance_after = evm_loader.get_neon_balance(string_setter_contract.eth_address) assert sender_balance_before - transfer_amount == sender_balance_after assert contract_balance_before + transfer_amount == contract_balance_after assert text in to_text( - neon_cli().call_contract_get_function(evm_loader, sender_with_tokens, string_setter_contract, - "get()")) + neon_cli().call_contract_get_function(evm_loader, sender_with_tokens, string_setter_contract, "get()") + ) def test_transaction_with_access_list(self, operator_keypair, treasury_pool, sender_with_tokens, calculator_contract, calculator_caller_contract, @@ -105,10 +111,13 @@ def test_transaction_with_access_list(self, operator_keypair, treasury_pool, signed_tx = make_contract_call_trx(sender_with_tokens, calculator_caller_contract, "callCalculator()", [], chain_id=None, access_list=access_list) write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.INVALID_CHAIN_ID): + + error = re.escape("assertion failed: trx.chain_id().is_none()") + with pytest.raises(solana.rpc.core.RPCException, match=error): execute_transaction_steps_from_account_no_chain_id(operator_keypair, evm_loader, treasury_pool, holder_acc, [calculator_contract.solana_address, calculator_caller_contract.solana_address, + sender_with_tokens.balance_account_address, sender_with_tokens.solana_account_address] ) diff --git a/tests/test_transaction_step_from_instruction.py b/tests/test_transaction_step_from_instruction.py index 76e808bf6..e9a567c28 100644 --- a/tests/test_transaction_step_from_instruction.py +++ b/tests/test_transaction_step_from_instruction.py @@ -15,7 +15,7 @@ from solana.rpc.commitment import Confirmed from solana.rpc.core import RPCException -from .solana_utils import get_neon_balance, solana_client, execute_transaction_steps_from_instruction, neon_cli, \ +from .solana_utils import solana_client, execute_transaction_steps_from_instruction, neon_cli, \ create_treasury_pool_address, send_transaction_step_from_instruction from .utils.assert_messages import InstructionAsserts from .utils.constants import TAG_FINALIZED_STATE @@ -32,18 +32,19 @@ class TestTransactionStepFromInstruction: def test_simple_transfer_transaction(self, operator_keypair, treasury_pool, evm_loader, sender_with_tokens, session_user, holder_acc): amount = 10 - sender_balance_before = get_neon_balance(solana_client, sender_with_tokens.solana_account_address) - recipient_balance_before = get_neon_balance(solana_client, session_user.solana_account_address) + sender_balance_before = evm_loader.get_neon_balance(sender_with_tokens) + recipient_balance_before = evm_loader.get_neon_balance(session_user) - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, amount) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, amount) resp = execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, signed_tx, [session_user.solana_account_address, - sender_with_tokens.solana_account_address], 0) + session_user.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address], 0) - sender_balance_after = get_neon_balance(solana_client, sender_with_tokens.solana_account_address) - recipient_balance_after = get_neon_balance(solana_client, session_user.solana_account_address) + sender_balance_after = evm_loader.get_neon_balance(sender_with_tokens) + recipient_balance_after = evm_loader.get_neon_balance(session_user) check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) check_transaction_logs_have_text(resp.value, "exit_status=0x11") @@ -62,10 +63,12 @@ def test_deploy_contract(self, operator_keypair, holder_acc, treasury_pool, evm_ with open(contract_path, 'rb') as f: contract_code = f.read() - steps_count = neon_cli().get_steps_count(evm_loader, sender_with_tokens, "deploy", contract_code.hex()) + steps_count = neon_cli().get_steps_count(evm_loader, sender_with_tokens, None, contract_code.hex()) resp = execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, signed_tx, [contract.solana_address, - sender_with_tokens.solana_account_address], + contract.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address], steps_count) check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) @@ -78,7 +81,9 @@ def test_call_contract_function_without_neon_transfer(self, operator_keypair, tr resp = execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, signed_tx, [string_setter_contract.solana_address, - sender_with_tokens.solana_account_address] + string_setter_contract.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address] ) check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) @@ -92,8 +97,8 @@ def test_call_contract_function_with_neon_transfer(self, operator_keypair, treas evm_loader, holder_acc, string_setter_contract): transfer_amount = random.randint(1, 1000) - sender_balance_before = get_neon_balance(solana_client, sender_with_tokens.solana_account_address) - contract_balance_before = get_neon_balance(solana_client, string_setter_contract.solana_address) + sender_balance_before = evm_loader.get_neon_balance(sender_with_tokens) + contract_balance_before = evm_loader.get_neon_balance(string_setter_contract.eth_address) text = ''.join(random.choice(string.ascii_letters) for i in range(10)) signed_tx = make_contract_call_trx(sender_with_tokens, string_setter_contract, "set(string)", [text], @@ -101,14 +106,16 @@ def test_call_contract_function_with_neon_transfer(self, operator_keypair, treas resp = execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, signed_tx, [string_setter_contract.solana_address, - sender_with_tokens.solana_account_address] + string_setter_contract.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address] ) check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) check_transaction_logs_have_text(resp.value, "exit_status=0x11") - sender_balance_after = get_neon_balance(solana_client, sender_with_tokens.solana_account_address) - contract_balance_after = get_neon_balance(solana_client, string_setter_contract.solana_address) + sender_balance_after = evm_loader.get_neon_balance(sender_with_tokens) + contract_balance_after = evm_loader.get_neon_balance(string_setter_contract.eth_address) assert sender_balance_before - transfer_amount == sender_balance_after assert contract_balance_before + transfer_amount == contract_balance_after @@ -122,154 +129,171 @@ def test_transfer_transaction_with_non_existing_recipient(self, operator_keypair recipient = Keypair.generate() recipient_ether = eth_keys.PrivateKey(recipient.secret_key[:32]).public_key.to_canonical_address() recipient_solana_address, _ = evm_loader.ether2program(recipient_ether) + recipient_balance_address = evm_loader.ether2balance(recipient_ether) amount = 10 - signed_tx = make_eth_transaction(recipient_ether, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, amount) + signed_tx = make_eth_transaction(recipient_ether, None, sender_with_tokens, amount) resp = execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, signed_tx, [PublicKey(recipient_solana_address), - sender_with_tokens.solana_account_address], 0) + recipient_balance_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address], 0) - recipient_balance_after = get_neon_balance(solana_client, PublicKey(recipient_solana_address)) + recipient_balance_after = evm_loader.get_neon_balance(recipient_ether) check_transaction_logs_have_text(resp.value, "exit_status=0x11") assert recipient_balance_after == amount def test_incorrect_chain_id(self, operator_keypair, holder_acc, treasury_pool, sender_with_tokens, session_user, evm_loader): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1, chain_id=1) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1, chain_id=1) with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.INVALID_CHAIN_ID): execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, signed_tx, [session_user.solana_account_address, - sender_with_tokens.solana_account_address], 0) + session_user.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address], 0) def test_incorrect_nonce(self, operator_keypair, treasury_pool, sender_with_tokens, evm_loader, session_user, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, signed_tx, [session_user.solana_account_address, - sender_with_tokens.solana_account_address], 0) + session_user.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address], 0) new_holder_acc = create_holder(operator_keypair) with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.INVALID_NONCE): execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, new_holder_acc, signed_tx, [session_user.solana_account_address, - sender_with_tokens.solana_account_address], 0) + session_user.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address], 0) def test_run_finalized_transaction(self, operator_keypair, treasury_pool, sender_with_tokens, evm_loader, session_user, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, signed_tx, [session_user.solana_account_address, - sender_with_tokens.solana_account_address], 0) + session_user.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address], 0) with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.TRX_ALREADY_FINALIZED): execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, signed_tx, [session_user.solana_account_address, - sender_with_tokens.solana_account_address], 0) + session_user.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address], 0) def test_insufficient_funds(self, operator_keypair, treasury_pool, evm_loader, session_user, holder_acc, sender_with_tokens): - user_balance = get_neon_balance(solana_client, session_user.solana_account_address) + user_balance = evm_loader.get_neon_balance(session_user) - signed_tx = make_eth_transaction(sender_with_tokens.eth_address, None, session_user.solana_account, - session_user.solana_account_address, user_balance + 1) + signed_tx = make_eth_transaction(sender_with_tokens.eth_address, None, session_user, user_balance + 1) with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.INSUFFICIENT_FUNDS): execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, signed_tx, [session_user.solana_account_address, - sender_with_tokens.solana_account_address], 0) + session_user.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address], 0) def test_gas_limit_reached(self, operator_keypair, treasury_pool, session_user, evm_loader, sender_with_tokens, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 10, gas=1) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 10, gas=1) with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.OUT_OF_GAS): execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, signed_tx, [session_user.solana_account_address, - sender_with_tokens.solana_account_address], 0) + session_user.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address], 0) def test_sender_missed_in_remaining_accounts(self, operator_keypair, treasury_pool, session_user, sender_with_tokens, evm_loader, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.ADDRESS_MUST_BE_PRESENT): execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, signed_tx, - [session_user.solana_account_address], 0) + [session_user.solana_account_address, + session_user.balance_account_address], 0) def test_recipient_missed_in_remaining_accounts(self, operator_keypair, treasury_pool, session_user, sender_with_tokens, evm_loader, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.ADDRESS_MUST_BE_PRESENT): execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, signed_tx, - [session_user.solana_account_address], 0) + [session_user.solana_account_address, + session_user.balance_account_address], 0) def test_incorrect_treasure_pool(self, operator_keypair, sender_with_tokens, evm_loader, session_user, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) index = 2 treasury = TreasuryPool(index, Keypair().generate().public_key, index.to_bytes(4, 'little')) - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.INVALID_TREASURE_ACC): + error = str.format(InstructionAsserts.INVALID_ACCOUNT, treasury.account) + with pytest.raises(solana.rpc.core.RPCException, match=error): execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury, holder_acc, signed_tx, [session_user.solana_account_address, - sender_with_tokens.solana_account_address], 0) + session_user.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address], 0) def test_incorrect_treasure_index(self, operator_keypair, sender_with_tokens, evm_loader, session_user, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) index = 2 treasury = TreasuryPool(index, create_treasury_pool_address(index), (index + 1).to_bytes(4, 'little')) - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.INVALID_TREASURE_ACC): + + error = str.format(InstructionAsserts.INVALID_ACCOUNT, treasury.account) + with pytest.raises(solana.rpc.core.RPCException, match=error): execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury, holder_acc, signed_tx, [session_user.solana_account_address, - sender_with_tokens.solana_account_address], 0) + session_user.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address], 0) def test_incorrect_operator_account(self, sender_with_tokens, evm_loader, treasury_pool, session_user, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) fake_operator = Keypair().generate() with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.ACC_NOT_FOUND): execute_transaction_steps_from_instruction(fake_operator, evm_loader, treasury_pool, holder_acc, signed_tx, [session_user.solana_account_address, - sender_with_tokens.solana_account_address], 0) + session_user.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address], 0) def test_operator_is_not_in_white_list(self, sender_with_tokens, evm_loader, treasury_pool, session_user, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.NOT_AUTHORIZED_OPERATOR): execute_transaction_steps_from_instruction(sender_with_tokens.solana_account, evm_loader, treasury_pool, holder_acc, signed_tx, [session_user.solana_account_address, - sender_with_tokens.solana_account_address], 0, + session_user.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address], 0, signer=sender_with_tokens.solana_account) def test_incorrect_system_program(self, sender_with_tokens, operator_keypair, evm_loader, treasury_pool, session_user, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) fake_sys_program_id = Keypair().generate().public_key with pytest.raises(solana.rpc.core.RPCException, @@ -277,34 +301,23 @@ def test_incorrect_system_program(self, sender_with_tokens, operator_keypair, ev send_transaction_step_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, signed_tx, [sender_with_tokens.solana_account_address, - session_user.solana_account_address], 1, operator_keypair, + sender_with_tokens.balance_account_address, + session_user.solana_account_address, + session_user.balance_account_address], 1, operator_keypair, system_program=fake_sys_program_id) - def test_incorrect_neon_program(self, sender_with_tokens, operator_keypair, evm_loader, treasury_pool, - session_user, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) - fake_neon_program_id = Keypair().generate().public_key - - with pytest.raises(solana.rpc.core.RPCException, - match=str.format(InstructionAsserts.NOT_NEON_PROGRAM, fake_neon_program_id)): - send_transaction_step_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, - signed_tx, - [sender_with_tokens.solana_account_address, - session_user.solana_account_address], 1, operator_keypair, - evm_loader_public_key=fake_neon_program_id) - def test_incorrect_holder_account(self, sender_with_tokens, operator_keypair, evm_loader, treasury_pool, session_user): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens.solana_account, - sender_with_tokens.solana_account_address, 1) + signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) fake_holder_acc = Keypair.generate().public_key with pytest.raises(solana.rpc.core.RPCException, match=str.format(InstructionAsserts.NOT_PROGRAM_OWNED, fake_holder_acc)): send_transaction_step_from_instruction(operator_keypair, evm_loader, treasury_pool, fake_holder_acc, signed_tx, [sender_with_tokens.solana_account_address, - session_user.solana_account_address], 1, operator_keypair) + sender_with_tokens.balance_account_address, + session_user.solana_account_address, + session_user.balance_account_address], 1, operator_keypair) @pytest.mark.parametrize("value", [0, 10]) def test_transaction_with_access_list(self, operator_keypair, treasury_pool, sender_with_tokens, @@ -323,7 +336,9 @@ def test_transaction_with_access_list(self, operator_keypair, treasury_pool, sen value=value, access_list=access_list) resp = execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, signed_tx, [string_setter_contract.solana_address, - sender_with_tokens.solana_account_address] + string_setter_contract.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address] ) check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) @@ -347,10 +362,12 @@ def test_deploy_contract_with_access_list(self, operator_keypair, holder_acc, tr with open(contract_path, 'rb') as f: contract_code = f.read() - steps_count = neon_cli().get_steps_count(evm_loader, sender_with_tokens, "deploy", contract_code.hex()) + steps_count = neon_cli().get_steps_count(evm_loader, sender_with_tokens, None, contract_code.hex()) resp = execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, signed_tx, [contract.solana_address, - sender_with_tokens.solana_account_address], + contract.balance_account_address, + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address], steps_count) check_transaction_logs_have_text(resp.value, "exit_status=0x12") @@ -363,7 +380,8 @@ def test_contract_call_unchange_storage_function(self, rw_lock_contract, session signed_tx, [rw_lock_caller.solana_address, rw_lock_contract.solana_address, - session_user.solana_account_address]) + session_user.solana_account_address, + session_user.balance_account_address]) check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) check_transaction_logs_have_text(resp.value, "exit_status=0x12") @@ -376,7 +394,8 @@ def test_contract_call_set_function(self, rw_lock_contract, session_user, evm_lo signed_tx, [rw_lock_caller.solana_address, rw_lock_contract.solana_address, - session_user.solana_account_address], 1000) + session_user.solana_account_address, + session_user.balance_account_address], 1000) check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) check_transaction_logs_have_text(resp.value, "exit_status=0x11") @@ -391,7 +410,8 @@ def test_contract_call_get_function(self, rw_lock_contract, session_user, evm_lo signed_tx, [rw_lock_caller.solana_address, rw_lock_contract.solana_address, - session_user.solana_account_address], 1000) + session_user.solana_account_address, + session_user.balance_account_address], 1000) check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) check_transaction_logs_have_text(resp.value, "exit_status=0x12") @@ -407,8 +427,10 @@ def test_contract_call_update_storage_map_function(self, rw_lock_contract, sessi session_user.eth_address.hex(), rw_lock_caller.eth_address.hex(), data.hex()) - additional_accounts = [session_user.solana_account_address, rw_lock_contract.solana_address, - rw_lock_caller.solana_address] + additional_accounts = [session_user.solana_account_address, + session_user.balance_account_address, + rw_lock_contract.solana_address, + rw_lock_caller.solana_address] for acc in result['solana_accounts']: additional_accounts.append(PublicKey(acc['pubkey'])) @@ -431,6 +453,7 @@ def test_one_user_call_2_contracts(self, rw_lock_contract, string_setter_contrac signed_tx = make_contract_call_trx(user_account, rw_lock_contract, 'unchange_storage(uint8,uint8)', [1, 1]) send_transaction_step_from_instruction(operator_keypair, evm_loader, treasury_pool, new_holder_acc, signed_tx, [user_account.solana_account_address, + user_account.balance_account_address, rw_lock_contract.solana_address], 1, operator_keypair) signed_tx2 = make_contract_call_trx(user_account, string_setter_contract, 'get()') @@ -438,6 +461,7 @@ def test_one_user_call_2_contracts(self, rw_lock_contract, string_setter_contrac with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.LOCKED_ACC): send_transaction_step_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc2, signed_tx2, [user_account.solana_account_address, + user_account.balance_account_address, string_setter_contract.solana_address], 1, operator_keypair) def test_2_users_call_the_same_contract(self, rw_lock_contract, user_account, @@ -447,6 +471,7 @@ def test_2_users_call_the_same_contract(self, rw_lock_contract, user_account, send_transaction_step_from_instruction(operator_keypair, evm_loader, treasury_pool, new_holder_acc, signed_tx, [user_account.solana_account_address, + user_account.balance_account_address, rw_lock_contract.solana_address], 1, operator_keypair) signed_tx2 = make_contract_call_trx(session_user, rw_lock_contract, 'get_text()') @@ -455,6 +480,7 @@ def test_2_users_call_the_same_contract(self, rw_lock_contract, user_account, with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.LOCKED_ACC): send_transaction_step_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc2, signed_tx2, [session_user.solana_account_address, + session_user.balance_account_address, rw_lock_contract.solana_address], 1, operator_keypair) def test_two_contracts_call_same_contract(self, rw_lock_contract, user_account, @@ -472,6 +498,7 @@ def test_two_contracts_call_same_contract(self, rw_lock_contract, user_account, send_transaction_step_from_instruction(operator_keypair, evm_loader, treasury_pool, new_holder_acc, signed_tx1, [user_account.solana_account_address, + user_account.balance_account_address, rw_lock_contract.solana_address, contract1.solana_address], 1, operator_keypair) @@ -479,6 +506,7 @@ def test_two_contracts_call_same_contract(self, rw_lock_contract, user_account, with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.LOCKED_ACC): send_transaction_step_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc2, signed_tx2, [session_user.solana_account_address, + session_user.balance_account_address, rw_lock_contract.solana_address, contract2.solana_address], 1, operator_keypair) @@ -493,6 +521,7 @@ def test_next_operator_can_continue_trx_after_some_time(self, rw_lock_contract, send_transaction_step_from_instruction(operator_keypair, evm_loader, treasury_pool, new_holder_acc, signed_tx, [user_account.solana_account_address, + user_account.balance_account_address, rw_lock_contract.solana_address], 1, operator_keypair) # next operator can't continue trx during OPERATOR_PRIORITY_SLOTS*0.4 with pytest.raises(solana.rpc.core.RPCException, @@ -500,16 +529,19 @@ def test_next_operator_can_continue_trx_after_some_time(self, rw_lock_contract, send_transaction_step_from_instruction(second_operator_keypair, evm_loader, treasury_pool, new_holder_acc, signed_tx, [user_account.solana_account_address, + user_account.balance_account_address, rw_lock_contract.solana_address], 500, second_operator_keypair) time.sleep(15) send_transaction_step_from_instruction(second_operator_keypair, evm_loader, treasury_pool, new_holder_acc, signed_tx, [user_account.solana_account_address, + user_account.balance_account_address, rw_lock_contract.solana_address], 500, second_operator_keypair) resp = send_transaction_step_from_instruction(second_operator_keypair, evm_loader, treasury_pool, new_holder_acc, signed_tx, [user_account.solana_account_address, + user_account.balance_account_address, rw_lock_contract.solana_address], 1, second_operator_keypair) check_transaction_logs_have_text(resp.value, "exit_status=0x11") @@ -532,8 +564,10 @@ def test_add_waste_to_trx(self, sender_with_tokens, operator_keypair, treasury_p ) with pytest.raises(RPCException, match="Program log: RLP error: RlpIncorrectListLen"): execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, - signed_tx_new, [sender_with_tokens.solana_account_address, - string_setter_contract.solana_address]) + signed_tx_new, + [sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address, + string_setter_contract.solana_address]) def test_add_waste_to_trx_without_decoding(self, sender_with_tokens, operator_keypair, treasury_pool, evm_loader, holder_acc, @@ -549,15 +583,18 @@ def test_add_waste_to_trx_without_decoding(self, sender_with_tokens, operator_ke ) with pytest.raises(RPCException, match="Program log: RLP error: RlpInconsistentLengthAndData"): execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, - signed_tx_new, [sender_with_tokens.solana_account_address, - string_setter_contract.solana_address]) + signed_tx_new, + [sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address, + string_setter_contract.solana_address]) def test_old_trx_type_with_leading_zeros(self, sender_with_tokens, operator_keypair, evm_loader, string_setter_contract, treasury_pool, holder_acc): text = ''.join(random.choice(string.ascii_letters) for _ in range(10)) signed_tx = make_contract_call_trx(sender_with_tokens, string_setter_contract, "set(string)", [text]) - new_raw_trx = HexBytes('0x' + (b'\x00' + bytes.fromhex(signed_tx.rawTransaction.hex()[2:])).hex()) + new_raw_trx = HexBytes(bytes([0]) + signed_tx.rawTransaction) + signed_tx_new = SignedTransaction( rawTransaction=new_raw_trx, hash=signed_tx.hash, @@ -568,6 +605,7 @@ def test_old_trx_type_with_leading_zeros(self, sender_with_tokens, operator_keyp resp = execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, signed_tx_new, [string_setter_contract.solana_address, - sender_with_tokens.solana_account_address] + sender_with_tokens.solana_account_address, + sender_with_tokens.balance_account_address] ) check_transaction_logs_have_text(resp.value, "exit_status=0x11") diff --git a/tests/utils/assert_messages.py b/tests/utils/assert_messages.py index 39a69e9aa..43511cd81 100644 --- a/tests/utils/assert_messages.py +++ b/tests/utils/assert_messages.py @@ -2,11 +2,11 @@ class InstructionAsserts: LOCKED_ACC = "trying to execute transaction on rw locked account" INVALID_CHAIN_ID = "Invalid Chain ID" INVALID_NONCE = "Invalid Nonce" - TRX_ALREADY_FINALIZED = "is finalized" + TRX_ALREADY_FINALIZED = "Transaction already finalized" INSUFFICIENT_FUNDS = "Insufficient balance" OUT_OF_GAS = "Out of Gas" ADDRESS_MUST_BE_PRESENT = r"address .* must be present in the transaction" - INVALID_TREASURE_ACC = "invalid treasure account" + INVALID_ACCOUNT = "Account {} - invalid public key" ACC_NOT_FOUND = "AccountNotFound" NOT_AUTHORIZED_OPERATOR = "Operator is not authorized" NOT_SYSTEM_PROGRAM = "Account {} - is not system program" @@ -15,3 +15,4 @@ class InstructionAsserts: INVALID_HOLDER_OWNER = "Holder Account - invalid owner" INVALID_OPERATOR_KEY = "operator.key != storage.operator" HOLDER_OVERFLOW = "Checked Integer Math Overflow" + HOLDER_INSUFFICIENT_SIZE = "Holder Account - insufficient size" diff --git a/tests/utils/constants.py b/tests/utils/constants.py index 0e78ae976..cdeff51bc 100644 --- a/tests/utils/constants.py +++ b/tests/utils/constants.py @@ -10,19 +10,18 @@ KECCAKPROG_ADDRESS = "KeccakSecp256k11111111111111111111111111111" RENT_ID_ADDRESS = "SysvarRent111111111111111111111111111111111" INCINERATOR_ADDRESS = "1nc1nerator11111111111111111111111111111111" -TREASURY_POOL_SEED = os.environ.get("NEON_POOL_SEED", "treasury_pool") -TREASURY_POOL_COUNT = os.environ.get("NEON_POOL_COUNT", 128) +TREASURY_POOL_SEED = os.environ.get("NEON_TREASURY_POOL_SEED", "treasury_pool") +TREASURY_POOL_COUNT = os.environ.get("NEON_TREASURY_POOL_COUNT", 128) COMPUTE_BUDGET_ID: PublicKey = PublicKey("ComputeBudget111111111111111111111111111111") ACCOUNT_SEED_VERSION = b'\3' TAG_EMPTY = 0 -TAG_ACCOUNT_V3 = 12 -TAG_STATE = 22 -TAG_FINALIZED_STATE = 31 -TAG_CONTRACT_STORAGE = 42 -TAG_HOLDER = 51 +TAG_STATE = 23 +TAG_FINALIZED_STATE = 32 +TAG_HOLDER = 52 SOLANA_URL = os.environ.get("SOLANA_URL", "http://localhost:8899") EVM_LOADER = os.environ.get("EVM_LOADER") NEON_TOKEN_MINT_ID: PublicKey = PublicKey(os.environ.get("NEON_TOKEN_MINT")) +CHAIN_ID = int(os.environ.get("NEON_CHAIN_ID")) diff --git a/tests/utils/contract.py b/tests/utils/contract.py index 21bc071c4..1e2d7e123 100644 --- a/tests/utils/contract.py +++ b/tests/utils/contract.py @@ -7,9 +7,9 @@ from eth_utils import abi from solana.keypair import Keypair -from .types import Caller, TreasuryPool +from .types import Caller, Contract, TreasuryPool from ..solana_utils import solana_client, \ - get_transaction_count, EvmLoader, write_transaction_to_holder_account, \ + EvmLoader, write_transaction_to_holder_account, \ send_transaction_step_from_account from .storage import create_holder from .ethereum import create_contract_address, make_eth_transaction @@ -33,12 +33,13 @@ def make_deployment_transaction( if encoded_args is not None: data += encoded_args + nonce = EvmLoader(user.solana_account).get_neon_nonce(user.eth_address) tx = { 'to': None, 'value': 0, 'gas': gas, 'gasPrice': 0, - 'nonce': get_transaction_count(solana_client, user.solana_account_address), + 'nonce': nonce, 'data': data } if chain_id: @@ -46,7 +47,7 @@ def make_deployment_transaction( if access_list: tx['accessList'] = access_list tx['type'] = 1 - print(tx) + return w3.eth.account.sign_transaction(tx, user.solana_account.secret_key[:32]) @@ -61,8 +62,8 @@ def make_contract_call_trx(user, contract, function_signature, params=None, valu elif isinstance(param, str): data += eth_abi.encode(['string'], [param]) - signed_tx = make_eth_transaction(contract.eth_address, data, user.solana_account, user.solana_account_address, - value=value, chain_id=chain_id, access_list=access_list, type=trx_type) + signed_tx = make_eth_transaction(contract.eth_address, data, user, value=value, + chain_id=chain_id, access_list=access_list, type=trx_type) return signed_tx @@ -78,7 +79,7 @@ def deploy_contract( print("Deploying contract") if isinstance(contract_path, str): contract_path = pathlib.Path(contract_path) - contract = create_contract_address(user, evm_loader) + contract: Contract = create_contract_address(user, evm_loader) holder_acc = create_holder(operator) signed_tx = make_deployment_transaction(user, contract_path, encoded_args=encoded_args) write_transaction_to_holder_account(signed_tx, holder_acc, operator) @@ -86,7 +87,9 @@ def deploy_contract( contract_deployed = False while not contract_deployed: receipt = send_transaction_step_from_account(operator, evm_loader, treasury_pool, holder_acc, - [contract.solana_address, user.solana_account_address], + [contract.solana_address, + contract.balance_account_address, + user.balance_account_address], step_count, operator) if receipt.value.transaction.meta.err: raise AssertionError(f"Can't deploy contract: {receipt.value.transaction.meta.err}") diff --git a/tests/utils/ethereum.py b/tests/utils/ethereum.py index 0c8cb4a0f..28e5fe1ba 100644 --- a/tests/utils/ethereum.py +++ b/tests/utils/ethereum.py @@ -1,35 +1,35 @@ from typing import Union -from base58 import b58encode from sha3 import keccak_256 from solana.keypair import Keypair from solana.publickey import PublicKey from web3.auto import w3 -from .constants import ACCOUNT_SEED_VERSION +from .constants import CHAIN_ID + from .types import Caller, Contract from ..eth_tx_utils import pack -from ..solana_utils import EvmLoader, solana_client, get_transaction_count +from ..solana_utils import EvmLoader def create_contract_address(user: Caller, evm_loader: EvmLoader) -> Contract: # Create contract address from (caller_address, nonce) - user_nonce = get_transaction_count(solana_client, user.solana_account_address) + user_nonce = evm_loader.get_neon_nonce(user.eth_address) contract_eth_address = keccak_256(pack([user.eth_address, user_nonce or None])).digest()[-20:] - contract_solana_address, contract_nonce = evm_loader.ether2program(contract_eth_address) - seed = b58encode(ACCOUNT_SEED_VERSION + contract_eth_address).decode('utf8') + contract_solana_address, _ = evm_loader.ether2program(contract_eth_address) + contract_neon_address = evm_loader.ether2balance(contract_eth_address) + print(f"Contract addresses: " f" eth {contract_eth_address.hex()}, " - f" solana {contract_solana_address}" - f" nonce {contract_nonce}" - f" user nonce {user_nonce}" - f" seed {seed}") - return Contract(contract_eth_address, PublicKey(contract_solana_address), contract_nonce, seed) + f" solana {contract_solana_address}") + + return Contract(contract_eth_address, PublicKey(contract_solana_address), contract_neon_address) -def make_eth_transaction(to_addr: bytes, data: Union[bytes, None], signer: Keypair, from_solana_user: PublicKey, - value: int = 0, chain_id=111, gas=9999999999, access_list=None, type=None): - nonce = get_transaction_count(solana_client, from_solana_user) +def make_eth_transaction(to_addr: bytes, data: Union[bytes, None], caller: Caller, + value: int = 0, chain_id=CHAIN_ID, gas=9999999999, access_list=None, type=None): + + nonce = EvmLoader(caller.solana_account).get_neon_nonce(caller.eth_address) tx = {'to': to_addr, 'value': value, 'gas': gas, 'gasPrice': 0, 'nonce': nonce} @@ -43,4 +43,4 @@ def make_eth_transaction(to_addr: bytes, data: Union[bytes, None], signer: Keypa tx['accessList'] = access_list if type is not None: tx['type'] = type - return w3.eth.account.sign_transaction(tx, signer.secret_key[:32]) + return w3.eth.account.sign_transaction(tx, caller.solana_account.secret_key[:32]) diff --git a/tests/utils/instructions.py b/tests/utils/instructions.py index ffdf9b78b..1121c60e2 100644 --- a/tests/utils/instructions.py +++ b/tests/utils/instructions.py @@ -5,10 +5,9 @@ from solana.publickey import PublicKey import solana.system_program as sp from solana.transaction import AccountMeta, TransactionInstruction, Transaction - from .constants import EVM_LOADER, INCINERATOR_ADDRESS -DEFAULT_UNITS = 500 * 1000 +DEFAULT_UNITS = 1_400_000 DEFAULT_HEAP_FRAME = 256 * 1024 DEFAULT_ADDITIONAL_FEE = 0 COMPUTE_BUDGET_ID: PublicKey = PublicKey("ComputeBudget111111111111111111111111111111") @@ -76,7 +75,6 @@ def make_ExecuteTrxFromInstruction( message: bytes, additional_accounts: tp.List[PublicKey], system_program=sp.SYS_PROGRAM_ID, - evm_loader_public_key=PublicKey(EVM_LOADER) ): data = bytes.fromhex('1f') + treasury_buffer + message operator_ether = eth_keys.PrivateKey(operator.secret_key[:32]).public_key.to_canonical_address() @@ -84,13 +82,12 @@ def make_ExecuteTrxFromInstruction( print("Operator: ", operator.public_key) print("Treasury: ", treasury_address) print("Operator ether: ", operator_ether.hex()) - print("Operator eth solana: ", evm_loader.ether2program(operator_ether)[0]) + print("Operator eth solana: ", evm_loader.ether2balance(operator_ether)) accounts = [ AccountMeta(pubkey=operator.public_key, is_signer=True, is_writable=True), AccountMeta(pubkey=treasury_address, is_signer=False, is_writable=True), - AccountMeta(pubkey=PublicKey(evm_loader.ether2program(operator_ether)[0]), is_signer=False, is_writable=True), + AccountMeta(pubkey=PublicKey(evm_loader.ether2balance(operator_ether)), is_signer=False, is_writable=True), AccountMeta(system_program, is_signer=False, is_writable=True), - AccountMeta(evm_loader_public_key, is_signer=False, is_writable=False), ] for acc in additional_accounts: print("Additional acc ", acc) @@ -112,7 +109,7 @@ def make_ExecuteTrxFromAccountDataIterativeOrContinue( step_count: int, additional_accounts: tp.List[PublicKey], sys_program_id=sp.SYS_PROGRAM_ID, - neon_evm_program_id=PublicKey(EVM_LOADER), tag=33): + tag=33): # 33 - TransactionStepFromAccount # 34 - TransactionStepFromAccountNoChainId d = tag.to_bytes(1, "little") + treasury_buffer + step_count.to_bytes(8, byteorder="little") @@ -122,15 +119,13 @@ def make_ExecuteTrxFromAccountDataIterativeOrContinue( print("Operator: ", operator.public_key) print("Treasury: ", treasury_address) print("Operator ether: ", operator_ether.hex()) - print("Operator eth solana: ", evm_loader.ether2program(operator_ether)[0]) + print("Operator eth solana: ", evm_loader.ether2balance(operator_ether)) accounts = [ AccountMeta(pubkey=holder_address, is_signer=False, is_writable=True), AccountMeta(pubkey=operator.public_key, is_signer=True, is_writable=True), AccountMeta(pubkey=treasury_address, is_signer=False, is_writable=True), - AccountMeta(pubkey=PublicKey(evm_loader.ether2program(operator_ether)[0]), is_signer=False, is_writable=True), + AccountMeta(pubkey=PublicKey(evm_loader.ether2balance(operator_ether)), is_signer=False, is_writable=True), AccountMeta(sys_program_id, is_signer=False, is_writable=True), - # Neon EVM account - AccountMeta(neon_evm_program_id, is_signer=False, is_writable=False), ] for acc in additional_accounts: @@ -153,8 +148,7 @@ def make_PartialCallOrContinueFromRawEthereumTX( treasury_buffer: bytes, step_count: int, additional_accounts: tp.List[PublicKey], - system_program=sp.SYS_PROGRAM_ID, - evm_loader_public_key=PublicKey(EVM_LOADER)): + system_program=sp.SYS_PROGRAM_ID): d = (32).to_bytes(1, "little") + treasury_buffer + step_count.to_bytes(8, byteorder="little") + instruction operator_ether = eth_keys.PrivateKey(operator.secret_key[:32]).public_key.to_canonical_address() @@ -162,10 +156,8 @@ def make_PartialCallOrContinueFromRawEthereumTX( AccountMeta(pubkey=storage_address, is_signer=False, is_writable=True), AccountMeta(pubkey=operator.public_key, is_signer=True, is_writable=True), AccountMeta(pubkey=treasury_address, is_signer=False, is_writable=True), - AccountMeta(pubkey=PublicKey(evm_loader.ether2program(operator_ether)[0]), is_signer=False, is_writable=True), + AccountMeta(pubkey=evm_loader.ether2balance(operator_ether), is_signer=False, is_writable=True), AccountMeta(system_program, is_signer=False, is_writable=True), - # Neon EVM account - AccountMeta(evm_loader_public_key, is_signer=False, is_writable=False), ] for acc in additional_accounts: accounts.append(AccountMeta(acc, is_signer=False, is_writable=True), ) @@ -177,13 +169,14 @@ def make_PartialCallOrContinueFromRawEthereumTX( ) -def make_Cancel(storage_address: PublicKey, operator: Keypair, hash: bytes, additional_accounts: tp.List[PublicKey]): +def make_Cancel(evm_loader: "EvmLoader", storage_address: PublicKey, operator: Keypair, hash: bytes, additional_accounts: tp.List[PublicKey]): d = (35).to_bytes(1, "little") + hash + operator_ether = eth_keys.PrivateKey(operator.secret_key[:32]).public_key.to_canonical_address() accounts = [ AccountMeta(pubkey=storage_address, is_signer=False, is_writable=True), AccountMeta(pubkey=operator.public_key, is_signer=True, is_writable=True), - AccountMeta(pubkey=PublicKey(INCINERATOR_ADDRESS), is_signer=False, is_writable=True), + AccountMeta(pubkey=evm_loader.ether2balance(operator_ether), is_signer=False, is_writable=True), ] for acc in additional_accounts: @@ -198,18 +191,23 @@ def make_Cancel(storage_address: PublicKey, operator: Keypair, hash: bytes, addi def make_DepositV03( ether_address: bytes, - solana_account: PublicKey, + chain_id: int, + balance_account: PublicKey, + contract_account: PublicKey, + mint: PublicKey, source: PublicKey, pool: PublicKey, token_program: PublicKey, operator_pubkey: PublicKey, ) -> TransactionInstruction: - data = bytes.fromhex('27') + ether_address + data = bytes.fromhex('27') + ether_address + chain_id.to_bytes(8, 'little') accounts = [ + AccountMeta(pubkey=mint, is_signer=False, is_writable=True), AccountMeta(pubkey=source, is_signer=False, is_writable=True), AccountMeta(pubkey=pool, is_signer=False, is_writable=True), - AccountMeta(pubkey=solana_account, is_signer=False, is_writable=True), + AccountMeta(pubkey=balance_account, is_signer=False, is_writable=True), + AccountMeta(pubkey=contract_account, is_signer=False, is_writable=True), AccountMeta(pubkey=token_program, is_signer=False, is_writable=False), AccountMeta(pubkey=operator_pubkey, is_signer=True, is_writable=True), AccountMeta(pubkey=sp.SYS_PROGRAM_ID, is_signer=False, is_writable=False), diff --git a/tests/utils/layouts.py b/tests/utils/layouts.py index 96046c186..68cb2dcfa 100644 --- a/tests/utils/layouts.py +++ b/tests/utils/layouts.py @@ -2,9 +2,11 @@ STORAGE_ACCOUNT_INFO_LAYOUT = Struct( "tag" / Int8ul, + "blocked" / Int8ul, "owner" / Bytes(32), "hash" / Bytes(32), "caller" / Bytes(20), + "chain_id" / Int64ul, "gas_limit" / Bytes(32), "gas_price" / Bytes(32), "gas_used" / Bytes(32), @@ -15,6 +17,7 @@ HOLDER_ACCOUNT_INFO_LAYOUT = Struct( "tag" / Int8ul, + "blocked" / Int8ul, "owner" / Bytes(32), "hash" / Bytes(32), "len" / Int64ul @@ -23,23 +26,23 @@ FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT = Struct( "tag" / Int8ul, + "blocked" / Int8ul, "owner" / Bytes(32), "hash" / Bytes(32), ) -ACCOUNT_INFO_LAYOUT = Struct( +CONTRACT_ACCOUNT_LAYOUT = Struct( "type" / Int8ul, - "ether" / Bytes(20), - "nonce" / Int8ul, - "trx_count" / Bytes(8), - "balance" / Bytes(32), + "blocked" / Int8ul, + "chain_id" / Int64ul, "generation" / Int32ul, - "code_size" / Int32ul, - "is_rw_blocked" / Int8ul, ) - -CREATE_ACCOUNT_LAYOUT = Struct( - "ether" / Bytes(20), -) +BALANCE_ACCOUNT_LAYOUT = Struct( + "type" / Int8ul, + "blocked" / Int8ul, + "chain_id" / Int64ul, + "trx_count" / Int64ul, + "balance" / Bytes(32), +) \ No newline at end of file diff --git a/tests/utils/neon_api_client.py b/tests/utils/neon_api_client.py index 2599f6ce3..977085c9a 100644 --- a/tests/utils/neon_api_client.py +++ b/tests/utils/neon_api_client.py @@ -1,35 +1,41 @@ -import os - import requests +from .constants import CHAIN_ID, NEON_TOKEN_MINT_ID + class NeonApiClient: def __init__(self, url): self.url = url - self.token_mint = os.environ.get('NEON_TOKEN_MINT') - self.chain_id = os.environ.get('NEON_CHAIN_ID') self.headers = {"Content-Type": "application/json"} - def emulate(self, sender, contract, gas_limit=None, data=None, token_mint=None, chain_id=None, - cached_accounts=None, solana_accounts=None, max_steps_to_execute=500000, - value='0x0'): - token_mint = self.token_mint if token_mint is None else token_mint - chain_id = int(self.chain_id) if chain_id is None else chain_id + def emulate(self, sender, contract, data=bytes(), chain_id=CHAIN_ID, value='0x0', max_steps_to_execute=500000): + body = { + "step_limit": max_steps_to_execute, + "tx": { + "from": sender, + "to": contract, + "data": data.hex(), + "chain_id": chain_id, + "value": value + }, + "accounts": [] + } - body = {"token_mint": token_mint, "chain_id": chain_id, - "max_steps_to_execute": max_steps_to_execute, "cached_accounts": cached_accounts, - "solana_accounts": solana_accounts, - "sender": sender, - "contract": contract, "value": value, "gas_limit": gas_limit} - if contract: - body["contract"] = contract - if data: - body['data'] = list(data) resp = requests.post(url=f"{self.url}/emulate", json=body, headers=self.headers) + print(resp.text) return resp.json() def get_storage_at(self, contract_id, index="0x0"): - return requests.get(f"{self.url}/get-storage-at?contract_id={contract_id}&index={index}").json() + body = { + "contract": contract_id, + "index": index + } + return requests.post(url=f"{self.url}/storage", json=body, headers=self.headers).json() - def get_ether_account_data(self, ether): - return requests.get(f"{self.url}/get-ether-account-data?ether={ether}").json() + def get_ether_account_data(self, ether, chain_id = CHAIN_ID): + body = { + "account": [ + { "address": ether, "chain_id": chain_id } + ] + } + return requests.post(url=f"{self.url}/balance", json=body, headers=self.headers).json() \ No newline at end of file diff --git a/tests/utils/types.py b/tests/utils/types.py index 9e07cdecf..e1001f6e5 100644 --- a/tests/utils/types.py +++ b/tests/utils/types.py @@ -14,8 +14,8 @@ class TreasuryPool: class Caller: solana_account: Keypair solana_account_address: PublicKey + balance_account_address: PublicKey eth_address: bytes - nonce: int token_address: PublicKey @@ -23,5 +23,4 @@ class Caller: class Contract: eth_address: bytes solana_address: PublicKey - nonce: int - seed: str + balance_account_address: PublicKey From 7fbd045e819e6ddf7ec76343902984db98428705 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Tue, 14 Nov 2023 18:24:50 +0300 Subject: [PATCH 060/318] [Multi Tokens] CI --- ci/deploy-evm.sh | 2 +- ci/wait-for-neon.sh | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ci/deploy-evm.sh b/ci/deploy-evm.sh index e89df5c6d..64c5efe59 100755 --- a/ci/deploy-evm.sh +++ b/ci/deploy-evm.sh @@ -29,4 +29,4 @@ fi echo "Deployed finished from " $(solana address) " with " $(solana balance) neon-cli --url $SOLANA_URL --evm_loader $EVM_LOADER \ --keypair evm_loader-keypair.json \ - --loglevel warn init-environment --send-trx --keys-dir keys/ + --loglevel debug init-environment --send-trx --keys-dir keys/ diff --git a/ci/wait-for-neon.sh b/ci/wait-for-neon.sh index 3554fb277..19b676ac3 100755 --- a/ci/wait-for-neon.sh +++ b/ci/wait-for-neon.sh @@ -7,7 +7,7 @@ set -euo pipefail ./wait-for-solana.sh "$@" if [ $# -eq 0 ]; then - if neon-cli --url $SOLANA_URL --evm_loader $EVM_LOADER --loglevel off init-environment > /dev/null; then + if neon-cli --url $SOLANA_URL --commitment finalized --evm_loader $EVM_LOADER --loglevel off init-environment > /dev/null; then echo "Executed neon-cli init-environment successfully" exit 0 fi @@ -16,7 +16,7 @@ else echo "Waiting $WAIT_TIME seconds for NeonEVM to be available at $SOLANA_URL:$EVM_LOADER" for i in $(seq 1 $WAIT_TIME); do echo "Try neon-cli init-environment count=$i" - if neon-cli --url $SOLANA_URL --evm_loader $EVM_LOADER --loglevel off init-environment > /dev/null; then + if neon-cli --url $SOLANA_URL --commitment finalized --evm_loader $EVM_LOADER --loglevel off init-environment > /dev/null; then echo "Executed neon-cli init-environment successfully after count=$i" exit 0 fi From b31d93155e949205f43710bb25a7776aa65dc963 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Wed, 15 Nov 2023 11:30:43 +0300 Subject: [PATCH 061/318] [Multi Tokens] Bugfixes --- evm_loader/lib/src/commands/get_config.rs | 2 +- evm_loader/lib/src/rpc/db_call_client.rs | 6 ++++-- evm_loader/lib/src/rpc/mod.rs | 2 +- evm_loader/lib/src/rpc/validator_client.rs | 21 ++++++++++++++----- .../program/src/account_storage/apply.rs | 9 ++++++-- 5 files changed, 29 insertions(+), 11 deletions(-) diff --git a/evm_loader/lib/src/commands/get_config.rs b/evm_loader/lib/src/commands/get_config.rs index 8db6fd2c6..5c70e85e8 100644 --- a/evm_loader/lib/src/commands/get_config.rs +++ b/evm_loader/lib/src/commands/get_config.rs @@ -123,7 +123,7 @@ impl<'r> ConfigSimulator<'r> { program_id: Pubkey, ) -> NeonResult> { let simulator = if rpc_client.can_simulate_transaction() { - let identity = rpc_client.identity().await?; + let identity = rpc_client.get_account_with_sol().await?; Self::Rpc(identity, rpc_client) } else { let program_data = read_program_data_from_account(rpc_client, program_id).await?; diff --git a/evm_loader/lib/src/rpc/db_call_client.rs b/evm_loader/lib/src/rpc/db_call_client.rs index 4db00cd22..605676dd4 100644 --- a/evm_loader/lib/src/rpc/db_call_client.rs +++ b/evm_loader/lib/src/rpc/db_call_client.rs @@ -218,8 +218,10 @@ impl Rpc for CallDbClient { )) } - async fn identity(&self) -> ClientResult { - Err(e!("identity() not implemented for db_call_client")) + async fn get_account_with_sol(&self) -> ClientResult { + Err(e!( + "get_account_with_sol() not implemented for db_call_client" + )) } fn as_any(&self) -> &dyn Any { diff --git a/evm_loader/lib/src/rpc/mod.rs b/evm_loader/lib/src/rpc/mod.rs index 8a23bb5dd..8b6dd1c89 100644 --- a/evm_loader/lib/src/rpc/mod.rs +++ b/evm_loader/lib/src/rpc/mod.rs @@ -89,7 +89,7 @@ pub trait Rpc { instructions: &[Instruction], ) -> RpcResult; - async fn identity(&self) -> ClientResult; + async fn get_account_with_sol(&self) -> ClientResult; fn as_any(&self) -> &dyn Any; } diff --git a/evm_loader/lib/src/rpc/validator_client.rs b/evm_loader/lib/src/rpc/validator_client.rs index 48872c8e7..4bfc488b9 100644 --- a/evm_loader/lib/src/rpc/validator_client.rs +++ b/evm_loader/lib/src/rpc/validator_client.rs @@ -3,7 +3,10 @@ use async_trait::async_trait; use solana_client::{ client_error::Result as ClientResult, nonblocking::rpc_client::RpcClient, - rpc_config::{RpcSendTransactionConfig, RpcSimulateTransactionConfig, RpcTransactionConfig}, + rpc_config::{ + RpcLargestAccountsConfig, RpcSendTransactionConfig, RpcSimulateTransactionConfig, + RpcTransactionConfig, + }, rpc_response::{RpcResult, RpcSimulateTransactionResult}, }; use solana_sdk::{ @@ -19,7 +22,7 @@ use solana_sdk::{ use solana_transaction_status::{ EncodedConfirmedBlock, EncodedConfirmedTransactionWithStatusMeta, TransactionStatus, }; -use std::any::Any; +use std::{any::Any, str::FromStr}; #[async_trait(?Send)] impl Rpc for RpcClient { @@ -146,7 +149,7 @@ impl Rpc for RpcClient { let payer_pubkey = if let Some(signer) = signer { signer } else { - self.get_identity().await? + self.get_account_with_sol().await? }; let tx = Transaction::new_with_payer(instructions, Some(&payer_pubkey)); @@ -162,8 +165,16 @@ impl Rpc for RpcClient { .await } - async fn identity(&self) -> ClientResult { - self.get_identity().await + async fn get_account_with_sol(&self) -> ClientResult { + let r = self + .get_largest_accounts_with_config(RpcLargestAccountsConfig { + commitment: Some(self.commitment()), + filter: None, + }) + .await?; + + let pubkey = Pubkey::from_str(&r.value[0].address).unwrap(); + Ok(pubkey) } fn as_any(&self) -> &dyn Any { diff --git a/evm_loader/program/src/account_storage/apply.rs b/evm_loader/program/src/account_storage/apply.rs index ee020ee4d..2577eb093 100644 --- a/evm_loader/program/src/account_storage/apply.rs +++ b/evm_loader/program/src/account_storage/apply.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use ethnum::U256; use solana_program::account_info::AccountInfo; use solana_program::instruction::Instruction; -use solana_program::program::invoke_signed_unchecked; +use solana_program::program::{invoke_signed_unchecked, invoke_unchecked}; use solana_program::rent::Rent; use solana_program::system_program; use solana_program::sysvar::Sysvar; @@ -155,7 +155,12 @@ impl<'a> ProgramAccountStorage<'a> { accounts, data, }; - invoke_signed_unchecked(&instruction, &accounts_info, &[&seeds])?; + + if !seeds.is_empty() { + invoke_signed_unchecked(&instruction, &accounts_info, &[&seeds])?; + } else { + invoke_unchecked(&instruction, &accounts_info)?; + } } } } From c779193670966d6dbacbd767b4152226e320e4f2 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Tue, 14 Nov 2023 14:53:52 +0200 Subject: [PATCH 062/318] [Multi Tokens] Fixes for tracer-api --- evm_loader/lib/src/commands/emulate.rs | 15 ++++++--------- evm_loader/lib/src/commands/get_balance.rs | 6 +++--- evm_loader/lib/src/commands/get_contract.rs | 4 ++-- evm_loader/lib/src/commands/get_storage_at.rs | 2 +- evm_loader/lib/src/commands/trace.rs | 2 -- evm_loader/lib/src/types/mod.rs | 8 ++++---- .../src/evm/tracing/tracers/struct_logger.rs | 19 +++++++++++++++++-- 7 files changed, 33 insertions(+), 23 deletions(-) diff --git a/evm_loader/lib/src/commands/emulate.rs b/evm_loader/lib/src/commands/emulate.rs index 3a268a4d0..7fb6b2419 100644 --- a/evm_loader/lib/src/commands/emulate.rs +++ b/evm_loader/lib/src/commands/emulate.rs @@ -1,6 +1,6 @@ use evm_loader::account::ContractAccount; use log::{debug, info}; -use serde::Serialize; +use serde::{Deserialize, Serialize}; use solana_sdk::entrypoint::MAX_PERMITTED_DATA_INCREASE; use solana_sdk::pubkey::Pubkey; @@ -19,13 +19,12 @@ use evm_loader::{ executor::{Action, ExecutorState}, gasometer::LAMPORTS_PER_SIGNATURE, }; -use serde_with::{hex::Hex, serde_as, DisplayFromStr}; +use serde_with::{hex::Hex, serde_as}; #[serde_as] -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct EmulateResponse { - #[serde_as(as = "DisplayFromStr")] - pub exit_status: ExitStatus, + pub exit_status: String, #[serde_as(as = "Hex")] pub result: Vec, pub steps_executed: u64, @@ -109,14 +108,12 @@ async fn emulate_trx( let solana_accounts = storage.accounts.borrow().values().cloned().collect(); - let result = exit_status.clone().into_result().unwrap_or_default(); - Ok(EmulateResponse { - exit_status, + exit_status: exit_status.status().to_string(), steps_executed, used_gas, solana_accounts, - result, + result: exit_status.into_result().unwrap_or_default(), iterations, }) } diff --git a/evm_loader/lib/src/commands/get_balance.rs b/evm_loader/lib/src/commands/get_balance.rs index 418e0a1ec..80620dc76 100644 --- a/evm_loader/lib/src/commands/get_balance.rs +++ b/evm_loader/lib/src/commands/get_balance.rs @@ -1,7 +1,7 @@ use ethnum::U256; use evm_loader::account::legacy::LegacyEtherData; use evm_loader::account::BalanceAccount; -use serde::Serialize; +use serde::{Deserialize, Serialize}; use solana_sdk::{account::Account, pubkey::Pubkey}; use crate::{account_storage::account_info, rpc::Rpc, types::BalanceAddress, NeonResult}; @@ -10,7 +10,7 @@ use serde_with::{serde_as, DisplayFromStr}; use super::get_config::ChainInfo; -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub enum BalanceStatus { Ok, Legacy, @@ -18,7 +18,7 @@ pub enum BalanceStatus { } #[serde_as] -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct GetBalanceResponse { #[serde_as(as = "DisplayFromStr")] pub solana_address: Pubkey, diff --git a/evm_loader/lib/src/commands/get_contract.rs b/evm_loader/lib/src/commands/get_contract.rs index 2619a35aa..4d275d634 100644 --- a/evm_loader/lib/src/commands/get_contract.rs +++ b/evm_loader/lib/src/commands/get_contract.rs @@ -2,7 +2,7 @@ use evm_loader::{ account::{legacy::LegacyEtherData, ContractAccount}, types::Address, }; -use serde::Serialize; +use serde::{Deserialize, Serialize}; use solana_sdk::{account::Account, pubkey::Pubkey}; use crate::{account_storage::account_info, rpc::Rpc, NeonResult}; @@ -12,7 +12,7 @@ use serde_with::{hex::Hex, serde_as, DisplayFromStr}; use super::get_config::ChainInfo; #[serde_as] -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct GetContractResponse { #[serde_as(as = "DisplayFromStr")] pub solana_address: Pubkey, diff --git a/evm_loader/lib/src/commands/get_storage_at.rs b/evm_loader/lib/src/commands/get_storage_at.rs index 41fe16eee..83dd0cee3 100644 --- a/evm_loader/lib/src/commands/get_storage_at.rs +++ b/evm_loader/lib/src/commands/get_storage_at.rs @@ -6,7 +6,7 @@ use evm_loader::{account_storage::AccountStorage, types::Address}; use crate::{account_storage::EmulatorAccountStorage, rpc::Rpc, NeonResult}; -#[derive(Default, Serialize, Deserialize)] +#[derive(Debug, Default, Serialize, Deserialize)] pub struct GetStorageAtReturn(pub [u8; 32]); pub async fn execute( diff --git a/evm_loader/lib/src/commands/trace.rs b/evm_loader/lib/src/commands/trace.rs index 233533663..6bff5dcbb 100644 --- a/evm_loader/lib/src/commands/trace.rs +++ b/evm_loader/lib/src/commands/trace.rs @@ -28,9 +28,7 @@ pub async fn trace_transaction( .expect("There is must be only one reference") .into_inner() .into_traces(); - traces["failed"] = r.exit_status.is_succeed().unwrap().into(); traces["gas"] = r.used_gas.into(); - traces["return_value"] = hex::encode(&r.result).into(); Ok(traces) } diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index 81ae9af1a..40954cebf 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -19,7 +19,7 @@ use serde_with::{hex::Hex, serde_as, DisplayFromStr, OneOrMany}; use crate::commands::get_config::ChainInfo; -#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone, Default)] +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Default)] pub struct ChDbConfig { pub clickhouse_url: Vec, pub clickhouse_user: Option, @@ -152,7 +152,7 @@ impl BalanceAddress { } #[serde_as] -#[derive(Deserialize, Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default)] pub struct GetBalanceRequest { #[serde_as(as = "OneOrMany<_>")] pub account: Vec, @@ -160,14 +160,14 @@ pub struct GetBalanceRequest { } #[serde_as] -#[derive(Deserialize, Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default)] pub struct GetContractRequest { #[serde_as(as = "OneOrMany<_>")] pub contract: Vec
, pub slot: Option, } -#[derive(Deserialize, Debug, Default)] +#[derive(Serialize, Deserialize, Debug, Default)] pub struct GetStorageAtRequest { pub contract: Address, pub index: U256, diff --git a/evm_loader/program/src/evm/tracing/tracers/struct_logger.rs b/evm_loader/program/src/evm/tracing/tracers/struct_logger.rs index 1143f3909..71e7b8adf 100644 --- a/evm_loader/program/src/evm/tracing/tracers/struct_logger.rs +++ b/evm_loader/program/src/evm/tracing/tracers/struct_logger.rs @@ -1,5 +1,6 @@ use std::collections::BTreeMap; +use crate::evm::ExitStatus; use ethnum::U256; use serde::Serialize; use serde_json::{json, Value}; @@ -120,6 +121,7 @@ pub struct StructLogger { logs: Vec, depth: usize, storage_access: Option<(U256, U256)>, + exit_status: Option, } impl StructLogger { @@ -130,6 +132,7 @@ impl StructLogger { logs: vec![], depth: 0, storage_access: None, + exit_status: None, } } } @@ -140,7 +143,10 @@ impl EventListener for StructLogger { Event::BeginVM { .. } => { self.depth += 1; } - Event::EndVM { .. } => { + Event::EndVM { status } => { + if self.depth == 1 { + self.exit_status = Some(status); + } self.depth -= 1; } Event::BeginStep { @@ -199,8 +205,17 @@ impl EventListener for StructLogger { } fn into_traces(self: Box) -> Value { + let exit_status = self.exit_status.expect("Emulation is not completed"); json!({ - "struct_logs": self.logs + "struct_logs": self.logs, + "failed": exit_status + .is_succeed() + .expect("Emulation is not completed"), + "return_value": hex::encode( + exit_status + .into_result() + .unwrap_or_default(), + ) }) } } From 203a38fd53a4efa02c92ff723b4d8abe4b0ff5cc Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Thu, 16 Nov 2023 15:44:17 +0300 Subject: [PATCH 063/318] Split get_multiple_accounts request by chunks --- evm_loader/lib/src/rpc/validator_client.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/evm_loader/lib/src/rpc/validator_client.rs b/evm_loader/lib/src/rpc/validator_client.rs index 4bfc488b9..1a5be4b69 100644 --- a/evm_loader/lib/src/rpc/validator_client.rs +++ b/evm_loader/lib/src/rpc/validator_client.rs @@ -57,7 +57,13 @@ impl Rpc for RpcClient { &self, pubkeys: &[Pubkey], ) -> ClientResult>> { - self.get_multiple_accounts(pubkeys).await + let mut result: Vec> = Vec::new(); + for chunk in pubkeys.chunks(100) { + let mut accounts = self.get_multiple_accounts(chunk).await?; + result.append(&mut accounts); + } + + Ok(result) } async fn get_account_data(&self, key: &Pubkey) -> ClientResult> { From ecd6c15df5fe9012339b7ce03f7d24ec6cbf2fcf Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Tue, 21 Nov 2023 14:54:33 +0300 Subject: [PATCH 064/318] [Multi Tokens] Review Fixes --- evm_loader/lib/src/commands/cancel_trx.rs | 2 +- evm_loader/lib/src/commands/emulate.rs | 23 ++- evm_loader/program-macro/src/lib.rs | 6 +- evm_loader/program/src/entrypoint.rs | 2 +- .../src/instruction/account_create_balance.rs | 8 +- evm_loader/program/src/instruction/mod.rs | 175 ++++++++++++++---- tests/solana_utils.py | 10 +- tests/utils/instructions.py | 24 +-- 8 files changed, 187 insertions(+), 63 deletions(-) diff --git a/evm_loader/lib/src/commands/cancel_trx.rs b/evm_loader/lib/src/commands/cancel_trx.rs index 5723a697f..b7663eeec 100644 --- a/evm_loader/lib/src/commands/cancel_trx.rs +++ b/evm_loader/lib/src/commands/cancel_trx.rs @@ -54,7 +54,7 @@ pub async fn execute( } let cancel_with_nonce_instruction = - Instruction::new_with_bincode(evm_loader, &(0x23_u8, storage.trx_hash()), accounts_meta); + Instruction::new_with_bincode(evm_loader, &(0x37_u8, storage.trx_hash()), accounts_meta); let instructions = vec![cancel_with_nonce_instruction]; diff --git a/evm_loader/lib/src/commands/emulate.rs b/evm_loader/lib/src/commands/emulate.rs index 7fb6b2419..a99d0b5e8 100644 --- a/evm_loader/lib/src/commands/emulate.rs +++ b/evm_loader/lib/src/commands/emulate.rs @@ -1,4 +1,5 @@ use evm_loader::account::ContractAccount; +use evm_loader::error::build_revert_message; use log::{debug, info}; use serde::{Deserialize, Serialize}; use solana_sdk::entrypoint::MAX_PERMITTED_DATA_INCREASE; @@ -33,6 +34,21 @@ pub struct EmulateResponse { pub solana_accounts: Vec, } +impl EmulateResponse { + pub fn revert(e: E) -> Self { + let revert_message = build_revert_message(&e.to_string()); + let exit_status = ExitStatus::Revert(revert_message); + Self { + exit_status: exit_status.to_string(), + result: exit_status.into_result().unwrap_or_default(), + steps_executed: 0, + used_gas: 0, + iterations: 0, + solana_accounts: vec![], + } + } +} + pub async fn execute( rpc_client: &dyn Rpc, program_id: Pubkey, @@ -79,7 +95,10 @@ async fn emulate_trx( let (exit_status, actions, steps_executed) = { let mut backend = ExecutorState::new(storage); - let mut evm = Machine::new(tx, origin, &mut backend, tracer).await?; + let mut evm = match Machine::new(tx, origin, &mut backend, tracer).await { + Ok(evm) => evm, + Err(e) => return Ok(EmulateResponse::revert(e)), + }; let (result, steps_executed) = evm.execute(step_limit, &mut backend).await?; if result == ExitStatus::StepLimit { @@ -109,7 +128,7 @@ async fn emulate_trx( let solana_accounts = storage.accounts.borrow().values().cloned().collect(); Ok(EmulateResponse { - exit_status: exit_status.status().to_string(), + exit_status: exit_status.to_string(), steps_executed, used_gas, solana_accounts, diff --git a/evm_loader/program-macro/src/lib.rs b/evm_loader/program-macro/src/lib.rs index 1a96de2bf..ec3b5c5c0 100644 --- a/evm_loader/program-macro/src/lib.rs +++ b/evm_loader/program-macro/src/lib.rs @@ -96,11 +96,11 @@ pub fn net_specific_config_parser(tokens: TokenStream) -> TokenStream { neon_elf_param!(NEON_CHAIN_ID, #neon_chain_id_str); neon_elf_param!(NEON_TOKEN_MINT, #neon_token_mint); - pub static AUTHORIZED_OPERATOR_LIST: [::solana_program::pubkey::Pubkey; #operators_len] = [ + pub const AUTHORIZED_OPERATOR_LIST: [::solana_program::pubkey::Pubkey; #operators_len] = [ #(::solana_program::pubkey::Pubkey::new_from_array([#((#operators),)*]),)* ]; - pub static CHAIN_ID_LIST: [(u64, &str, ::solana_program::pubkey::Pubkey); #chains_len] = [ + pub const CHAIN_ID_LIST: [(u64, &str, ::solana_program::pubkey::Pubkey); #chains_len] = [ #( (#chain_ids, #chain_names, ::solana_program::pubkey::Pubkey::new_from_array([#(#chain_tokens),*])) ),* ]; } @@ -144,7 +144,7 @@ pub fn common_config_parser(tokens: TokenStream) -> TokenStream { quote! { #(#tokens)* - pub static PARAMETERS: [(&str, &str); #variables_len] = [ + pub const PARAMETERS: [(&str, &str); #variables_len] = [ #( (#variable_names, #variable_values) ),* ]; } diff --git a/evm_loader/program/src/entrypoint.rs b/evm_loader/program/src/entrypoint.rs index e58144bce..daa05f33c 100644 --- a/evm_loader/program/src/entrypoint.rs +++ b/evm_loader/program/src/entrypoint.rs @@ -80,7 +80,7 @@ fn process_instruction<'a>( EvmInstruction::HolderWrite => { instruction::account_holder_write::process(program_id, accounts, instruction) } - EvmInstruction::DepositV03 => { + EvmInstruction::Deposit => { instruction::neon_tokens_deposit::process(program_id, accounts, instruction) } EvmInstruction::Cancel => { diff --git a/evm_loader/program/src/instruction/account_create_balance.rs b/evm_loader/program/src/instruction/account_create_balance.rs index 08743ac92..878eb4c78 100644 --- a/evm_loader/program/src/instruction/account_create_balance.rs +++ b/evm_loader/program/src/instruction/account_create_balance.rs @@ -2,8 +2,8 @@ use arrayref::array_ref; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; use crate::account::{program, AccountsDB, BalanceAccount, Operator}; -use crate::config::DEFAULT_CHAIN_ID; -use crate::error::Result; +use crate::config::{CHAIN_ID_LIST, DEFAULT_CHAIN_ID}; +use crate::error::{Error, Result}; use crate::types::Address; pub fn process<'a>( @@ -24,7 +24,9 @@ pub fn process<'a>( let chain_id = array_ref![instruction, 20, 8]; let chain_id = u64::from_le_bytes(*chain_id); - // TODO: validate chain_id? + CHAIN_ID_LIST + .binary_search_by_key(&chain_id, |c| c.0) + .map_err(|_| Error::InvalidChainId(chain_id))?; solana_program::msg!("Address: {}, ChainID: {}", address, chain_id); diff --git a/evm_loader/program/src/instruction/mod.rs b/evm_loader/program/src/instruction/mod.rs index 5648cff75..d5468775a 100644 --- a/evm_loader/program/src/instruction/mod.rs +++ b/evm_loader/program/src/instruction/mod.rs @@ -6,67 +6,170 @@ use solana_program::program_error::ProgramError; /// `EvmInstruction` serialized in instruction data #[derive(Debug, PartialEq, Eq, Clone)] pub enum EvmInstruction { - /// Deposits NEON tokens to an Ether account (V3). + /// Deposits spl-tokens to an Ether account. /// Requires previously executed SPL-Token.Approve which /// delegates the deposit amount to the NEON destination account. /// - /// Accounts expected by this instruction: - /// - /// 0. `[writable]` NEON token source account. - /// 1. `[writable]` NEON token pool (destination) account. - /// 2. `[writable]` Ether account to store balance of NEONs. - /// 3. `[]` SPL Token program id. - /// 4. `[writeable,signer]` Funding account (must be a system account). - /// 5. `[]` System program. - DepositV03, + /// Accounts: + /// `[]` spl-token mint account. + /// `[WRITE]` spl-token source account. + /// `[WRITE]` spl-token pool (destination) account. + /// `[WRITE]` NeonEVM user balance account + /// `[WRITE]` NeonEVM user contract account + /// `[]` SPL Token program id. + /// `[writeable,signer]` Funding account (must be a system account). + /// `[]` System program. + /// Instruction data: + /// 0..20 - destination address + /// 20..28 - chain id in little endian + Deposit, /// Collect lamports from treasury pool accounts to main pool balance - /// 0. `[WRITE]` Main treasury balance: PDA["treasury_pool"] - /// 1. `[WRITE]` Auxiliary treasury balance: PDA["treasury_pool", index.to_le_bytes()] - /// 2. `[]` System program + /// + /// Accounts: + /// `[WRITE]` Main treasury balance: PDA["treasury_pool"] + /// `[WRITE]` Auxiliary treasury balance: PDA["treasury_pool", index.to_le_bytes()] + /// `[]` System program + /// Instruction data: + /// 0..4 - treasury index in little endian CollectTreasure, /// Create Holder Account + /// + /// Accounts: + /// `[WRITE]` Holder Account + /// `[SIGNER]` Holder Account Owner + /// Instruction data: + /// 0..8 - seed length in little endian + /// 8..8+seed_len - seed in utf-8 HolderCreate, /// Delete Holder Account + /// + /// Accounts: + /// `[WRITE]` Holder Account + /// `[WRITE,SIGNER]` Holder Account Owner + /// Instruction data: + /// None HolderDelete, /// Write Transaction into Holder Account + /// + /// Accounts: + /// `[WRITE]` Holder Account + /// `[SIGNER]` Holder Account Owner + /// Instruction data: + /// 0..32 - transaction hash + /// 32..40 - offset in Holder in little endian + /// 40.. - transaction data HolderWrite, /// Execute Transaction from Instruction in single iteration + /// + /// Accounts: + /// `[WRITE,SIGNER]` Operator + /// `[WRITE]` Treasury + /// `[WRITE]` Operator Balance + /// `[]` System program + /// `[WRITE?]` Other accounts + /// Instruction data: + /// 0..4 - treasury index in little endian + /// 4.. - transaction data TransactionExecuteFromInstruction, /// Execute Transaction from Account in single iteration + /// + /// Accounts: + /// `[]` Holder + /// `[WRITE,SIGNER]` Operator + /// `[WRITE]` Treasury + /// `[WRITE]` Operator Balance + /// `[]` System program + /// `[WRITE?]` Other accounts + /// Instruction data: + /// 0..4 - treasury index in little endian TransactionExecuteFromAccount, /// Execute Iterative Transaction from Instruction + /// + /// Accounts: + /// `[WRITE]` Holder/State + /// `[WRITE,SIGNER]` Operator + /// `[WRITE]` Treasury + /// `[WRITE]` Operator Balance + /// `[]` System program + /// `[WRITE]` Other accounts + /// Instruction data: + /// 0..4 - treasury index in little endian + /// 4..8 - step count in little endian + /// 8.. - transaction data TransactionStepFromInstruction, /// Execute Iterative Transaction from Account + /// + /// Accounts: + /// `[WRITE]` Holder/State + /// `[WRITE,SIGNER]` Operator + /// `[WRITE]` Treasury + /// `[WRITE]` Operator Balance + /// `[]` System program + /// `[WRITE]` Other accounts + /// Instruction data: + /// 0..4 - treasury index in little endian + /// 4..8 - step count in little endian TransactionStepFromAccount, /// Execute Iterative Transaction without ChainId from Account + /// + /// Accounts: + /// `[WRITE]` Holder/State + /// `[WRITE,SIGNER]` Operator + /// `[WRITE]` Treasury + /// `[WRITE]` Operator Balance + /// `[]` System program + /// `[WRITE]` Other accounts + /// Instruction data: + /// 0..4 - treasury index in little endian + /// 4..8 - step count in little endian TransactionStepFromAccountNoChainId, /// Cancel Transaction + /// + /// Accounts: + /// `[WRITE]` State + /// `[SIGNER]` Operator + /// `[WRITE]` Operator Balance + /// Instruction data: + /// 0..32 - transaction hash Cancel, /// CreateMainTreasury - /// 0. `[WRITE]` Main treasury balance: PDA["treasury_pool"] - /// 1. `[]` Program data (to get program upgrade-authority) - /// 2. `[SIGNER]` Owner for account (upgrade program authority) - /// 3. `[]` SPL token program id - /// 4. `[]` System program - /// 5. `[]` wSOL mint - /// 6. `[WRITE,SIGNER]` Payer + /// + /// Accounts: + /// `[WRITE]` Main treasury balance: PDA["treasury_pool"] + /// `[]` Program data (to get program upgrade-authority) + /// `[SIGNER]` Owner for account (upgrade program authority) + /// `[]` SPL token program id + /// `[]` System program + /// `[]` wSOL mint + /// `[WRITE,SIGNER]` Payer + /// Instruction data: + /// None CreateMainTreasury, /// Block additional accounts AccountBlockAdd, - /// Create User Balance account + /// Create a User Balance account + /// + /// Accounts: + /// `[WRITE,SIGNER]` Operator + /// `[]` System program + /// `[WRITE]` NeonEVM user balance account + /// `[WRITE]` NeonEVM user contract account + /// Instruction data: + /// 0..20 - address + /// 20..28 - chain id in little endian AccountCreateBalance, ConfigGetChainCount, @@ -86,21 +189,21 @@ impl EvmInstruction { /// Will return `ProgramError::InvalidInstructionData` if can't parse `tag` pub const fn parse(tag: &u8) -> Result { Ok(match tag { - 0x1e => Self::CollectTreasure, // 30 - 0x1f => Self::TransactionExecuteFromInstruction, // 31 - 0x20 => Self::TransactionStepFromInstruction, // 32 - 0x21 => Self::TransactionStepFromAccount, // 33 - 0x22 => Self::TransactionStepFromAccountNoChainId, // 34 - 0x23 => Self::Cancel, // 35 - 0x24 => Self::HolderCreate, // 36 - 0x25 => Self::HolderDelete, // 37 - 0x26 => Self::HolderWrite, // 38 - 0x27 => Self::DepositV03, // 39 - 0x29 => Self::CreateMainTreasury, // 41 - 0x2A => Self::TransactionExecuteFromAccount, // 42 - 0x2B => Self::AccountBlockAdd, // 43 - // 0x2C => Self::TestAccountUpdateNonce, // 44 - 0x2D => Self::AccountCreateBalance, // 45 + 0x1e => Self::CollectTreasure, // 30 + 0x24 => Self::HolderCreate, // 36 + 0x25 => Self::HolderDelete, // 37 + 0x26 => Self::HolderWrite, // 38 + 0x29 => Self::CreateMainTreasury, // 41 + 0x2B => Self::AccountBlockAdd, // 43 + + 0x30 => Self::AccountCreateBalance, // 48 + 0x31 => Self::Deposit, // 49 + 0x32 => Self::TransactionExecuteFromInstruction, // 50 + 0x33 => Self::TransactionExecuteFromAccount, // 51 + 0x34 => Self::TransactionStepFromInstruction, // 52 + 0x35 => Self::TransactionStepFromAccount, // 53 + 0x36 => Self::TransactionStepFromAccountNoChainId, // 54 + 0x37 => Self::Cancel, // 55 0xA0 => Self::ConfigGetChainCount, // 160 0xA1 => Self::ConfigGetChainInfo, diff --git a/tests/solana_utils.py b/tests/solana_utils.py index 83f9388f9..ba26728b3 100644 --- a/tests/solana_utils.py +++ b/tests/solana_utils.py @@ -312,7 +312,7 @@ def create_balance_account(self, ether: Union[str, bytes]) -> PublicKey: contract_pubkey = PublicKey(self.ether2program(ether)[0]) print('createBalanceAccount: {} => {}'.format(ether, account_pubkey)) - data = bytes.fromhex('2D') + self.ether2bytes(ether) + CHAIN_ID.to_bytes(8, 'little') + data = bytes([0x30]) + self.ether2bytes(ether) + CHAIN_ID.to_bytes(8, 'little') trx = Transaction() trx.add(TransactionInstruction( program_id=self.loader_id, @@ -588,7 +588,7 @@ def execute_transaction_steps_from_instruction(operator: Keypair, evm_loader: Ev def send_transaction_step_from_account(operator: Keypair, evm_loader: EvmLoader, treasury, storage_account, additional_accounts, steps_count, signer: Keypair, system_program=sp.SYS_PROGRAM_ID, - tag=33) -> GetTransactionResp: + tag=0x35) -> GetTransactionResp: trx = TransactionWithComputeBudget(operator) trx.add( make_ExecuteTrxFromAccountDataIterativeOrContinue( @@ -621,12 +621,12 @@ def execute_transaction_steps_from_account_no_chain_id(operator: Keypair, evm_lo signer = operator if signer is None else signer send_transaction_step_from_account(operator, evm_loader, treasury, storage_account, additional_accounts, 1, signer, - tag=34) + tag=0x36) if steps_count > 0: steps_left = steps_count while steps_left > 0: send_transaction_step_from_account(operator, evm_loader, treasury, storage_account, additional_accounts, - EVM_STEPS, signer, tag=34) + EVM_STEPS, signer, tag=0x36) steps_left = steps_left - EVM_STEPS return send_transaction_step_from_account(operator, evm_loader, treasury, storage_account, additional_accounts, 1, - signer, tag=34) + signer, tag=0x36) diff --git a/tests/utils/instructions.py b/tests/utils/instructions.py index 1121c60e2..bad066b25 100644 --- a/tests/utils/instructions.py +++ b/tests/utils/instructions.py @@ -48,7 +48,7 @@ def __init__(self, def write_holder_layout(hash: bytes, offset: int, data: bytes): assert (len(hash) == 32) return ( - bytes.fromhex("26") + bytes([0x26]) + hash + offset.to_bytes(8, byteorder="little") + data @@ -76,7 +76,7 @@ def make_ExecuteTrxFromInstruction( additional_accounts: tp.List[PublicKey], system_program=sp.SYS_PROGRAM_ID, ): - data = bytes.fromhex('1f') + treasury_buffer + message + data = bytes([0x32]) + treasury_buffer + message operator_ether = eth_keys.PrivateKey(operator.secret_key[:32]).public_key.to_canonical_address() print("make_ExecuteTrxFromInstruction accounts") print("Operator: ", operator.public_key) @@ -109,10 +109,10 @@ def make_ExecuteTrxFromAccountDataIterativeOrContinue( step_count: int, additional_accounts: tp.List[PublicKey], sys_program_id=sp.SYS_PROGRAM_ID, - tag=33): - # 33 - TransactionStepFromAccount - # 34 - TransactionStepFromAccountNoChainId - d = tag.to_bytes(1, "little") + treasury_buffer + step_count.to_bytes(8, byteorder="little") + tag=0x35): + # 0x35 - TransactionStepFromAccount + # 0x36 - TransactionStepFromAccountNoChainId + data = tag.to_bytes(1, "little") + treasury_buffer + step_count.to_bytes(8, byteorder="little") operator_ether = eth_keys.PrivateKey(operator.secret_key[:32]).public_key.to_canonical_address() print("make_ExecuteTrxFromAccountDataIterativeOrContinue accounts") print("Holder: ", holder_address) @@ -134,7 +134,7 @@ def make_ExecuteTrxFromAccountDataIterativeOrContinue( return TransactionInstruction( program_id=PublicKey(EVM_LOADER), - data=d, + data=data, keys=accounts ) @@ -149,7 +149,7 @@ def make_PartialCallOrContinueFromRawEthereumTX( step_count: int, additional_accounts: tp.List[PublicKey], system_program=sp.SYS_PROGRAM_ID): - d = (32).to_bytes(1, "little") + treasury_buffer + step_count.to_bytes(8, byteorder="little") + instruction + data = bytes([0x34]) + treasury_buffer + step_count.to_bytes(8, byteorder="little") + instruction operator_ether = eth_keys.PrivateKey(operator.secret_key[:32]).public_key.to_canonical_address() accounts = [ @@ -164,13 +164,13 @@ def make_PartialCallOrContinueFromRawEthereumTX( return TransactionInstruction( program_id=PublicKey(EVM_LOADER), - data=d, + data=data, keys=accounts ) def make_Cancel(evm_loader: "EvmLoader", storage_address: PublicKey, operator: Keypair, hash: bytes, additional_accounts: tp.List[PublicKey]): - d = (35).to_bytes(1, "little") + hash + data = bytes([0x37]) + hash operator_ether = eth_keys.PrivateKey(operator.secret_key[:32]).public_key.to_canonical_address() accounts = [ @@ -184,7 +184,7 @@ def make_Cancel(evm_loader: "EvmLoader", storage_address: PublicKey, operator: K return TransactionInstruction( program_id=PublicKey(EVM_LOADER), - data=d, + data=data, keys=accounts ) @@ -200,7 +200,7 @@ def make_DepositV03( token_program: PublicKey, operator_pubkey: PublicKey, ) -> TransactionInstruction: - data = bytes.fromhex('27') + ether_address + chain_id.to_bytes(8, 'little') + data = bytes([0x31]) + ether_address + chain_id.to_bytes(8, 'little') accounts = [ AccountMeta(pubkey=mint, is_signer=False, is_writable=True), From 3c903abfb23389395ee05331090e3f98bc08c733 Mon Sep 17 00:00:00 2001 From: Andrey Falaleev Date: Wed, 22 Nov 2023 13:53:43 +0000 Subject: [PATCH 065/318] [Multi Tokens] Fix ci scripts --- ci/create-test-accounts.sh | 22 +++++++++------------- ci/wait-for-solana.sh | 20 ++++++++++++++++---- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/ci/create-test-accounts.sh b/ci/create-test-accounts.sh index 4c1ddcd42..7a2cd511a 100755 --- a/ci/create-test-accounts.sh +++ b/ci/create-test-accounts.sh @@ -34,20 +34,16 @@ function createAccount() { fi ACCOUNT=$(solana address -k "${ID_FILE}") echo "$(date "+%F %X.%3N") I ${FILENAME}:${LINENO} $$ ${COMPONENT}:CreateTestAcc {} New account ${ACCOUNT}" - # if ! solana account "${ACCOUNT}"; then - echo "$(date "+%F %X.%3N") I ${FILENAME}:${LINENO} $$ ${COMPONENT}:CreateTestAcc {} airdropping..." - solana airdrop 5000 "${ACCOUNT}" - # check that balance >= 10 otherwise airdroping by 1 SOL up to 10 + + echo "$(date "+%F %X.%3N") I ${FILENAME}:${LINENO} $$ ${COMPONENT}:CreateTestAcc {} airdropping..." + solana airdrop 5000 "${ACCOUNT}" + # check that balance >= 10 otherwise airdroping by 1 SOL up to 10 + BALANCE=$(solana balance "${ACCOUNT}" | tr '.' '\t'| tr '[:space:]' '\t' | cut -f1) + while [ "${BALANCE}" -lt 10 ]; do + solana airdrop 1 "${ACCOUNT}" + sleep 1 BALANCE=$(solana balance "${ACCOUNT}" | tr '.' '\t'| tr '[:space:]' '\t' | cut -f1) - while [ "${BALANCE}" -lt 10 ]; do - solana airdrop 1 "${ACCOUNT}" - sleep 1 - BALANCE=$(solana balance "${ACCOUNT}" | tr '.' '\t'| tr '[:space:]' '\t' | cut -f1) - done - - TOKEN_ACCOUNT=$(spl-token create-account ${NEON_TOKEN_MINT} --owner ${ACCOUNT} --fee-payer ${ID_FILE} | grep -Po 'Creating account \K[^\n]*' || true) - spl-token mint ${NEON_TOKEN_MINT} 5000 --owner evm_loader-keypair.json --fee-payer ${ID_FILE} -- ${TOKEN_ACCOUNT} - # fi + done } NUM_ACCOUNTS=${1} diff --git a/ci/wait-for-solana.sh b/ci/wait-for-solana.sh index 081873b49..ebe0ec736 100755 --- a/ci/wait-for-solana.sh +++ b/ci/wait-for-solana.sh @@ -3,15 +3,27 @@ set -euo pipefail : ${SOLANA_URL:?is not set} +function check_solana() { + local DATA='{"jsonrpc":"2.0","id":1,"method":"getHealth"}' + local RESULT='"ok"' + local CHECK_COMMAND="curl $SOLANA_URL -s -X POST -H 'Content-Type: application/json' -d '$DATA' | grep -cF '$RESULT'" + + local CHECK_COMMAND_RESULT=$(eval $CHECK_COMMAND) + if [[ "$CHECK_COMMAND_RESULT" == "1" ]]; then + exit 0 + fi + exit 1 +} + if [ $# -eq 0 ]; then - if solana -u $SOLANA_URL cluster-version >/dev/null 2>&1; then exit 0; fi + if $(check_solana); then exit 0; fi else WAIT_TIME=$1 echo "Waiting $WAIT_TIME seconds for solana cluster to be available at $SOLANA_URL" for i in $(seq 1 $WAIT_TIME); do - echo "Try solana cluster-version count=$i" - if solana -u $SOLANA_URL cluster-version; then - echo "Executed solana cluster-version successfully after count=$i" + echo "Try solana getHealth count=$i" + if $(check_solana); then + echo "Executed solana getHealth successfully after count=$i" exit 0 fi sleep 1 From bcfd04c60032b18e0b883c0cc5e67437c44be4ec Mon Sep 17 00:00:00 2001 From: Denis Date: Wed, 22 Nov 2023 18:32:07 +0200 Subject: [PATCH 066/318] NDEV-2309: Implement NEON_REVISION caching (#226) --- evm_loader/Cargo.lock | 48 +++++++------- evm_loader/lib/src/types/mod.rs | 65 +++++++++++++++++++ evm_loader/lib/src/types/tracer_ch_common.rs | 67 ++++++++++++++++++++ evm_loader/lib/src/types/tracer_ch_db.rs | 37 ++++++++++- 4 files changed, 191 insertions(+), 26 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 4b2ac3410..072bdc8f4 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -543,9 +543,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.73" +version = "0.1.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", @@ -903,9 +903,9 @@ checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "bytestring" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "238e4886760d98c4f899360c834fa93e62cf7f721ac3c2da375cbdf4b8679aae" +checksum = "74d80203ea6b29df88012294f62733de21cfeab47f17b41af3a38bc30a03ee72" dependencies = [ "bytes", ] @@ -952,9 +952,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cfa25e60aea747ec7e1124f238816749faa93759c6ff5b31f1ccdda137f4479" +checksum = "12024c4645c97566567129c204f65d5815a8c9aecf30fcbe682b2fe034996d36" dependencies = [ "serde", ] @@ -2640,9 +2640,9 @@ checksum = "9b085a4f2cde5781fc4b1717f2e86c62f5cda49de7ba99a7c2eae02b61c9064c" [[package]] name = "local-channel" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a493488de5f18c8ffcba89eebb8532ffc562dc400490eb65b84893fae0b178" +checksum = "b6cbc85e69b8df4b8bb8b89ec634e7189099cea8927a276b7384ce5488e53ec8" dependencies = [ "futures-core", "futures-sink", @@ -2651,9 +2651,9 @@ dependencies = [ [[package]] name = "local-waker" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e34f76eb3611940e0e7d53a9aaa4e6a3151f69541a282fd0dad5571420c53ff1" +checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" [[package]] name = "lock_api" @@ -2876,8 +2876,8 @@ dependencies = [ "num-traits", "shank", "solana-program", - "spl-associated-token-account 2.2.0", - "spl-token 4.0.0", + "spl-associated-token-account 1.1.3", + "spl-token 3.5.0", "thiserror", ] @@ -3197,11 +3197,11 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70bf6736f74634d299d00086f02986875b3c2d924781a6a2cb6c201e73da0ceb" +checksum = "683751d591e6d81200c39fb0d1032608b77724f34114db54f571ff1317b337c0" dependencies = [ - "num_enum_derive 0.7.0", + "num_enum_derive 0.7.1", ] [[package]] @@ -3230,9 +3230,9 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ea360eafe1022f7cc56cd7b869ed57330fb2453d0c7831d99b74c65d2f5597" +checksum = "6c11e44798ad209ccdd91fc192f0526a369a01234f7373e1b141c96d7cee4f0e" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2 1.0.66", @@ -3621,9 +3621,9 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.9.5" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c956be1b23f4261676aed05a0046e204e8a6836e50203902683a718af0797989" +checksum = "94b0b33c13a79f669c85defaf4c275dc86a0c0372807d0ca3d78e0bb87274863" dependencies = [ "bytes", "rand 0.8.5", @@ -4274,9 +4274,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.107" +version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "indexmap 2.0.0", "itoa", @@ -5892,7 +5892,7 @@ dependencies = [ "bytemuck", "num-derive 0.4.1", "num-traits", - "num_enum 0.7.0", + "num_enum 0.7.1", "solana-program", "solana-zk-token-sdk", "spl-memo 4.0.0", @@ -6674,9 +6674,9 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] name = "uuid" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" dependencies = [ "getrandom 0.2.9", ] diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index 40954cebf..f446d7309 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -181,3 +181,68 @@ pub struct GetHolderRequest { pub pubkey: Pubkey, pub slot: Option, } + +#[cfg(test)] +mod tests { + use crate::types::tracer_ch_common::RevisionMap; + + #[test] + fn test_build_ranges_empty() { + let results = Vec::new(); + let exp = Vec::new(); + let res = RevisionMap::build_ranges(results); + assert_eq!(res, exp); + } + + #[test] + fn test_build_ranges_single_element() { + let results = vec![(1u64, String::from("Rev1"))]; + let exp = vec![(1u64, 2u64, String::from("Rev1"))]; + let res = RevisionMap::build_ranges(results); + assert_eq!(res, exp); + } + + #[test] + fn test_build_ranges_multiple_elements_different_revision() { + let results = vec![ + (222222222u64, String::from("Rev1")), + (333333333u64, String::from("Rev2")), + (444444444u64, String::from("Rev3")), + ]; + + let exp = vec![ + (222222222u64, 333333333u64, String::from("Rev1")), + (333333334u64, 444444444u64, String::from("Rev2")), + (444444445u64, 444444445u64, String::from("Rev3")), + ]; + let res = RevisionMap::build_ranges(results); + + assert_eq!(res, exp); + } + + #[test] + fn test_rangemap() { + let ranges = vec![ + (123456780, 123456788, String::from("Rev1")), + (123456789, 123456793, String::from("Rev2")), + (123456794, 123456799, String::from("Rev3")), + ]; + let map = RevisionMap::new(ranges); + + assert_eq!(map.get(123456779), None); // Below the bottom bound of the first range + + assert_eq!(map.get(123456780), Some(String::from("Rev1"))); // The bottom bound of the first range + assert_eq!(map.get(123456785), Some(String::from("Rev1"))); // Within the first range + assert_eq!(map.get(123456788), Some(String::from("Rev1"))); // The top bound of the first range + + assert_eq!(map.get(123456793), Some(String::from("Rev2"))); // The bottom bound of the second range + assert_eq!(map.get(123456790), Some(String::from("Rev2"))); // Within the second range + assert_eq!(map.get(123456793), Some(String::from("Rev2"))); // The top bound of the second range + + assert_eq!(map.get(123456799), Some(String::from("Rev3"))); // The bottom bound of the third range + assert_eq!(map.get(123456795), Some(String::from("Rev3"))); // Within the third range + assert_eq!(map.get(123456799), Some(String::from("Rev3"))); // The top bound of the third range + + assert_eq!(map.get(123456800), None); // Beyond the top end of the last range + } +} diff --git a/evm_loader/lib/src/types/tracer_ch_common.rs b/evm_loader/lib/src/types/tracer_ch_common.rs index c7c0e54f4..d61897d25 100644 --- a/evm_loader/lib/src/types/tracer_ch_common.rs +++ b/evm_loader/lib/src/types/tracer_ch_common.rs @@ -3,6 +3,8 @@ use std::fmt; use clickhouse::Row; use serde::{Deserialize, Serialize}; use solana_sdk::{account::Account, pubkey::Pubkey}; +use std::collections::BTreeMap; +use std::time::Instant; use thiserror::Error; pub const ROOT_BLOCK_DELAY: u8 = 100; @@ -52,6 +54,13 @@ impl SlotParent { } } +// NEON_REVISION row +#[derive(Row, Deserialize)] +pub struct RevisionRow { + pub slot: u64, + pub data: Vec, +} + #[derive(Row, serde::Deserialize, Clone)] pub struct AccountRow { pub owner: Vec, @@ -129,3 +138,61 @@ pub struct EthSyncing { pub current_block: u64, pub highest_block: u64, } + +pub struct RevisionMap { + map: BTreeMap, + pub last_update: Instant, +} + +impl RevisionMap { + pub fn new(neon_revision_ranges: Vec<(u64, u64, String)>) -> Self { + let mut map = BTreeMap::new(); + + for (start, end, value) in neon_revision_ranges { + map.insert(start, value.clone()); + map.insert(end, value); + } + + let last_update = std::time::Instant::now(); + + RevisionMap { map, last_update } + } + + // When deploying a program for the first time it is now only available in the next slot (the slot after the one the deployment transaction landed in). + // When undeploying / closing a program the change is visible immediately and the very next instruction even within the transaction can not access it anymore. + // When redeploying the program becomes temporarily closed immediately and will reopen with the new version in the next slot. + pub fn build_ranges(input: Vec<(u64, String)>) -> Vec<(u64, u64, String)> { + let mut ranges = Vec::new(); + + for i in 0..input.len() { + let (start, rev) = input[i].clone(); + let end = if i < input.len() - 1 { + input[i + 1].0 - 1 + } else { + start + }; + + match i { + 0 => ranges.push((start, end + 1, rev.clone())), + _ if i == input.len() - 1 => ranges.push((start + 1, end + 1, rev.clone())), + _ => ranges.push((start + 1, end + 1, rev.clone())), + } + } + ranges + } + + pub fn get(&self, slot: u64) -> Option { + // Check if slot is less than the starting range or + // greater than the ending range + let (start, _) = self.map.iter().next()?; + let (end, _) = self.map.iter().last()?; + + if slot < *start || slot > *end { + return None; + } + + let value = self.map.range(..=slot).rev().next(); + + value.map(|(_, v)| v.clone()) + } +} diff --git a/evm_loader/lib/src/types/tracer_ch_db.rs b/evm_loader/lib/src/types/tracer_ch_db.rs index e4b9ff9df..f9140fc41 100644 --- a/evm_loader/lib/src/types/tracer_ch_db.rs +++ b/evm_loader/lib/src/types/tracer_ch_db.rs @@ -1,10 +1,10 @@ use crate::{ commands::get_neon_elf::get_elf_parameter, - types::tracer_ch_common::{AccountRow, ChError, SlotParent, ROOT_BLOCK_DELAY}, + types::tracer_ch_common::{AccountRow, ChError, RevisionRow, SlotParent, ROOT_BLOCK_DELAY}, }; use super::{ - tracer_ch_common::{ChResult, EthSyncStatus, EthSyncing, SlotParentRooted}, + tracer_ch_common::{ChResult, EthSyncStatus, EthSyncing, RevisionMap, SlotParentRooted}, ChDbConfig, }; @@ -586,6 +586,39 @@ impl ClickHouseDb { } } + pub async fn get_neon_revisions(&self, pubkey: &Pubkey) -> ChResult { + let query = r#"SELECT slot, data + FROM events.update_account_distributed + WHERE + pubkey = ? + ORDER BY + slot ASC, + write_version ASC"#; + + let pubkey_str = format!("{:?}", pubkey.to_bytes()); + let rows: Vec = self + .client + .query(query) + .bind(pubkey_str) + .fetch_all() + .await?; + + let mut results: Vec<(u64, String)> = Vec::new(); + + for row in rows { + let neon_revision = get_elf_parameter(&row.data, "NEON_REVISION").map_err(|e| { + ChError::Db(clickhouse::error::Error::Custom(format!( + "Failed to get NEON_REVISION, error: {:?}", + e + ))) + })?; + results.push((row.slot, neon_revision)); + } + let ranges = RevisionMap::build_ranges(results); + + Ok(RevisionMap::new(ranges)) + } + pub async fn get_slot_by_blockhash(&self, blockhash: &str) -> ChResult { let query = r#"SELECT slot FROM events.notify_block_distributed From e5a17d89703ee28cfaf0d6bad7f6c66108acfe78 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Fri, 24 Nov 2023 12:28:09 +0200 Subject: [PATCH 067/318] NDEV-2332: Decouple tracer code from evm-loader to neon-lib crate (#232) * NDEV-2332: Move tracer impl from evm_loader to neon_lib * NDEV-2332: Move types from program::evm::tracing::mod to lib::tracing::mod * NDEV-2332: Remove Send + Sync from EventListener * NDEV-2332: Remove unused impl * NDEV-2332: Convert tracing module from directory to file --- evm_loader/lib/src/account_storage.rs | 2 +- evm_loader/lib/src/commands/trace.rs | 3 +- evm_loader/lib/src/lib.rs | 1 + .../src/evm => lib/src}/tracing/mod.rs | 54 ++----------------- .../evm => lib/src}/tracing/tracers/mod.rs | 10 ++-- .../src}/tracing/tracers/struct_logger.rs | 10 ++-- evm_loader/lib/src/types/mod.rs | 2 +- evm_loader/program/src/evm/mod.rs | 2 +- evm_loader/program/src/evm/tracing.rs | 41 ++++++++++++++ 9 files changed, 59 insertions(+), 66 deletions(-) rename evm_loader/{program/src/evm => lib/src}/tracing/mod.rs (73%) rename evm_loader/{program/src/evm => lib/src}/tracing/tracers/mod.rs (56%) rename evm_loader/{program/src/evm => lib/src}/tracing/tracers/struct_logger.rs (97%) create mode 100644 evm_loader/program/src/evm/tracing.rs diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index afa98cc4a..2c9f1c885 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -14,7 +14,6 @@ use std::{cell::RefCell, collections::HashMap, convert::TryInto, rc::Rc}; use crate::{rpc::Rpc, NeonError}; use ethnum::U256; -use evm_loader::evm::tracing::{AccountOverride, AccountOverrides, BlockOverrides}; use evm_loader::{ account::{BalanceAccount, ContractAccount, StorageCell, StorageCellAddress}, account_storage::AccountStorage, @@ -27,6 +26,7 @@ use solana_client::client_error; use solana_sdk::{account::Account, account_info::AccountInfo, pubkey, pubkey::Pubkey}; use crate::commands::get_config::ChainInfo; +use crate::tracing::{AccountOverride, AccountOverrides, BlockOverrides}; use serde_with::{serde_as, DisplayFromStr}; const FAKE_OPERATOR: Pubkey = pubkey!("neonoperator1111111111111111111111111111111"); diff --git a/evm_loader/lib/src/commands/trace.rs b/evm_loader/lib/src/commands/trace.rs index 6bff5dcbb..8dcc48d20 100644 --- a/evm_loader/lib/src/commands/trace.rs +++ b/evm_loader/lib/src/commands/trace.rs @@ -3,8 +3,7 @@ use std::rc::Rc; use serde_json::Value; use solana_sdk::pubkey::Pubkey; -use evm_loader::evm::tracing::tracers::new_tracer; - +use crate::tracing::tracers::new_tracer; use crate::types::EmulateRequest; use crate::{errors::NeonError, rpc::Rpc}; diff --git a/evm_loader/lib/src/lib.rs b/evm_loader/lib/src/lib.rs index 7475b056c..3cea4c495 100644 --- a/evm_loader/lib/src/lib.rs +++ b/evm_loader/lib/src/lib.rs @@ -7,6 +7,7 @@ pub mod context; pub mod errors; pub mod rpc; pub mod syscall_stubs; +pub mod tracing; pub mod types; pub use config::Config; diff --git a/evm_loader/program/src/evm/tracing/mod.rs b/evm_loader/lib/src/tracing/mod.rs similarity index 73% rename from evm_loader/program/src/evm/tracing/mod.rs rename to evm_loader/lib/src/tracing/mod.rs index 7fd50bb60..4b99e2d01 100644 --- a/evm_loader/program/src/evm/tracing/mod.rs +++ b/evm_loader/lib/src/tracing/mod.rs @@ -1,50 +1,11 @@ -use std::cell::RefCell; -use std::collections::HashMap; -use std::fmt::Debug; -use std::rc::Rc; - -use crate::types::hexbytes::HexBytes; -use crate::types::Address; use ethnum::U256; +use evm_loader::types::hexbytes::HexBytes; +use evm_loader::types::Address; use serde_json::Value; - -use super::{Context, ExitStatus}; +use std::collections::HashMap; pub mod tracers; -pub trait EventListener: Send + Sync + Debug { - fn event(&mut self, event: Event); - fn into_traces(self: Box) -> Value; -} - -pub type TracerType = Rc>>; -pub type TracerTypeOpt = Option; - -/// Trace event -pub enum Event { - BeginVM { - context: Context, - code: Vec, - }, - EndVM { - status: ExitStatus, - }, - BeginStep { - opcode: u8, - pc: usize, - stack: Vec<[u8; 32]>, - memory: Vec, - }, - EndStep { - gas_used: u64, - return_data: Option>, - }, - StorageAccess { - index: U256, - value: [u8; 32], - }, -} - /// See #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] @@ -119,12 +80,3 @@ pub struct TraceCallConfig { pub block_overrides: Option, pub state_overrides: Option, } - -impl From for TraceCallConfig { - fn from(trace_config: TraceConfig) -> Self { - Self { - trace_config, - ..Self::default() - } - } -} diff --git a/evm_loader/program/src/evm/tracing/tracers/mod.rs b/evm_loader/lib/src/tracing/tracers/mod.rs similarity index 56% rename from evm_loader/program/src/evm/tracing/tracers/mod.rs rename to evm_loader/lib/src/tracing/tracers/mod.rs index ed98e1af9..e0dd86756 100644 --- a/evm_loader/program/src/evm/tracing/tracers/mod.rs +++ b/evm_loader/lib/src/tracing/tracers/mod.rs @@ -1,17 +1,17 @@ -use crate::evm::tracing::tracers::struct_logger::StructLogger; -use crate::evm::tracing::TraceConfig; -use crate::evm::tracing::TracerType; +use crate::tracing::tracers::struct_logger::StructLogger; +use crate::tracing::TraceConfig; +use evm_loader::evm::tracing::TracerType; use std::cell::RefCell; use std::rc::Rc; pub mod struct_logger; -pub fn new_tracer(trace_config: &TraceConfig) -> crate::error::Result { +pub fn new_tracer(trace_config: &TraceConfig) -> evm_loader::error::Result { Ok(Rc::new(RefCell::new( match trace_config.tracer.as_deref() { None | Some("") => Box::new(StructLogger::new(trace_config)), _ => { - return Err(crate::error::Error::Custom(format!( + return Err(evm_loader::error::Error::Custom(format!( "Unsupported tracer: {:?}", trace_config.tracer ))) diff --git a/evm_loader/program/src/evm/tracing/tracers/struct_logger.rs b/evm_loader/lib/src/tracing/tracers/struct_logger.rs similarity index 97% rename from evm_loader/program/src/evm/tracing/tracers/struct_logger.rs rename to evm_loader/lib/src/tracing/tracers/struct_logger.rs index 71e7b8adf..b3067d003 100644 --- a/evm_loader/program/src/evm/tracing/tracers/struct_logger.rs +++ b/evm_loader/lib/src/tracing/tracers/struct_logger.rs @@ -1,14 +1,14 @@ use std::collections::BTreeMap; -use crate::evm::ExitStatus; use ethnum::U256; +use evm_loader::evm::ExitStatus; use serde::Serialize; use serde_json::{json, Value}; -use crate::evm::opcode_table::OPNAMES; -use crate::evm::tracing::TraceConfig; -use crate::evm::tracing::{Event, EventListener}; -use crate::types::hexbytes::HexBytes; +use crate::tracing::TraceConfig; +use evm_loader::evm::opcode_table::OPNAMES; +use evm_loader::evm::tracing::{Event, EventListener}; +use evm_loader::types::hexbytes::HexBytes; /// `StructLoggerResult` groups all structured logs emitted by the EVM /// while replaying a transaction in debug mode as well as transaction diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index f446d7309..cf4138198 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -11,7 +11,7 @@ use serde_with::skip_serializing_none; use solana_sdk::pubkey::Pubkey; pub use tracer_ch_db::ClickHouseDb as TracerDb; -use evm_loader::evm::tracing::TraceCallConfig; +use crate::tracing::TraceCallConfig; use ethnum::U256; use serde::{Deserialize, Serialize}; diff --git a/evm_loader/program/src/evm/mod.rs b/evm_loader/program/src/evm/mod.rs index c237db03f..f84010139 100644 --- a/evm_loader/program/src/evm/mod.rs +++ b/evm_loader/program/src/evm/mod.rs @@ -25,7 +25,7 @@ mod buffer; pub mod database; mod memory; mod opcode; -mod opcode_table; +pub mod opcode_table; mod precompile; mod stack; #[cfg(not(target_os = "solana"))] diff --git a/evm_loader/program/src/evm/tracing.rs b/evm_loader/program/src/evm/tracing.rs new file mode 100644 index 000000000..d9386f6ee --- /dev/null +++ b/evm_loader/program/src/evm/tracing.rs @@ -0,0 +1,41 @@ +use std::cell::RefCell; +use std::fmt::Debug; +use std::rc::Rc; + +use ethnum::U256; +use serde_json::Value; + +use super::{Context, ExitStatus}; + +pub trait EventListener: Debug { + fn event(&mut self, event: Event); + fn into_traces(self: Box) -> Value; +} + +pub type TracerType = Rc>>; +pub type TracerTypeOpt = Option; + +/// Trace event +pub enum Event { + BeginVM { + context: Context, + code: Vec, + }, + EndVM { + status: ExitStatus, + }, + BeginStep { + opcode: u8, + pc: usize, + stack: Vec<[u8; 32]>, + memory: Vec, + }, + EndStep { + gas_used: u64, + return_data: Option>, + }, + StorageAccess { + index: U256, + value: [u8; 32], + }, +} From 0c9ea59636b4aaf01da972066d14eb1b439beaef Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Mon, 27 Nov 2023 12:58:56 +0300 Subject: [PATCH 068/318] Correct error when trying to block legacy account (#234) --- evm_loader/program/src/account/legacy/mod.rs | 12 ++++++++++++ evm_loader/program/src/account/mod.rs | 18 ++++++++++++------ evm_loader/program/src/error.rs | 3 +++ 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/evm_loader/program/src/account/legacy/mod.rs b/evm_loader/program/src/account/legacy/mod.rs index 2c5784a80..cf730df67 100644 --- a/evm_loader/program/src/account/legacy/mod.rs +++ b/evm_loader/program/src/account/legacy/mod.rs @@ -219,3 +219,15 @@ pub fn update_legacy_accounts(accounts: &AccountsDB) -> Result { Ok(lamports_collected) } + +#[must_use] +pub fn is_legacy_tag(tag: u8) -> bool { + matches!( + tag, + TAG_ACCOUNT_CONTRACT_DEPRECATED + | TAG_STORAGE_CELL_DEPRECATED + | TAG_HOLDER_DEPRECATED + | TAG_STATE_FINALIZED_DEPRECATED + | TAG_STATE_DEPRECATED + ) +} diff --git a/evm_loader/program/src/account/mod.rs b/evm_loader/program/src/account/mod.rs index 77863afb2..37c73b6e1 100644 --- a/evm_loader/program/src/account/mod.rs +++ b/evm_loader/program/src/account/mod.rs @@ -1,7 +1,4 @@ -use crate::{ - account::legacy::{TAG_ACCOUNT_CONTRACT_DEPRECATED, TAG_STORAGE_CELL_DEPRECATED}, - error::{Error, Result}, -}; +use crate::error::{Error, Result}; use solana_program::account_info::AccountInfo; use solana_program::pubkey::Pubkey; use std::cell::{Ref, RefMut}; @@ -118,6 +115,10 @@ pub fn is_blocked(program_id: &Pubkey, info: &AccountInfo) -> Result { return Err(Error::AccountInvalidData(*info.key)); } + if legacy::is_legacy_tag(data[0]) { + return Err(Error::AccountLegacy(*info.key)); + } + Ok(data[1] == 1) } @@ -126,8 +127,13 @@ fn set_block(program_id: &Pubkey, info: &AccountInfo, block: bool) -> Result<()> assert_eq!(info.owner, program_id); let mut data = info.try_borrow_mut_data()?; - assert!(data.len() >= ACCOUNT_PREFIX_LEN); - assert!(data[0] != TAG_ACCOUNT_CONTRACT_DEPRECATED && data[0] != TAG_STORAGE_CELL_DEPRECATED); + if data.len() < ACCOUNT_PREFIX_LEN { + return Err(Error::AccountInvalidData(*info.key)); + } + + if legacy::is_legacy_tag(data[0]) { + return Err(Error::AccountLegacy(*info.key)); + } if block && (data[1] != 0) { return Err(Error::AccountBlocked(*info.key)); diff --git a/evm_loader/program/src/error.rs b/evm_loader/program/src/error.rs index e824095b0..d0049f7af 100644 --- a/evm_loader/program/src/error.rs +++ b/evm_loader/program/src/error.rs @@ -79,6 +79,9 @@ pub enum Error { #[error("Account {0} - already initialized")] AccountAlreadyInitialized(Pubkey), + #[error("Account {0} - in legacy format")] + AccountLegacy(Pubkey), + #[error("Operator is not authorized")] UnauthorizedOperator, From ad73d3caf05e0fe55e519671948c57fa71ccd9e0 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Tue, 28 Nov 2023 11:12:11 +0300 Subject: [PATCH 069/318] Add ethereum address to accounts (#235) Add ethereum address to accounts --- evm_loader/lib/src/account_storage.rs | 2 +- evm_loader/lib/src/commands/get_balance.rs | 2 +- .../program/src/account/ether_balance.rs | 41 ++++++++++--------- .../program/src/account/ether_contract.rs | 7 ++++ evm_loader/program/src/account/mod.rs | 10 +++++ evm_loader/program/src/account/state.rs | 2 +- .../program/src/account_storage/apply.rs | 2 +- .../program/src/account_storage/base.rs | 2 +- .../src/instruction/transaction_cancel.rs | 18 ++++---- .../transaction_execute_from_account.rs | 3 +- .../transaction_execute_from_instruction.rs | 3 +- .../transaction_step_from_account.rs | 7 +++- .../transaction_step_from_instruction.rs | 7 +++- tests/utils/layouts.py | 2 + 14 files changed, 71 insertions(+), 37 deletions(-) diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index 2c9f1c885..9b3694fd1 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -399,7 +399,7 @@ impl<'rpc> EmulatorAccountStorage<'rpc> { if let Some(account_data) = &mut account { let info = account_info(&pubkey, account_data); - if let Ok(a) = BalanceAccount::from_account(self.program_id(), info, Some(address)) { + if let Ok(a) = BalanceAccount::from_account(self.program_id(), info) { return action(a); } } diff --git a/evm_loader/lib/src/commands/get_balance.rs b/evm_loader/lib/src/commands/get_balance.rs index 80620dc76..760018ee9 100644 --- a/evm_loader/lib/src/commands/get_balance.rs +++ b/evm_loader/lib/src/commands/get_balance.rs @@ -49,7 +49,7 @@ fn read_account( let solana_address = address.find_pubkey(program_id); let account_info = account_info(&solana_address, &mut account); - let balance_account = BalanceAccount::from_account(program_id, account_info, None)?; + let balance_account = BalanceAccount::from_account(program_id, account_info)?; Ok(GetBalanceResponse { solana_address, diff --git a/evm_loader/program/src/account/ether_balance.rs b/evm_loader/program/src/account/ether_balance.rs index 600f1d5f3..d84dd3925 100644 --- a/evm_loader/program/src/account/ether_balance.rs +++ b/evm_loader/program/src/account/ether_balance.rs @@ -17,14 +17,13 @@ use super::{AccountsDB, ACCOUNT_PREFIX_LEN, ACCOUNT_SEED_VERSION, TAG_ACCOUNT_BA #[repr(C, packed)] pub struct Header { - // address: Address, + pub address: Address, pub chain_id: u64, pub trx_count: u64, pub balance: U256, } pub struct BalanceAccount<'a> { - pub address: Option
, account: AccountInfo<'a>, } @@ -36,14 +35,10 @@ impl<'a> BalanceAccount<'a> { ACCOUNT_PREFIX_LEN + size_of::
() } - pub fn from_account( - program_id: &Pubkey, - account: AccountInfo<'a>, - address: Option
, - ) -> Result { + pub fn from_account(program_id: &Pubkey, account: AccountInfo<'a>) -> Result { super::validate_tag(program_id, &account, TAG_ACCOUNT_BALANCE)?; - Ok(Self { address, account }) + Ok(Self { account }) } pub fn create( @@ -60,7 +55,11 @@ impl<'a> BalanceAccount<'a> { // Already created. Return immidiately let account = accounts.get(&pubkey).clone(); if !system_program::check_id(account.owner) { - return Self::from_account(&crate::ID, account, Some(address)); + let balance_account = Self::from_account(&crate::ID, account)?; + assert_eq!(balance_account.address(), address); + assert_eq!(balance_account.chain_id(), chain_id); + + return Ok(balance_account); } if chain_id == DEFAULT_CHAIN_ID { @@ -97,12 +96,10 @@ impl<'a> BalanceAccount<'a> { )?; super::set_tag(&crate::ID, &account, TAG_ACCOUNT_BALANCE)?; - let mut balance_account = Self { - address: Some(address), - account, - }; + let mut balance_account = Self { account }; { let mut header = balance_account.header_mut(); + header.address = address; header.chain_id = chain_id; header.trx_count = 0; header.balance = U256::ZERO; @@ -126,6 +123,11 @@ impl<'a> BalanceAccount<'a> { super::section_mut(&self.account, HEADER_OFFSET) } + #[must_use] + pub fn address(&self) -> Address { + self.header().address + } + #[must_use] pub fn chain_id(&self) -> u64 { self.header().chain_id @@ -148,13 +150,12 @@ impl<'a> BalanceAccount<'a> { } pub fn increment_nonce_by(&mut self, value: u64) -> Result<()> { - let address = self.address.unwrap_or_default(); - let mut header = self.header_mut(); + header.trx_count = header .trx_count .checked_add(value) - .ok_or_else(|| Error::NonceOverflow(address))?; + .ok_or_else(|| Error::NonceOverflow(header.address))?; Ok(()) } @@ -176,14 +177,16 @@ impl<'a> BalanceAccount<'a> { } pub fn burn(&mut self, value: U256) -> Result<()> { - let address = self.address.unwrap_or_default(); - let mut header = self.header_mut(); header.balance = header .balance .checked_sub(value) - .ok_or(Error::InsufficientBalance(address, header.chain_id, value))?; + .ok_or(Error::InsufficientBalance( + header.address, + header.chain_id, + value, + ))?; Ok(()) } diff --git a/evm_loader/program/src/account/ether_contract.rs b/evm_loader/program/src/account/ether_contract.rs index f96fd93cd..4eb41c658 100644 --- a/evm_loader/program/src/account/ether_contract.rs +++ b/evm_loader/program/src/account/ether_contract.rs @@ -25,6 +25,7 @@ pub enum AllocateResult { #[repr(C, packed)] pub struct Header { + pub address: Address, pub chain_id: u64, pub generation: u32, } @@ -122,6 +123,7 @@ impl<'a> ContractAccount<'a> { let mut contract = Self::from_account(&crate::ID, account)?; { let mut header = contract.header_mut(); + header.address = address; header.chain_id = chain_id; header.generation = generation; } @@ -186,6 +188,11 @@ impl<'a> ContractAccount<'a> { self.account.data_len().saturating_sub(CODE_OFFSET) } + #[must_use] + pub fn address(&self) -> Address { + self.header().address + } + #[must_use] pub fn chain_id(&self) -> u64 { self.header().chain_id diff --git a/evm_loader/program/src/account/mod.rs b/evm_loader/program/src/account/mod.rs index 37c73b6e1..8ba611a8c 100644 --- a/evm_loader/program/src/account/mod.rs +++ b/evm_loader/program/src/account/mod.rs @@ -1,4 +1,5 @@ use crate::error::{Error, Result}; +use crate::types::Address; use solana_program::account_info::AccountInfo; use solana_program::pubkey::Pubkey; use std::cell::{Ref, RefMut}; @@ -231,6 +232,15 @@ impl<'a> AccountsDB<'a> { panic!("Operator Balance Account must be present in the transaction"); } + #[must_use] + pub fn operator_balance_address(&self) -> Address { + if let Some(operator_balance) = &self.operator_balance { + return operator_balance.address(); + } + + panic!("Operator Balance Account must be present in the transaction"); + } + #[must_use] pub fn operator_key(&self) -> Pubkey { *self.operator.key diff --git a/evm_loader/program/src/account/state.rs b/evm_loader/program/src/account/state.rs index 64e772ac3..e7b235e1c 100644 --- a/evm_loader/program/src/account/state.rs +++ b/evm_loader/program/src/account/state.rs @@ -358,7 +358,7 @@ impl<'a> StateAccount<'a> { pub fn refund_unused_gas(&mut self, origin: &mut BalanceAccount) -> Result<()> { assert!(origin.chain_id() == self.trx_chain_id()); - assert!(origin.address == Some(self.trx_origin())); + assert!(origin.address() == self.trx_origin()); let unused_gas = self.gas_available(); self.consume_gas(unused_gas, origin) diff --git a/evm_loader/program/src/account_storage/apply.rs b/evm_loader/program/src/account_storage/apply.rs index 2577eb093..a98bfacde 100644 --- a/evm_loader/program/src/account_storage/apply.rs +++ b/evm_loader/program/src/account_storage/apply.rs @@ -38,7 +38,7 @@ impl<'a> ProgramAccountStorage<'a> { let (pubkey, _) = origin.find_balance_address(&crate::ID, chain_id); let source = self.accounts.get(&pubkey).clone(); - let mut source = BalanceAccount::from_account(&crate::ID, source, Some(origin))?; + let mut source = BalanceAccount::from_account(&crate::ID, source)?; let target = self.accounts.operator_balance(); diff --git a/evm_loader/program/src/account_storage/base.rs b/evm_loader/program/src/account_storage/base.rs index f160487b9..3169d66a1 100644 --- a/evm_loader/program/src/account_storage/base.rs +++ b/evm_loader/program/src/account_storage/base.rs @@ -70,7 +70,7 @@ impl<'a> ProgramAccountStorage<'a> { let pubkey = self.keys.balance(&crate::ID, address, chain_id); let account = self.accounts.get(&pubkey); - let result = BalanceAccount::from_account(&crate::ID, account.clone(), Some(address)); + let result = BalanceAccount::from_account(&crate::ID, account.clone()); if result.is_err() && (chain_id == DEFAULT_CHAIN_ID) { let contract_pubkey = self.keys.contract(&crate::ID, address); diff --git a/evm_loader/program/src/instruction/transaction_cancel.rs b/evm_loader/program/src/instruction/transaction_cancel.rs index be9038e4f..21360e828 100644 --- a/evm_loader/program/src/instruction/transaction_cancel.rs +++ b/evm_loader/program/src/instruction/transaction_cancel.rs @@ -12,20 +12,20 @@ pub fn process<'a>( ) -> Result<()> { solana_program::msg!("Instruction: Cancel Transaction"); + let transaction_hash = array_ref![instruction, 0, 32]; + let storage_info = accounts[0].clone(); let operator = Operator::from_account(&accounts[1])?; - let balance = BalanceAccount::from_account(program_id, accounts[2].clone(), None)?; - - let accounts_database = AccountsDB::new(&accounts[3..], operator, Some(balance), None, None); - - let storage = StateAccount::restore(program_id, storage_info, &accounts_database, true)?; - - let transaction_hash = array_ref![instruction, 0, 32]; + let operator_balance = BalanceAccount::from_account(program_id, accounts[2].clone())?; solana_program::log::sol_log_data(&[b"HASH", transaction_hash]); + solana_program::log::sol_log_data(&[b"MINER", operator_balance.address().as_bytes()]); + + let accounts_db = AccountsDB::new(&accounts[3..], operator, Some(operator_balance), None, None); + let storage = StateAccount::restore(program_id, storage_info, &accounts_db, true)?; validate(&storage, transaction_hash)?; - execute(program_id, accounts_database, storage) + execute(program_id, accounts_db, storage) } fn validate(storage: &StateAccount, transaction_hash: &[u8; 32]) -> Result<()> { @@ -60,7 +60,7 @@ fn execute<'a>( { let origin_info = accounts.get(&origin_pubkey).clone(); - let mut account = BalanceAccount::from_account(program_id, origin_info, Some(origin))?; + let mut account = BalanceAccount::from_account(program_id, origin_info)?; account.increment_nonce()?; storage.refund_unused_gas(&mut account)?; diff --git a/evm_loader/program/src/instruction/transaction_execute_from_account.rs b/evm_loader/program/src/instruction/transaction_execute_from_account.rs index a1538f887..5b28216f6 100644 --- a/evm_loader/program/src/instruction/transaction_execute_from_account.rs +++ b/evm_loader/program/src/instruction/transaction_execute_from_account.rs @@ -20,7 +20,7 @@ pub fn process<'a>( let operator = unsafe { Operator::from_account_not_whitelisted(&accounts[1])? }; let treasury = Treasury::from_account(program_id, treasury_index, &accounts[2])?; - let operator_balance = BalanceAccount::from_account(program_id, accounts[3].clone(), None)?; + let operator_balance = BalanceAccount::from_account(program_id, accounts[3].clone())?; let system = program::System::from_account(&accounts[4])?; holder.validate_owner(&operator)?; @@ -30,6 +30,7 @@ pub fn process<'a>( let origin = trx.recover_caller_address()?; solana_program::log::sol_log_data(&[b"HASH", &trx.hash()]); + solana_program::log::sol_log_data(&[b"MINER", operator_balance.address().as_bytes()]); let accounts_db = AccountsDB::new( &accounts[5..], diff --git a/evm_loader/program/src/instruction/transaction_execute_from_instruction.rs b/evm_loader/program/src/instruction/transaction_execute_from_instruction.rs index bd2aeb998..ffe964728 100644 --- a/evm_loader/program/src/instruction/transaction_execute_from_instruction.rs +++ b/evm_loader/program/src/instruction/transaction_execute_from_instruction.rs @@ -19,13 +19,14 @@ pub fn process<'a>( let operator = unsafe { Operator::from_account_not_whitelisted(&accounts[0])? }; let treasury = Treasury::from_account(program_id, treasury_index, &accounts[1])?; - let operator_balance = BalanceAccount::from_account(program_id, accounts[2].clone(), None)?; + let operator_balance = BalanceAccount::from_account(program_id, accounts[2].clone())?; let system = program::System::from_account(&accounts[3])?; let trx = Transaction::from_rlp(messsage)?; let origin = trx.recover_caller_address()?; solana_program::log::sol_log_data(&[b"HASH", &trx.hash()]); + solana_program::log::sol_log_data(&[b"MINER", operator_balance.address().as_bytes()]); let accounts_db = AccountsDB::new( &accounts[4..], diff --git a/evm_loader/program/src/instruction/transaction_step_from_account.rs b/evm_loader/program/src/instruction/transaction_step_from_account.rs index 7872e9eaa..2697a430b 100644 --- a/evm_loader/program/src/instruction/transaction_step_from_account.rs +++ b/evm_loader/program/src/instruction/transaction_step_from_account.rs @@ -35,9 +35,11 @@ pub fn process_inner<'a>( let operator = Operator::from_account(&accounts[1])?; let treasury = Treasury::from_account(program_id, treasury_index, &accounts[2])?; - let operator_balance = BalanceAccount::from_account(program_id, accounts[3].clone(), None)?; + let operator_balance = BalanceAccount::from_account(program_id, accounts[3].clone())?; let system = program::System::from_account(&accounts[4])?; + let miner_address = operator_balance.address(); + let accounts_db = AccountsDB::new( &accounts[5..], operator.clone(), @@ -68,6 +70,8 @@ pub fn process_inner<'a>( }; solana_program::log::sol_log_data(&[b"HASH", &trx.hash]); + solana_program::log::sol_log_data(&[b"MINER", miner_address.as_bytes()]); + let origin = trx.recover_caller_address()?; let mut gasometer = Gasometer::new(U256::ZERO, accounts_db.operator())?; @@ -98,6 +102,7 @@ pub fn process_inner<'a>( StateAccount::restore(program_id, holder_or_storage.clone(), &accounts_db, false)?; solana_program::log::sol_log_data(&[b"HASH", &storage.trx_hash()]); + solana_program::log::sol_log_data(&[b"MINER", miner_address.as_bytes()]); let mut gasometer = Gasometer::new(storage.gas_used(), accounts_db.operator())?; gasometer.record_solana_transaction_cost(); diff --git a/evm_loader/program/src/instruction/transaction_step_from_instruction.rs b/evm_loader/program/src/instruction/transaction_step_from_instruction.rs index 3cdf97f70..656d8915d 100644 --- a/evm_loader/program/src/instruction/transaction_step_from_instruction.rs +++ b/evm_loader/program/src/instruction/transaction_step_from_instruction.rs @@ -27,9 +27,11 @@ pub fn process<'a>( let operator = Operator::from_account(&accounts[1])?; let treasury = Treasury::from_account(program_id, treasury_index, &accounts[2])?; - let operator_balance = BalanceAccount::from_account(program_id, accounts[3].clone(), None)?; + let operator_balance = BalanceAccount::from_account(program_id, accounts[3].clone())?; let system = program::System::from_account(&accounts[4])?; + let miner_address = operator_balance.address(); + let accounts_db = AccountsDB::new( &accounts[5..], operator.clone(), @@ -51,6 +53,7 @@ pub fn process<'a>( let origin = trx.recover_caller_address()?; solana_program::log::sol_log_data(&[b"HASH", &trx.hash()]); + solana_program::log::sol_log_data(&[b"MINER", miner_address.as_bytes()]); let mut gasometer = Gasometer::new(U256::ZERO, accounts_db.operator())?; gasometer.record_solana_transaction_cost(); @@ -65,7 +68,9 @@ pub fn process<'a>( } TAG_STATE => { let storage = StateAccount::restore(program_id, storage_info, &accounts_db, false)?; + solana_program::log::sol_log_data(&[b"HASH", &storage.trx_hash()]); + solana_program::log::sol_log_data(&[b"MINER", miner_address.as_bytes()]); let mut gasometer = Gasometer::new(storage.gas_used(), accounts_db.operator())?; gasometer.record_solana_transaction_cost(); diff --git a/tests/utils/layouts.py b/tests/utils/layouts.py index 68cb2dcfa..461358bd0 100644 --- a/tests/utils/layouts.py +++ b/tests/utils/layouts.py @@ -35,6 +35,7 @@ CONTRACT_ACCOUNT_LAYOUT = Struct( "type" / Int8ul, "blocked" / Int8ul, + "address" / Bytes(20), "chain_id" / Int64ul, "generation" / Int32ul, ) @@ -42,6 +43,7 @@ BALANCE_ACCOUNT_LAYOUT = Struct( "type" / Int8ul, "blocked" / Int8ul, + "address" / Bytes(20), "chain_id" / Int64ul, "trx_count" / Int64ul, "balance" / Bytes(32), From 0535388e67f529d44d134992219858b301a83ccd Mon Sep 17 00:00:00 2001 From: Vladimir Bugaev Date: Thu, 30 Nov 2023 21:11:13 +0700 Subject: [PATCH 070/318] Update LICENSE --- LICENSE | 105 +++++++++----------------------------------------------- 1 file changed, 16 insertions(+), 89 deletions(-) diff --git a/LICENSE b/LICENSE index d9db7a3c4..4491f8b8c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,92 +1,19 @@ -Business Source License 1.1 +Neon EVM License -License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved. -"Business Source License" is a trademark of MariaDB Corporation Ab. - ------------------------------------------------------------------------------ - -Parameters - -Licensor: Neon Labs - -Licensed Work: Neon EVM - The Licensed Work is (c) 2021 Neon Labs - ------------------------------------------------------------------------------ +Copyright (c) 2023 by Neon Protocol Ltd. +All rights reserved. Terms - -The Licensor hereby grants you the right to copy, modify, create derivative -works, redistribute, and make non-production use of the Licensed Work. The -Licensor may make an Additional Use Grant, above, permitting limited -production use. - -Effective on the Change Date, or the fourth anniversary of the first publicly -available distribution of a specific version of the Licensed Work under this -License, whichever comes first, the Licensor hereby grants you rights under -the terms of the Change License, and the rights granted in the paragraph -above terminate. - -If your use of the Licensed Work does not comply with the requirements -currently in effect as described in this License, you must purchase a -commercial license from the Licensor, its affiliated entities, or authorized -resellers, or you must refrain from using the Licensed Work. - -All copies of the original and modified Licensed Work, and derivative works -of the Licensed Work, are subject to this License. This License applies -separately for each version of the Licensed Work and the Change Date may vary -for each version of the Licensed Work released by Licensor. - -You must conspicuously display this License on each original or modified copy -of the Licensed Work. If you receive the Licensed Work in original or -modified form from a third party, the terms and conditions set forth in this -License apply to your use of that work. - -Any use of the Licensed Work in violation of this License will automatically -terminate your rights under this License for the current and all other -versions of the Licensed Work. - -This License does not grant you any right in any trademark or logo of -Licensor or its affiliates (provided that you may use a trademark or logo of -Licensor as expressly required by this License). - -TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON -AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, -EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND -TITLE. - -MariaDB hereby grants you permission to use this License’s text to license -your works, and to refer to it using the trademark "Business Source License", -as long as you comply with the Covenants of Licensor below. - ------------------------------------------------------------------------------ - -Covenants of Licensor - -In consideration of the right to use this License’s text and the "Business -Source License" name and trademark, Licensor covenants to MariaDB, and to all -other recipients of the licensed work to be provided by Licensor: - -1. To specify as the Change License the GPL Version 2.0 or any later version, - or a license that is compatible with GPL Version 2.0 or a later version, - where "compatible" means that software provided under the Change License can - be included in a program with software provided under GPL Version 2.0 or a - later version. Licensor may specify additional Change Licenses without - limitation. - -2. To either: (a) specify an additional grant of rights to use that does not - impose any additional restriction on the right granted in this License, as - the Additional Use Grant; or (b) insert the text "None". - -3. To specify a Change Date. - -4. Not to modify this License in any other way. - ------------------------------------------------------------------------------ - -Notice - -The Business Source License (this document, or the "License") is not an Open -Source license. However, the Licensed Work will eventually be made available -under an Open Source License, as stated in this License. +1. **Grant of license:** non-commercial usage for information purposes only, without the right to copy or compile. +1. **Restrictions:** The code, in whole or in part (“Licensed Work”), may not be copied, reproduced, distributed, modified, or forked without explicit prior written permission from Neon Protocol Ltd. +1. **No Redistribution:** Redistribution of the source code or any derivative work is strictly prohibited. If you wish to use in any way or distribute the software, please request permission by contacting legal@neonfoundation.io. +1. **Audit and Enforcement:** Neon Protocol Ltd. reserves the right to audit uses of the Licensed Work to ensure compliance with this license. +1. **Legal Recourse for Violation:** Violations may result in legal action, including injunctions, damages, and recovery of legal costs. +1. **Notification of Changes:** Any modifications under permission must be documented and communicated to Neon Protocol Ltd. +1. **Attribution and Branding:** Distributions (if approved by Neon Protocol Ltd) must include attribution to Neon Protocol Ltd. and adhere to specified branding guidelines. +1. **Limitations on Transferability:** Rights and permissions under this license are non-transferable and non-sublicensable, unless explicitly allowed by Neon Protocol Ltd. +1. **Acknowledgement:** Permitted redistributions must include: “Copyright (c) 2023 by Neon Protocol Ltd”. +1. **License Scope:** Applies to all versions of the Licensed Work, including copies, modifications, and derivatives. +1. **Termination for Violation:** Any violation terminates your rights for all versions of the Licensed Work. +1. **Trademark Rights:** No rights granted in any trademark or logo of the Neon Protocol Ltd, except as required by this License. +1. **Disclaimer:** The Licensed Work is provided “AS IS” without any warranties From 4246c164eaa35132406927e62379685a76b779ec Mon Sep 17 00:00:00 2001 From: Vladimir Bugaev Date: Thu, 30 Nov 2023 21:15:30 +0700 Subject: [PATCH 071/318] Update LICENSE --- LICENSE | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/LICENSE b/LICENSE index 4491f8b8c..b0220600a 100644 --- a/LICENSE +++ b/LICENSE @@ -4,16 +4,16 @@ Copyright (c) 2023 by Neon Protocol Ltd. All rights reserved. Terms -1. **Grant of license:** non-commercial usage for information purposes only, without the right to copy or compile. -1. **Restrictions:** The code, in whole or in part (“Licensed Work”), may not be copied, reproduced, distributed, modified, or forked without explicit prior written permission from Neon Protocol Ltd. -1. **No Redistribution:** Redistribution of the source code or any derivative work is strictly prohibited. If you wish to use in any way or distribute the software, please request permission by contacting legal@neonfoundation.io. -1. **Audit and Enforcement:** Neon Protocol Ltd. reserves the right to audit uses of the Licensed Work to ensure compliance with this license. -1. **Legal Recourse for Violation:** Violations may result in legal action, including injunctions, damages, and recovery of legal costs. -1. **Notification of Changes:** Any modifications under permission must be documented and communicated to Neon Protocol Ltd. -1. **Attribution and Branding:** Distributions (if approved by Neon Protocol Ltd) must include attribution to Neon Protocol Ltd. and adhere to specified branding guidelines. -1. **Limitations on Transferability:** Rights and permissions under this license are non-transferable and non-sublicensable, unless explicitly allowed by Neon Protocol Ltd. -1. **Acknowledgement:** Permitted redistributions must include: “Copyright (c) 2023 by Neon Protocol Ltd”. -1. **License Scope:** Applies to all versions of the Licensed Work, including copies, modifications, and derivatives. -1. **Termination for Violation:** Any violation terminates your rights for all versions of the Licensed Work. -1. **Trademark Rights:** No rights granted in any trademark or logo of the Neon Protocol Ltd, except as required by this License. -1. **Disclaimer:** The Licensed Work is provided “AS IS” without any warranties + 1. Grant of license: non-commercial usage for information purposes only, without the right to copy or compile. + 2. Restrictions: The code, in whole or in part (“Licensed Work”), may not be copied, reproduced, distributed, modified, or forked without explicit prior written permission from Neon Protocol Ltd. + 3. No Redistribution: Redistribution of the source code or any derivative work is strictly prohibited. If you wish to use in any way or distribute the software, please request permission by contacting legal@neonfoundation.io. + 4. Audit and Enforcement: Neon Protocol Ltd. reserves the right to audit uses of the Licensed Work to ensure compliance with this license. + 5. Legal Recourse for Violation: Violations may result in legal action, including injunctions, damages, and recovery of legal costs. + 6. Notification of Changes: Any modifications under permission must be documented and communicated to Neon Protocol Ltd. + 7. Attribution and Branding: Distributions (if approved by Neon Protocol Ltd) must include attribution to Neon Protocol Ltd. and adhere to specified branding guidelines. + 8. Limitations on Transferability: Rights and permissions under this license are non-transferable and non-sublicensable, unless explicitly allowed by Neon Protocol Ltd. + 9. Acknowledgement: Permitted redistributions must include: “Copyright (c) 2023 by Neon Protocol Ltd”. + 10. License Scope: Applies to all versions of the Licensed Work, including copies, modifications, and derivatives. + 11. Termination for Violation: Any violation terminates your rights for all versions of the Licensed Work. + 12. Trademark Rights: No rights granted in any trademark or logo of the Neon Protocol Ltd, except as required by this License. + 13. Disclaimer: The Licensed Work is provided “AS IS” without any warranties From 70cc42ec3565cc8c21bb940e78c9d56435bb7e76 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Mon, 4 Dec 2023 15:06:00 +0300 Subject: [PATCH 072/318] Use solana-test-validator for the CI (#239) * Use solana-test-validator * Add neon_test_invoke_program to the genesis --- .dockerignore | 1 + .gitignore | 1 + Dockerfile | 58 ++--- ci/docker-compose-ci.yml | 9 +- ci/docker-compose-test.yml | 3 +- ci/solana-run-neon.sh | 43 ++++ ci/wait-for-neon.sh | 4 +- ci/wait-for-solana.sh | 22 +- evm_loader/solana-run-neon.sh | 61 ----- tests/conftest.py | 21 +- tests/solana_utils.py | 232 +++++++++----------- tests/test_cli.py | 16 +- tests/test_parallel.py | 5 +- tests/test_transaction_step_from_account.py | 3 +- tests/utils/contract.py | 5 +- tests/utils/instructions.py | 49 ++++- tests/utils/transaction_checks.py | 2 +- 17 files changed, 255 insertions(+), 280 deletions(-) create mode 100755 ci/solana-run-neon.sh delete mode 100755 evm_loader/solana-run-neon.sh diff --git a/.dockerignore b/.dockerignore index bcd73a3cc..3d2d744f8 100644 --- a/.dockerignore +++ b/.dockerignore @@ -17,6 +17,7 @@ evm_loader/rust-evm/gasometer/target evm_loader/rust-evm/runtime/target evm_loader/rust-evm/src/target evm_loader/target +test-ledger .idea venv diff --git a/.gitignore b/.gitignore index 75aec949c..d79576072 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ hfuzz_workspace *.code-workspace evm_loader/solidity/artifacts evm_loader/solidity/cache +test-ledger \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 55744efae..333ca365d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,12 +6,13 @@ WORKDIR /opt ARG SOLANA_BPF_VERSION RUN sh -c "$(curl -sSfL https://release.solana.com/"${SOLANA_BPF_VERSION}"/install)" && \ /root/.local/share/solana/install/active_release/bin/sdk/sbf/scripts/install.sh -ENV PATH=/root/.local/share/solana/install/active_release/bin:/usr/local/cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +ENV PATH=${PATH}:/root/.local/share/solana/install/active_release/bin # Build evm_loader FROM builder AS evm-loader-builder -COPY . /opt/neon-evm/ +COPY .git /opt/neon-evm/.git +COPY evm_loader /opt/neon-evm/evm_loader WORKDIR /opt/neon-evm/evm_loader ARG REVISION ENV NEON_REVISION=${REVISION} @@ -27,61 +28,38 @@ RUN cargo fmt --check && \ cargo build-bpf --features ci --dump # Build Solidity contracts -FROM ethereum/solc:0.8.0 AS solc -FROM ubuntu:20.04 AS contracts -RUN apt-get update && \ - DEBIAN_FRONTEND=nontineractive apt-get -y install xxd && \ - rm -rf /var/lib/apt/lists/* /var/lib/apt/cache/* +FROM ethereum/solc:stable-alpine AS contracts COPY tests/contracts/*.sol /opt/ COPY solidity/*.sol /opt/ -#COPY evm_loader/tests/test_solidity_precompiles.json /opt/ -COPY --from=solc /usr/bin/solc /usr/bin/solc WORKDIR /opt/ -RUN solc --optimize --optimize-runs 200 --output-dir . --bin *.sol && \ +RUN /usr/local/bin/solc --optimize --optimize-runs 200 --output-dir . --bin *.sol && \ for file in $(ls *.bin); do xxd -r -p $file >${file}ary; done && \ ls -l -# Define solana-image that contains utility -FROM ${SOLANA_IMAGE} AS solana +# Add neon_test_invoke_program to the genesis +FROM neonlabsorg/neon_test_invoke_program:develop AS neon_test_invoke_program -# Build target image -FROM ubuntu:20.04 AS base -WORKDIR /opt -RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get -y install vim less openssl ca-certificates curl python3 python3-pip parallel && \ - rm -rf /var/lib/apt/lists/* +# Define solana-image that contains utility +FROM builder AS base +RUN apt-get update +RUN apt-get -y install curl python3 python3-pip COPY tests/requirements.txt /tmp/ RUN pip3 install -r /tmp/requirements.txt -#COPY /evm_loader/solidity/ /opt/contracts/contracts/ -WORKDIR /opt - -COPY --from=solana \ - /usr/bin/solana \ - /usr/bin/solana-validator \ - /usr/bin/solana-keygen \ - /usr/bin/solana-faucet \ - /usr/bin/solana-genesis \ - /usr/bin/solana-run.sh \ - /usr/bin/fetch-spl.sh \ - /usr/bin/spl* \ - /opt/solana/bin/ - -RUN /opt/solana/bin/solana program dump metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s /opt/solana/bin/metaplex.so --url mainnet-beta - -COPY evm_loader/solana-run-neon.sh \ - /opt/solana/bin/ +RUN solana program dump metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s /opt/metaplex.so --url mainnet-beta COPY --from=evm-loader-builder /opt/neon-evm/evm_loader/target/deploy/evm_loader*.so /opt/ COPY --from=evm-loader-builder /opt/neon-evm/evm_loader/target/deploy/evm_loader-dump.txt /opt/ COPY --from=evm-loader-builder /opt/neon-evm/evm_loader/target/release/neon-cli /opt/ COPY --from=evm-loader-builder /opt/neon-evm/evm_loader/target/release/neon-api /opt/ -COPY --from=solana /usr/bin/spl-token /opt/spl-token COPY --from=contracts /opt/ /opt/solidity/ -COPY --from=contracts /usr/bin/solc /usr/bin/solc +COPY --from=neon_test_invoke_program /opt/neon_test_invoke_program.so /opt/ +COPY --from=neon_test_invoke_program /opt/neon_test_invoke_program-keypair.json /opt/ + COPY ci/wait-for-solana.sh \ ci/wait-for-neon.sh \ + ci/solana-run-neon.sh \ ci/deploy-evm.sh \ ci/deploy-test.sh \ ci/create-test-accounts.sh \ @@ -95,4 +73,6 @@ COPY ci/operator-keypairs/id2.json /root/.config/solana/id2.json COPY ci/keys/ /opt/keys #ENV CONTRACTS_DIR=/opt/solidity/ -ENV PATH=/opt/solana/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt +ENV PATH=${PATH}:/opt + +ENTRYPOINT [ "/opt/solana-run-neon.sh" ] diff --git a/ci/docker-compose-ci.yml b/ci/docker-compose-ci.yml index c86929df7..e7ef0b13b 100644 --- a/ci/docker-compose-ci.yml +++ b/ci/docker-compose-ci.yml @@ -4,8 +4,8 @@ services: solana: image: ${EVM_LOADER_IMAGE} environment: - - RUST_LOG=solana_runtime::system_instruction_processor=trace,solana_runtime::message_processor=debug,solana_bpf_loader=debug,solana_rbpf=debug - - SOLANA_URL=http://solana:8899 + - SOLANA_URL=http://127.0.0.1:8899 + - CI=true hostname: solana ports: - "8899" @@ -16,14 +16,15 @@ services: soft: 1048576 hard: 1048576 entrypoint: - /opt/solana/bin/solana-run-neon.sh + /opt/solana-run-neon.sh networks: - net dk-neon-api: restart: unless-stopped hostname: neon_api - command: /opt/neon-api -H 0.0.0.0:8085 + entrypoint: + /opt/neon-api -H 0.0.0.0:8085 environment: RUST_BACKTRACE: 1 RUST_LOG: debug diff --git a/ci/docker-compose-test.yml b/ci/docker-compose-test.yml index d9ce3d0cd..c705b2fef 100644 --- a/ci/docker-compose-test.yml +++ b/ci/docker-compose-test.yml @@ -5,7 +5,6 @@ services: container_name: solana image: ${EVM_LOADER_IMAGE} environment: - - RUST_LOG=solana_runtime::system_instruction_processor=trace,solana_runtime::message_processor=debug,solana_bpf_loader=debug,solana_rbpf=debug - SOLANA_URL=http://127.0.0.1:8899 hostname: solana ports: @@ -19,7 +18,7 @@ services: - "8900" - "8003/udp" entrypoint: - /opt/solana/bin/solana-run-neon.sh + /opt/solana-run-neon.sh # proxy: # container_name: proxy diff --git a/ci/solana-run-neon.sh b/ci/solana-run-neon.sh new file mode 100755 index 000000000..8f58a1122 --- /dev/null +++ b/ci/solana-run-neon.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash + +set -em + +NEON_BIN=/opt + +EVM_LOADER_AUTHORITY_KEYPAIR=${NEON_BIN}/evm_loader-keypair.json +EVM_LOADER_PROGRAM_ID_KEYPAIR=${NEON_BIN}/evm_loader-keypair.json +EVM_LOADER=$(solana address -k ${EVM_LOADER_PROGRAM_ID_KEYPAIR}) +EVM_LOADER_PATH=${NEON_BIN}/evm_loader.so + +METAPLEX=metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s +METAPLEX_PATH=${NEON_BIN}/metaplex.so + +TEST_INVOKE_PROGRAM_ID_KEYPAIR=${NEON_BIN}/neon_test_invoke_program-keypair.json +TEST_INVOKE=$(solana address -k ${TEST_INVOKE_PROGRAM_ID_KEYPAIR}) +TEST_INVOKE_PATH=${NEON_BIN}/neon_test_invoke_program.so + +VALIDATOR_ARGS=( + --reset + --warp-slot 1 + --log-messages-bytes-limit 50000 + --ticks-per-slot 16 + --upgradeable-program ${EVM_LOADER} ${EVM_LOADER_PATH} ${EVM_LOADER_AUTHORITY_KEYPAIR} + --bpf-program ${METAPLEX} ${METAPLEX_PATH} + --bpf-program ${TEST_INVOKE} ${TEST_INVOKE_PATH} +) + +if [[ -n $GEYSER_PLUGIN_CONFIG ]]; then + echo "Using geyser plugin with config: $GEYSER_PLUGIN_CONFIG" + VALIDATOR_ARGS+=(--geyser-plugin-config $GEYSER_PLUGIN_CONFIG) +fi + +export RUST_LOG=solana_runtime::system_instruction_processor=trace,solana_runtime::message_processor=debug,solana_bpf_loader=debug,solana_rbpf=debug +solana-test-validator "${VALIDATOR_ARGS[@]}" > /dev/null & +./wait-for-solana.sh ${SOLANA_WAIT_TIMEOUT:-60} + +neon-cli --url http://localhost:8899 --evm_loader $EVM_LOADER \ + --commitment confirmed \ + --keypair ${EVM_LOADER_AUTHORITY_KEYPAIR} \ + --loglevel trace init-environment --send-trx --keys-dir /opt/keys + +tail +1f test-ledger/validator.log diff --git a/ci/wait-for-neon.sh b/ci/wait-for-neon.sh index 19b676ac3..878cbdc0f 100755 --- a/ci/wait-for-neon.sh +++ b/ci/wait-for-neon.sh @@ -7,7 +7,7 @@ set -euo pipefail ./wait-for-solana.sh "$@" if [ $# -eq 0 ]; then - if neon-cli --url $SOLANA_URL --commitment finalized --evm_loader $EVM_LOADER --loglevel off init-environment > /dev/null; then + if neon-cli --url $SOLANA_URL --commitment confirmed --evm_loader $EVM_LOADER --loglevel off init-environment > /dev/null; then echo "Executed neon-cli init-environment successfully" exit 0 fi @@ -16,7 +16,7 @@ else echo "Waiting $WAIT_TIME seconds for NeonEVM to be available at $SOLANA_URL:$EVM_LOADER" for i in $(seq 1 $WAIT_TIME); do echo "Try neon-cli init-environment count=$i" - if neon-cli --url $SOLANA_URL --commitment finalized --evm_loader $EVM_LOADER --loglevel off init-environment > /dev/null; then + if neon-cli --url $SOLANA_URL --commitment confirmed --evm_loader $EVM_LOADER --loglevel off init-environment > /dev/null; then echo "Executed neon-cli init-environment successfully after count=$i" exit 0 fi diff --git a/ci/wait-for-solana.sh b/ci/wait-for-solana.sh index ebe0ec736..87efc2ff1 100755 --- a/ci/wait-for-solana.sh +++ b/ci/wait-for-solana.sh @@ -1,16 +1,14 @@ #!/bin/bash set -euo pipefail -: ${SOLANA_URL:?is not set} - function check_solana() { local DATA='{"jsonrpc":"2.0","id":1,"method":"getHealth"}' local RESULT='"ok"' - local CHECK_COMMAND="curl $SOLANA_URL -s -X POST -H 'Content-Type: application/json' -d '$DATA' | grep -cF '$RESULT'" + local CHECK_COMMAND="curl http://localhost:8899 -s -X POST -H 'Content-Type: application/json' -d '$DATA' | grep -cF '$RESULT'" local CHECK_COMMAND_RESULT=$(eval $CHECK_COMMAND) if [[ "$CHECK_COMMAND_RESULT" == "1" ]]; then - exit 0 + exit 0 fi exit 1 } @@ -19,16 +17,16 @@ if [ $# -eq 0 ]; then if $(check_solana); then exit 0; fi else WAIT_TIME=$1 - echo "Waiting $WAIT_TIME seconds for solana cluster to be available at $SOLANA_URL" + echo "Waiting $WAIT_TIME seconds for solana cluster to be available at localhost" for i in $(seq 1 $WAIT_TIME); do - echo "Try solana getHealth count=$i" - if $(check_solana); then - echo "Executed solana getHealth successfully after count=$i" - exit 0 - fi - sleep 1 + echo "Try solana getHealth count=$i" + if $(check_solana); then + echo "Executed solana getHealth successfully after count=$i" + exit 0 + fi + sleep 1 done fi -echo "unable to connect to solana cluster $SOLANA_URL" +echo "unable to connect to solana cluster localhost" exit 1 diff --git a/evm_loader/solana-run-neon.sh b/evm_loader/solana-run-neon.sh deleted file mode 100755 index 50db9f4f9..000000000 --- a/evm_loader/solana-run-neon.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env bash - -set -e - -SOLANA_BIN=/opt/solana/bin -NEON_BIN=/opt - -EVM_LOADER_SO=evm_loader.so -EVM_LOADER=$(${SOLANA_BIN}/solana address -k ${NEON_BIN}/evm_loader-keypair.json) -EVM_LOADER_PATH=${NEON_BIN}/${EVM_LOADER_SO} - -function initialize_neon() { - # deploy tokens needed by Neon EVM - # temporary disable load NeonEVM in genesis - #export SKIP_EVM_DEPLOY=${DEPLOY_EVM_IN_GENESIS:-NO} - export SKIP_EVM_DEPLOY=NO - export SOLANA_URL=http://127.0.0.1:8899 - export EVM_LOADER - - cd ${NEON_BIN} - ./wait-for-solana.sh ${SOLANA_WAIT_TIMEOUT:-60} - ./deploy-evm.sh -} - -initialize_neon & - -# run Solana with Neon EVM in genesis -cd ${SOLANA_BIN} -cp ${EVM_LOADER_PATH} . - -# dump metaplex program from mainnet -METAPLEX=metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s -METAPLEX_SO=metaplex.so - -if [[ "${DEPLOY_EVM_IN_GENESIS:-YES}" == "YES" ]]; then -# temporary disable load NeoneEVM in genesis -# NEON_BPF_ARGS=( -# --bpf-program ${EVM_LOADER} BPFLoader2111111111111111111111111111111111 ${EVM_LOADER_SO} -# --bpf-program ${METAPLEX} BPFLoader2111111111111111111111111111111111 ${METAPLEX_SO} -# ) - NEON_BPF_ARGS=( - --bpf-program ${METAPLEX} BPFLoader2111111111111111111111111111111111 ${METAPLEX_SO} - ) -fi - -NEON_VALIDATOR_ARGS=( - --gossip-host $(hostname -i) - --log-messages-bytes-limit 50000 - # See https://github.com/solana-labs/solana/issues/33205 for why this is required for run-neon-evm-tests - --allow-private-addr -) - -if [[ -n $GEYSER_PLUGIN_CONFIG ]]; then - echo "Using geyser plugin with config: $GEYSER_PLUGIN_CONFIG" - NEON_VALIDATOR_ARGS+=(--geyser-plugin-config $GEYSER_PLUGIN_CONFIG) -fi - -export SOLANA_RUN_SH_GENESIS_ARGS="${NEON_BPF_ARGS[@]}" -export SOLANA_RUN_SH_VALIDATOR_ARGS="${NEON_VALIDATOR_ARGS[@]}" - -./solana-run.sh diff --git a/tests/conftest.py b/tests/conftest.py index 26e18a31e..74baf0b08 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -11,7 +11,7 @@ from solana.rpc.commitment import Confirmed from .solana_utils import EvmLoader, create_treasury_pool_address, make_new_user, \ - deposit_neon, solana_client, spl_cli, wait_confirm_transaction, get_solana_balance + deposit_neon, solana_client, get_solana_balance, wait_for_account_to_exists from .utils.constants import NEON_TOKEN_MINT_ID from .utils.contract import deploy_contract from .utils.storage import create_holder @@ -27,7 +27,7 @@ def pytest_addoption(parser): def pytest_configure(): - if "RUST_LOG" in os.environ: + if "CI" in os.environ: pytest.CONTRACTS_PATH = pathlib.Path("/opt/solidity") else: pytest.CONTRACTS_PATH = pathlib.Path(__file__).parent / "contracts" @@ -44,8 +44,11 @@ def prepare_operator(key_file): secret_key = json.load(key)[:32] account = Keypair.from_secret_key(secret_key) - tx = solana_client.request_airdrop(account.public_key, 1000000 * 10 ** 9, commitment=Confirmed) - wait_confirm_transaction(solana_client, tx.value) + solana_client.request_airdrop(account.public_key, 1000 * 10 ** 9, commitment=Confirmed) + wait_for_account_to_exists(solana_client, account.public_key) + + a = solana_client.get_account_info(account.public_key, commitment=Confirmed) + print(f"{a}") operator_ether = eth_keys.PrivateKey(account.secret_key[:32]).public_key.to_canonical_address() @@ -53,12 +56,18 @@ def prepare_operator(key_file): ether_balance_pubkey = evm_loader.ether2balance(operator_ether) acc_info = solana_client.get_account_info(ether_balance_pubkey, commitment=Confirmed) if acc_info.value is None: - token = spl_cli.create_token_account(NEON_TOKEN_MINT_ID, account.public_key, fee_payer=key_file) - spl_cli.mint(NEON_TOKEN_MINT_ID, token, 5000000, fee_payer=key_file) evm_loader.create_balance_account(operator_ether) return account +@pytest.fixture(scope="session") +def default_operator_keypair() -> Keypair: + """ + Initialized solana keypair with balance. Get private keys from ci/operator-keypairs/id.json + """ + key_path = pathlib.Path(__file__).parent.parent / "operator-keypairs" + key_file = key_path / "id.json" + return prepare_operator(key_file) @pytest.fixture(scope="session") def operator_keypair(worker_id) -> Keypair: diff --git a/tests/solana_utils.py b/tests/solana_utils.py index ba26728b3..f71358858 100644 --- a/tests/solana_utils.py +++ b/tests/solana_utils.py @@ -26,7 +26,7 @@ from solders.rpc.responses import SendTransactionResp, GetTransactionResp from solders.transaction_status import TransactionConfirmationStatus from spl.token.constants import TOKEN_PROGRAM_ID -from spl.token.instructions import get_associated_token_address, ApproveParams +from spl.token.instructions import get_associated_token_address, ApproveParams, MintToParams from .utils.constants import CHAIN_ID @@ -34,12 +34,12 @@ ACCOUNT_SEED_VERSION, TREASURY_POOL_SEED from .utils.instructions import make_DepositV03, make_Cancel, make_WriteHolder, make_ExecuteTrxFromInstruction, \ TransactionWithComputeBudget, make_PartialCallOrContinueFromRawEthereumTX, \ - make_ExecuteTrxFromAccountDataIterativeOrContinue + make_ExecuteTrxFromAccountDataIterativeOrContinue, make_CreateAssociatedTokenIdempotent from .utils.layouts import BALANCE_ACCOUNT_LAYOUT, CONTRACT_ACCOUNT_LAYOUT from .utils.types import Caller, Contract EVM_LOADER_SO = os.environ.get("EVM_LOADER_SO", 'target/bpfel-unknown-unknown/release/evm_loader.so') -solana_client = Client(SOLANA_URL) +solana_client = Client(SOLANA_URL, commitment=Confirmed) path_to_solana = 'solana' # amount of gas per 1 byte evm_storage @@ -59,56 +59,6 @@ # account storage overhead for calculation of base rent ACCOUNT_STORAGE_OVERHEAD = 128 -class SplToken: - def __init__(self, url): - self.url = url - - def call(self, arguments): - cmd = 'spl-token --url {} {}'.format(self.url, arguments) - print('cmd:', cmd) - try: - return subprocess.check_output(cmd, shell=True, universal_newlines=True) - except subprocess.CalledProcessError as err: - import sys - print("ERR: spl-token error {}".format(err)) - raise - - def transfer(self, mint, amount, recipient): - self.call("transfer {} {} {}".format(mint, amount, recipient)) - - def balance(self, acc): - from decimal import Decimal - res = self.call("balance --address {}".format(acc)) - return Decimal(res.rstrip()) - - def mint(self, mint_id, recipient, amount, fee_payer=None): - self.call( - "mint {} {} --owner evm_loader-keypair.json --fee-payer {} -- {}".format(mint_id, amount, fee_payer, - recipient)) - print("minting {} tokens for {}".format(amount, recipient)) - - def create_token(self, owner=None): - if owner is None: - res = self.call("create-token") - else: - res = self.call("create-token --owner {}".format(owner)) - if not res.startswith("Creating token "): - raise Exception("create token error") - else: - return res.split()[2] - - def create_token_account(self, token, owner=None, fee_payer=None): - if owner is None: - res = self.call("create-account {}".format(token)) - else: - res = self.call("create-account {} --owner {} --fee-payer {}".format(token, owner, fee_payer)) - if not res.startswith("Creating account "): - raise Exception("create account error %s" % res) - else: - return res.split()[2] - - -spl_cli = SplToken(SOLANA_URL) def create_treasury_pool_address(pool_index, evm_loader=EVM_LOADER): @@ -118,24 +68,17 @@ def create_treasury_pool_address(pool_index, evm_loader=EVM_LOADER): )[0] -def wait_confirm_transaction(http_client, tx_sig, confirmations=0): - """Confirm a transaction.""" - timeout = 30 +def wait_for_account_to_exists(http_client: Client, account: PublicKey, timeout = 30, sleep_time = 0.4): elapsed_time = 0 while elapsed_time < timeout: - print(f'Get transaction signature for {tx_sig}') - resp = http_client.get_signature_statuses([tx_sig]) - print(f'Response: {resp}') - if resp.value[0] is not None: - status = resp.value[0] - if status.confirmation_status in [TransactionConfirmationStatus.Finalized, - TransactionConfirmationStatus.Confirmed] and \ - status.confirmations >= confirmations: - return - sleep_time = 1 + resp = http_client.get_account_info(account, commitment=Confirmed) + if resp.value is not None: + return + time.sleep(sleep_time) elapsed_time += sleep_time - raise RuntimeError("could not confirm transaction: ", tx_sig) + + raise RuntimeError(f"Account {account} not exists after {timeout} seconds") def account_with_seed(base, seed, program) -> PublicKey: @@ -201,7 +144,7 @@ def call(self, arguments): def emulate(self, loader_id, sender, contract, data): cmd = ["neon-cli", - "--commitment=recent", + "--commitment=confirmed", "--url", SOLANA_URL, f"--evm_loader={loader_id}", "emulate" @@ -406,20 +349,12 @@ def get_solana_account_data(solana_client: Client, account: Union[str, PublicKey raise Exception("Wrong data length for account data {}".format(account)) return info.data -def send_transaction(client: Client, trx, acc, wait_status=Confirmed): +def send_transaction(client: Client, trx: Transaction, *signers: Keypair, wait_status=Confirmed): print("Send trx") - result = client.send_transaction(trx, acc, opts=TxOpts(skip_confirmation=True, preflight_commitment=wait_status)) - tx = result.value + result = client.send_transaction(trx, *signers, opts=TxOpts(skip_confirmation=True, preflight_commitment=wait_status)) print("Result: {}".format(result)) - wait_confirm_transaction(client, tx) - for _ in range(60): - receipt = client.confirm_transaction(tx) - if receipt.value is not None: - break - time.sleep(1) - else: - raise AssertionError(f"Can't get confirmed transaction ") - return solana_client.get_transaction(tx) + client.confirm_transaction(result.value, commitment=Confirmed) + return client.get_transaction(result.value, commitment=Confirmed) def evm_step_cost(): @@ -430,8 +365,8 @@ def evm_step_cost(): def make_new_user(evm_loader: EvmLoader) -> Caller: key = Keypair.generate() if get_solana_balance(key.public_key) == 0: - tx = solana_client.request_airdrop(key.public_key, 1000000 * 10 ** 9, commitment=Confirmed) - wait_confirm_transaction(solana_client, tx.value) + solana_client.request_airdrop(key.public_key, 1000 * 10 ** 9, commitment=Confirmed) + wait_for_account_to_exists(solana_client, key.public_key) caller_ether = eth_keys.PrivateKey(key.secret_key[:32]).public_key.to_canonical_address() caller_solana = evm_loader.ether2program(caller_ether)[0] @@ -452,38 +387,54 @@ def deposit_neon(evm_loader: EvmLoader, operator_keypair: Keypair, ether_address balance_pubkey = evm_loader.ether2balance(ether_address) contract_pubkey = PublicKey(evm_loader.ether2program(ether_address)[0]) - evm_token_authority, _auth_bump_seed = \ - PublicKey.find_program_address([bytes("Deposit", encoding='utf-8')], evm_loader.loader_id) + evm_token_authority = PublicKey.find_program_address([b"Deposit"], evm_loader.loader_id)[0] evm_pool_key = get_associated_token_address(evm_token_authority, NEON_TOKEN_MINT_ID) - signer_token_pubkey = get_associated_token_address(operator_keypair.public_key, NEON_TOKEN_MINT_ID) + token_pubkey = get_associated_token_address(operator_keypair.public_key, NEON_TOKEN_MINT_ID) + + with open("evm_loader-keypair.json", "r") as key: + secret_key = json.load(key)[:32] + mint_authority = Keypair.from_secret_key(secret_key) + trx = Transaction() trx.add( + make_CreateAssociatedTokenIdempotent( + operator_keypair.public_key, + operator_keypair.public_key, + NEON_TOKEN_MINT_ID + ), + spl.token.instructions.mint_to( + MintToParams( + spl.token.constants.TOKEN_PROGRAM_ID, + NEON_TOKEN_MINT_ID, + token_pubkey, + mint_authority.public_key, + amount + ) + ), spl.token.instructions.approve( ApproveParams( spl.token.constants.TOKEN_PROGRAM_ID, - signer_token_pubkey, + token_pubkey, balance_pubkey, operator_keypair.public_key, amount, ) - ) - ) - trx.add( + ), make_DepositV03( evm_loader.ether2bytes(ether_address), CHAIN_ID, balance_pubkey, contract_pubkey, NEON_TOKEN_MINT_ID, - signer_token_pubkey, + token_pubkey, evm_pool_key, spl.token.constants.TOKEN_PROGRAM_ID, operator_keypair.public_key, ) ) - receipt = send_transaction(solana_client, trx, operator_keypair) + receipt = send_transaction(solana_client, trx, operator_keypair, mint_authority) return receipt @@ -535,8 +486,9 @@ def write_transaction_to_holder_account( ) ) offset += len(part) + for rcpt in receipts: - wait_confirm_transaction(solana_client, rcpt.value) + solana_client.confirm_transaction(rcpt.value, commitment=Confirmed) def execute_trx_from_instruction(operator: Keypair, evm_loader: EvmLoader, treasury_address: PublicKey, treasury_buffer: bytes, @@ -548,23 +500,23 @@ def execute_trx_from_instruction(operator: Keypair, evm_loader: EvmLoader, treas treasury_buffer, instruction.rawTransaction, additional_accounts, system_program)) - return solana_client.send_transaction(trx, signer, opts=TxOpts(skip_preflight=False, skip_confirmation=False)) + return solana_client.send_transaction(trx, signer, opts=TxOpts(skip_preflight=False, skip_confirmation=False, preflight_commitment=Confirmed)) def send_transaction_step_from_instruction(operator: Keypair, evm_loader: EvmLoader, treasury, storage_account, instruction: SignedTransaction, additional_accounts, steps_count, signer: Keypair, - system_program=sp.SYS_PROGRAM_ID) -> SendTransactionResp: + system_program=sp.SYS_PROGRAM_ID, index=0) -> SendTransactionResp: trx = TransactionWithComputeBudget(operator) trx.add( make_PartialCallOrContinueFromRawEthereumTX( - instruction.rawTransaction, - operator, evm_loader, storage_account, treasury.account, treasury.buffer, steps_count, + index, steps_count, instruction.rawTransaction, + operator, evm_loader, storage_account, treasury, additional_accounts, system_program ) ) - return solana_client.send_transaction(trx, signer, opts=TxOpts(skip_preflight=False, skip_confirmation=False)) + return solana_client.send_transaction(trx, signer, opts=TxOpts(skip_preflight=False, skip_confirmation=False, preflight_commitment=Confirmed)) def execute_transaction_steps_from_instruction(operator: Keypair, evm_loader: EvmLoader, treasury, storage_account, @@ -573,26 +525,34 @@ def execute_transaction_steps_from_instruction(operator: Keypair, evm_loader: Ev signer: Keypair = None) -> SendTransactionResp: signer = operator if signer is None else signer - send_transaction_step_from_instruction(operator, evm_loader, treasury, storage_account, instruction, - additional_accounts, 1, signer) - if steps_count > 0: - steps_left = steps_count - while steps_left > 0: - send_transaction_step_from_instruction(operator, evm_loader, treasury, storage_account, instruction, - additional_accounts, EVM_STEPS, signer) - steps_left = steps_left - EVM_STEPS - return send_transaction_step_from_instruction(operator, evm_loader, treasury, storage_account, instruction, - additional_accounts, 1, signer) + index = 0 + done = False + while not done: + response = send_transaction_step_from_instruction(operator, evm_loader, treasury, storage_account, instruction, additional_accounts, EVM_STEPS, signer, index=index) + index += 1 + + receipt = solana_client.get_transaction(response.value, commitment=Confirmed) + if receipt.value.transaction.meta.err: + raise AssertionError(f"Can't deploy contract: {receipt.value.transaction.meta.err}") + for log in receipt.value.transaction.meta.log_messages: + if "exit_status" in log: + done = True + break + if "ExitError" in log: + raise AssertionError(f"EVM Return error in logs: {receipt}") + + return response def send_transaction_step_from_account(operator: Keypair, evm_loader: EvmLoader, treasury, storage_account, additional_accounts, steps_count, signer: Keypair, system_program=sp.SYS_PROGRAM_ID, - tag=0x35) -> GetTransactionResp: + tag=0x35, index=0) -> GetTransactionResp: trx = TransactionWithComputeBudget(operator) trx.add( make_ExecuteTrxFromAccountDataIterativeOrContinue( - operator, evm_loader, storage_account, treasury.account, treasury.buffer, steps_count, + index, steps_count, + operator, evm_loader, storage_account, treasury, additional_accounts, system_program, tag ) ) @@ -600,19 +560,25 @@ def send_transaction_step_from_account(operator: Keypair, evm_loader: EvmLoader, def execute_transaction_steps_from_account(operator: Keypair, evm_loader: EvmLoader, treasury, storage_account, - additional_accounts, steps_count=EVM_STEPS, - signer: Keypair = None) -> GetTransactionResp: + additional_accounts, steps_count=EVM_STEPS, signer: Keypair = None) -> GetTransactionResp: signer = operator if signer is None else signer - send_transaction_step_from_account(operator, evm_loader, treasury, storage_account, additional_accounts, 1, signer) - if steps_count > 0: - steps_left = steps_count - while steps_left > 0: - send_transaction_step_from_account(operator, evm_loader, treasury, storage_account, additional_accounts, - EVM_STEPS, signer) - steps_left = steps_left - EVM_STEPS - return send_transaction_step_from_account(operator, evm_loader, treasury, storage_account, additional_accounts, 1, - signer) + index = 0 + done = False + while not done: + receipt = send_transaction_step_from_account(operator, evm_loader, treasury, storage_account, additional_accounts, EVM_STEPS, signer, index=index) + index += 1 + + if receipt.value.transaction.meta.err: + raise AssertionError(f"Can't deploy contract: {receipt.value.transaction.meta.err}") + for log in receipt.value.transaction.meta.log_messages: + if "exit_status" in log: + done = True + break + if "ExitError" in log: + raise AssertionError(f"EVM Return error in logs: {receipt}") + + return receipt def execute_transaction_steps_from_account_no_chain_id(operator: Keypair, evm_loader: EvmLoader, treasury, storage_account, @@ -620,13 +586,19 @@ def execute_transaction_steps_from_account_no_chain_id(operator: Keypair, evm_lo signer: Keypair = None) -> GetTransactionResp: signer = operator if signer is None else signer - send_transaction_step_from_account(operator, evm_loader, treasury, storage_account, additional_accounts, 1, signer, - tag=0x36) - if steps_count > 0: - steps_left = steps_count - while steps_left > 0: - send_transaction_step_from_account(operator, evm_loader, treasury, storage_account, additional_accounts, - EVM_STEPS, signer, tag=0x36) - steps_left = steps_left - EVM_STEPS - return send_transaction_step_from_account(operator, evm_loader, treasury, storage_account, additional_accounts, 1, - signer, tag=0x36) + index = 0 + done = False + while not done: + receipt = send_transaction_step_from_account(operator, evm_loader, treasury, storage_account, additional_accounts, EVM_STEPS, signer, tag=0x36, index=index) + index += 1 + + if receipt.value.transaction.meta.err: + raise AssertionError(f"Can't deploy contract: {receipt.value.transaction.meta.err}") + for log in receipt.value.transaction.meta.log_messages: + if "exit_status" in log: + done = True + break + if "ExitError" in log: + raise AssertionError(f"EVM Return error in logs: {receipt}") + + return receipt diff --git a/tests/test_cli.py b/tests/test_cli.py index 075643575..ed60f63df 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -7,7 +7,7 @@ from solana.rpc.commitment import Confirmed from .solana_utils import neon_cli, create_treasury_pool_address -from .solana_utils import solana_client, wait_confirm_transaction, get_solana_balance, send_transaction +from .solana_utils import solana_client, get_solana_balance, send_transaction from .utils.constants import CHAIN_ID, SOLANA_URL from .utils.contract import deploy_contract from .utils.ethereum import make_eth_transaction @@ -92,7 +92,7 @@ def test_collect_treasury(evm_loader): amount = random.randint(1, 1000) trx = solana_client.request_airdrop(treasury_pool_address, amount) - wait_confirm_transaction(solana_client, trx.value) + solana_client.confirm_transaction(trx.value, commitment=Confirmed) result = neon_cli().call(command_args) balance_after = get_solana_balance(PublicKey(main_pool_address)) @@ -120,7 +120,7 @@ def test_get_storage_at(evm_loader, operator_keypair, user_account, treasury_poo assert result == expected_storage -def test_cancel_trx(evm_loader, user_account, rw_lock_contract, operator_keypair, treasury_pool): +def test_cancel_trx(evm_loader, user_account, rw_lock_contract, default_operator_keypair, treasury_pool): func_name = abi.function_signature_to_4byte_selector('unchange_storage(uint8,uint8)') data = (func_name + bytes.fromhex("%064x" % 0x01) + bytes.fromhex("%064x" % 0x01)) @@ -129,13 +129,13 @@ def test_cancel_trx(evm_loader, user_account, rw_lock_contract, operator_keypair data, user_account ) - storage_account = create_holder(operator_keypair) + storage_account = create_holder(default_operator_keypair) instruction = eth_transaction.rawTransaction - trx = TransactionWithComputeBudget(operator_keypair) + trx = TransactionWithComputeBudget(default_operator_keypair) trx.add( make_PartialCallOrContinueFromRawEthereumTX( - instruction, - operator_keypair, evm_loader, storage_account, treasury_pool.account, treasury_pool.buffer, 1, + 0, 1, instruction, + default_operator_keypair, evm_loader, storage_account, treasury_pool, [ rw_lock_contract.solana_address, user_account.balance_account_address, @@ -144,7 +144,7 @@ def test_cancel_trx(evm_loader, user_account, rw_lock_contract, operator_keypair ) solana_client = Client(SOLANA_URL) - receipt = send_transaction(solana_client, trx, operator_keypair) + receipt = send_transaction(solana_client, trx, default_operator_keypair) assert receipt.value.transaction.meta.err is None user_nonce = evm_loader.get_neon_nonce(user_account.eth_address) diff --git a/tests/test_parallel.py b/tests/test_parallel.py index ae277b695..c3dc56f46 100644 --- a/tests/test_parallel.py +++ b/tests/test_parallel.py @@ -14,7 +14,7 @@ from .utils.storage import create_holder from .utils.types import Caller, TreasuryPool -EVM_STEPS_COUNT = 0xFFFFFFFF_FFFFFFFF +EVM_STEPS_COUNT = 0xFFFFFFFF ONE_TOKEN = 10 ** 9 BIG_CONTRACT_FILENAME = "BigContract.binary" MAX_PERMITTED_DATA_INCREASE = 10240 @@ -67,7 +67,8 @@ def create_same_accounts_subtest(self, iterations: int): self.user_account.balance_account_address, self.user_account.solana_account_address], EVM_STEPS_COUNT, - self.operator_keypair) + self.operator_keypair, + index=i) assert not ParallelTransactionsTest.check_iteration_deployed(deployment_receipt) diff --git a/tests/test_transaction_step_from_account.py b/tests/test_transaction_step_from_account.py index bbc010164..a3bdf9343 100644 --- a/tests/test_transaction_step_from_account.py +++ b/tests/test_transaction_step_from_account.py @@ -524,7 +524,8 @@ def test_next_operator_can_continue_trx_after_some_time(self, rw_lock_contract, trx = TransactionWithComputeBudget(operator_keypair) trx.add( make_ExecuteTrxFromAccountDataIterativeOrContinue( - operator_keypair, evm_loader, new_holder_acc, treasury_pool.account, treasury_pool.buffer, 1, + 0, 1, + operator_keypair, evm_loader, new_holder_acc, treasury_pool, [user_account.solana_account_address, user_account.balance_account_address, rw_lock_contract.solana_address] diff --git a/tests/utils/contract.py b/tests/utils/contract.py index 1e2d7e123..631bac0fe 100644 --- a/tests/utils/contract.py +++ b/tests/utils/contract.py @@ -84,13 +84,16 @@ def deploy_contract( signed_tx = make_deployment_transaction(user, contract_path, encoded_args=encoded_args) write_transaction_to_holder_account(signed_tx, holder_acc, operator) + index = 0 contract_deployed = False while not contract_deployed: receipt = send_transaction_step_from_account(operator, evm_loader, treasury_pool, holder_acc, [contract.solana_address, contract.balance_account_address, user.balance_account_address], - step_count, operator) + step_count, operator, index=index) + index += 1 + if receipt.value.transaction.meta.err: raise AssertionError(f"Can't deploy contract: {receipt.value.transaction.meta.err}") for log in receipt.value.transaction.meta.log_messages: diff --git a/tests/utils/instructions.py b/tests/utils/instructions.py index bad066b25..d084804b3 100644 --- a/tests/utils/instructions.py +++ b/tests/utils/instructions.py @@ -5,7 +5,13 @@ from solana.publickey import PublicKey import solana.system_program as sp from solana.transaction import AccountMeta, TransactionInstruction, Transaction + +from tests.utils.types import TreasuryPool from .constants import EVM_LOADER, INCINERATOR_ADDRESS +from solana.system_program import SYS_PROGRAM_ID +from solana.sysvar import SYSVAR_RENT_PUBKEY +from spl.token.constants import ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_PROGRAM_ID +from spl.token.instructions import get_associated_token_address DEFAULT_UNITS = 1_400_000 DEFAULT_HEAP_FRAME = 256 * 1024 @@ -101,29 +107,29 @@ def make_ExecuteTrxFromInstruction( def make_ExecuteTrxFromAccountDataIterativeOrContinue( + index: int, + step_count: int, operator: Keypair, evm_loader: "EvmLoader", holder_address: PublicKey, - treasury_address: PublicKey, - treasury_buffer: bytes, - step_count: int, + treasury: TreasuryPool, additional_accounts: tp.List[PublicKey], sys_program_id=sp.SYS_PROGRAM_ID, tag=0x35): # 0x35 - TransactionStepFromAccount # 0x36 - TransactionStepFromAccountNoChainId - data = tag.to_bytes(1, "little") + treasury_buffer + step_count.to_bytes(8, byteorder="little") + data = tag.to_bytes(1, "little") + treasury.buffer + step_count.to_bytes(4, "little") + index.to_bytes(4, "little") operator_ether = eth_keys.PrivateKey(operator.secret_key[:32]).public_key.to_canonical_address() print("make_ExecuteTrxFromAccountDataIterativeOrContinue accounts") print("Holder: ", holder_address) print("Operator: ", operator.public_key) - print("Treasury: ", treasury_address) + print("Treasury: ", treasury.account) print("Operator ether: ", operator_ether.hex()) print("Operator eth solana: ", evm_loader.ether2balance(operator_ether)) accounts = [ AccountMeta(pubkey=holder_address, is_signer=False, is_writable=True), AccountMeta(pubkey=operator.public_key, is_signer=True, is_writable=True), - AccountMeta(pubkey=treasury_address, is_signer=False, is_writable=True), + AccountMeta(pubkey=treasury.account, is_signer=False, is_writable=True), AccountMeta(pubkey=PublicKey(evm_loader.ether2balance(operator_ether)), is_signer=False, is_writable=True), AccountMeta(sys_program_id, is_signer=False, is_writable=True), ] @@ -140,22 +146,22 @@ def make_ExecuteTrxFromAccountDataIterativeOrContinue( def make_PartialCallOrContinueFromRawEthereumTX( + index: int, + step_count: int, instruction: bytes, operator: Keypair, evm_loader: "EvmLoader", storage_address: PublicKey, - treasury_address: PublicKey, - treasury_buffer: bytes, - step_count: int, + treasury: TreasuryPool, additional_accounts: tp.List[PublicKey], system_program=sp.SYS_PROGRAM_ID): - data = bytes([0x34]) + treasury_buffer + step_count.to_bytes(8, byteorder="little") + instruction + data = bytes([0x34]) + treasury.buffer + step_count.to_bytes(4, "little") + index.to_bytes(4, "little") + instruction operator_ether = eth_keys.PrivateKey(operator.secret_key[:32]).public_key.to_canonical_address() accounts = [ AccountMeta(pubkey=storage_address, is_signer=False, is_writable=True), AccountMeta(pubkey=operator.public_key, is_signer=True, is_writable=True), - AccountMeta(pubkey=treasury_address, is_signer=False, is_writable=True), + AccountMeta(pubkey=treasury.account, is_signer=False, is_writable=True), AccountMeta(pubkey=evm_loader.ether2balance(operator_ether), is_signer=False, is_writable=True), AccountMeta(system_program, is_signer=False, is_writable=True), ] @@ -214,3 +220,24 @@ def make_DepositV03( ] return TransactionInstruction(program_id=PublicKey(EVM_LOADER), data=data, keys=accounts) + +def make_CreateAssociatedTokenIdempotent(payer: PublicKey, owner: PublicKey, mint: PublicKey) -> TransactionInstruction: + """Creates a transaction instruction to create an associated token account. + + Returns: + The instruction to create the associated token account. + """ + associated_token_address = get_associated_token_address(owner, mint) + return TransactionInstruction( + data=bytes([1]), + keys=[ + AccountMeta(pubkey=payer, is_signer=True, is_writable=True), + AccountMeta(pubkey=associated_token_address, is_signer=False, is_writable=True), + AccountMeta(pubkey=owner, is_signer=False, is_writable=False), + AccountMeta(pubkey=mint, is_signer=False, is_writable=False), + AccountMeta(pubkey=SYS_PROGRAM_ID, is_signer=False, is_writable=False), + AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False), + AccountMeta(pubkey=SYSVAR_RENT_PUBKEY, is_signer=False, is_writable=False), + ], + program_id=ASSOCIATED_TOKEN_PROGRAM_ID, + ) \ No newline at end of file diff --git a/tests/utils/transaction_checks.py b/tests/utils/transaction_checks.py index 5292426fa..60e2b8f9c 100644 --- a/tests/utils/transaction_checks.py +++ b/tests/utils/transaction_checks.py @@ -24,5 +24,5 @@ def check_transaction_logs_have_text(trx_hash, text): def check_holder_account_tag(storage_account, layout, expected_tag): account_data = solana_client.get_account_info(storage_account, commitment=Confirmed).value.data parsed_data = layout.parse(account_data) - assert parsed_data.tag == expected_tag, f"Account data {account_data} doesn't contain tag {expected_tag}" + assert parsed_data.tag == expected_tag, f"Account tag {account_data[0]} != expected {expected_tag}" From 6310ead4baf3cd7c058c7b89c7b894e91c82036e Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Thu, 7 Dec 2023 11:15:19 +0200 Subject: [PATCH 073/318] NDEV-2403: Decouple Rpc trait from Solana RpcClient (#233) --- evm_loader/Cargo.lock | 17 +- evm_loader/api/src/api_context.rs | 26 -- .../api/src/api_server/handlers/emulate.rs | 19 +- .../src/api_server/handlers/get_balance.rs | 16 +- .../api/src/api_server/handlers/get_config.rs | 8 +- .../src/api_server/handlers/get_contract.rs | 16 +- .../api/src/api_server/handlers/get_holder.rs | 16 +- .../src/api_server/handlers/get_storage_at.rs | 8 +- .../api/src/api_server/handlers/trace.rs | 16 +- evm_loader/api/src/api_server/state.rs | 28 +- evm_loader/api/src/main.rs | 3 - evm_loader/cli/src/main.rs | 254 ++++++++++-------- evm_loader/lib/Cargo.toml | 1 + evm_loader/lib/src/account_storage.rs | 28 +- evm_loader/lib/src/commands/cancel_trx.rs | 11 +- .../lib/src/commands/collect_treasury.rs | 55 ++-- evm_loader/lib/src/commands/emulate.rs | 8 +- evm_loader/lib/src/commands/get_balance.rs | 9 +- evm_loader/lib/src/commands/get_config.rs | 48 ++-- evm_loader/lib/src/commands/get_contract.rs | 7 +- evm_loader/lib/src/commands/get_holder.rs | 5 +- evm_loader/lib/src/commands/get_neon_elf.rs | 28 +- evm_loader/lib/src/commands/get_storage_at.rs | 7 +- .../lib/src/commands/init_environment.rs | 36 +-- evm_loader/lib/src/commands/mod.rs | 4 +- evm_loader/lib/src/commands/trace.rs | 7 +- .../lib/src/commands/transaction_executor.rs | 7 +- evm_loader/lib/src/config.rs | 16 +- evm_loader/lib/src/context.rs | 47 ---- evm_loader/lib/src/lib.rs | 2 - evm_loader/lib/src/rpc/db_call_client.rs | 173 ++---------- evm_loader/lib/src/rpc/mod.rs | 79 +----- evm_loader/lib/src/rpc/validator_client.rs | 139 +++------- evm_loader/lib/src/syscall_stubs.rs | 14 +- evm_loader/lib/src/types/tracer_ch_db.rs | 10 +- 35 files changed, 429 insertions(+), 739 deletions(-) delete mode 100644 evm_loader/api/src/api_context.rs delete mode 100644 evm_loader/lib/src/context.rs diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 072bdc8f4..34163a487 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -1735,6 +1735,18 @@ dependencies = [ "syn 2.0.28", ] +[[package]] +name = "enum_dispatch" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f33313078bb8d4d05a2733a94ac4c2d8a0df9a2b84424ebf4f33bfc224a890e" +dependencies = [ + "once_cell", + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 2.0.28", +] + [[package]] name = "env_logger" version = "0.9.3" @@ -2876,8 +2888,8 @@ dependencies = [ "num-traits", "shank", "solana-program", - "spl-associated-token-account 1.1.3", - "spl-token 3.5.0", + "spl-associated-token-account 2.2.0", + "spl-token 4.0.0", "thiserror", ] @@ -2988,6 +3000,7 @@ dependencies = [ "build-info", "build-info-build", "clickhouse", + "enum_dispatch", "ethnum", "evm-loader", "goblin 0.6.1", diff --git a/evm_loader/api/src/api_context.rs b/evm_loader/api/src/api_context.rs deleted file mode 100644 index 1d040a2d1..000000000 --- a/evm_loader/api/src/api_context.rs +++ /dev/null @@ -1,26 +0,0 @@ -use crate::NeonApiState; -use neon_lib::rpc::CallDbClient; -use neon_lib::{rpc, NeonError}; -use std::sync::Arc; - -pub async fn build_rpc_client( - state: &NeonApiState, - slot: Option, - tx_index_in_block: Option, -) -> Result, NeonError> { - if let Some(slot) = slot { - build_call_db_client(state, slot, tx_index_in_block).await - } else { - Ok(state.rpc_client.clone()) - } -} - -pub async fn build_call_db_client( - state: &NeonApiState, - slot: u64, - tx_index_in_block: Option, -) -> Result, NeonError> { - Ok(Arc::new( - CallDbClient::new(state.tracer_db.clone(), slot, tx_index_in_block).await?, - )) -} diff --git a/evm_loader/api/src/api_server/handlers/emulate.rs b/evm_loader/api/src/api_server/handlers/emulate.rs index fc5f583a3..d3483efd5 100644 --- a/evm_loader/api/src/api_server/handlers/emulate.rs +++ b/evm_loader/api/src/api_server/handlers/emulate.rs @@ -3,9 +3,7 @@ use actix_web::{http::StatusCode, post, web::Json, Responder}; use std::convert::Into; use crate::api_server::handlers::process_error; -use crate::{ - api_context, commands::emulate as EmulateCommand, types::EmulateApiRequest, NeonApiState, -}; +use crate::{commands::emulate as EmulateCommand, types::EmulateApiRequest, NeonApiState}; use super::process_result; @@ -19,19 +17,14 @@ pub async fn emulate( let slot = emulate_request.slot; let index = emulate_request.tx_index_in_block; - let rpc_client = match api_context::build_rpc_client(&state, slot, index).await { - Ok(rpc_client) => rpc_client, + let rpc = match state.build_rpc(slot, index).await { + Ok(rpc) => rpc, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; process_result( - &EmulateCommand::execute( - rpc_client.as_ref(), - state.config.evm_loader, - emulate_request.body, - None, - ) - .await - .map_err(Into::into), + &EmulateCommand::execute(&rpc, state.config.evm_loader, emulate_request.body, None) + .await + .map_err(Into::into), ) } diff --git a/evm_loader/api/src/api_server/handlers/get_balance.rs b/evm_loader/api/src/api_server/handlers/get_balance.rs index ef2574582..1c7fca2b5 100644 --- a/evm_loader/api/src/api_server/handlers/get_balance.rs +++ b/evm_loader/api/src/api_server/handlers/get_balance.rs @@ -1,6 +1,6 @@ use crate::api_server::handlers::process_error; use crate::commands::get_balance as GetBalanceCommand; -use crate::{api_context, types::GetBalanceRequest, NeonApiState}; +use crate::{types::GetBalanceRequest, NeonApiState}; use actix_request_identifier::RequestId; use actix_web::web::Json; use actix_web::{http::StatusCode, post, Responder}; @@ -15,18 +15,14 @@ pub async fn get_balance( request_id: RequestId, Json(req_params): Json, ) -> impl Responder { - let rpc_client = match api_context::build_rpc_client(&state, req_params.slot, None).await { - Ok(rpc_client) => rpc_client, + let rpc = match state.build_rpc(req_params.slot, None).await { + Ok(rpc) => rpc, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; process_result( - &GetBalanceCommand::execute( - rpc_client.as_ref(), - &state.config.evm_loader, - &req_params.account, - ) - .await - .map_err(Into::into), + &GetBalanceCommand::execute(&rpc, &state.config.evm_loader, &req_params.account) + .await + .map_err(Into::into), ) } diff --git a/evm_loader/api/src/api_server/handlers/get_config.rs b/evm_loader/api/src/api_server/handlers/get_config.rs index 34aedb8e5..ce0fdf7b3 100644 --- a/evm_loader/api/src/api_server/handlers/get_config.rs +++ b/evm_loader/api/src/api_server/handlers/get_config.rs @@ -1,5 +1,5 @@ use crate::api_server::handlers::process_error; -use crate::{api_context, NeonApiState}; +use crate::NeonApiState; use actix_request_identifier::RequestId; use actix_web::routes; use actix_web::{http::StatusCode, Responder}; @@ -14,13 +14,13 @@ use super::process_result; #[post("/config")] #[get("/config")] pub async fn get_config(state: NeonApiState, request_id: RequestId) -> impl Responder { - let rpc_client = match api_context::build_rpc_client(&state, None, None).await { - Ok(rpc_client) => rpc_client, + let rpc = match state.build_rpc(None, None).await { + Ok(rpc) => rpc, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; process_result( - &GetConfigCommand::execute(rpc_client.as_ref(), state.config.evm_loader) + &GetConfigCommand::execute(&rpc, state.config.evm_loader) .await .map_err(Into::into), ) diff --git a/evm_loader/api/src/api_server/handlers/get_contract.rs b/evm_loader/api/src/api_server/handlers/get_contract.rs index ab5294196..e8e96d686 100644 --- a/evm_loader/api/src/api_server/handlers/get_contract.rs +++ b/evm_loader/api/src/api_server/handlers/get_contract.rs @@ -1,6 +1,6 @@ use crate::api_server::handlers::process_error; use crate::commands::get_contract as GetContractCommand; -use crate::{api_context, types::GetContractRequest, NeonApiState}; +use crate::{types::GetContractRequest, NeonApiState}; use actix_request_identifier::RequestId; use actix_web::post; use actix_web::web::Json; @@ -16,18 +16,14 @@ pub async fn get_contract( request_id: RequestId, Json(req_params): Json, ) -> impl Responder { - let rpc_client = match api_context::build_rpc_client(&state, req_params.slot, None).await { - Ok(rpc_client) => rpc_client, + let rpc = match state.build_rpc(req_params.slot, None).await { + Ok(rpc) => rpc, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; process_result( - &GetContractCommand::execute( - rpc_client.as_ref(), - &state.config.evm_loader, - &req_params.contract, - ) - .await - .map_err(Into::into), + &GetContractCommand::execute(&rpc, &state.config.evm_loader, &req_params.contract) + .await + .map_err(Into::into), ) } diff --git a/evm_loader/api/src/api_server/handlers/get_holder.rs b/evm_loader/api/src/api_server/handlers/get_holder.rs index 36385b1a6..f9dc34400 100644 --- a/evm_loader/api/src/api_server/handlers/get_holder.rs +++ b/evm_loader/api/src/api_server/handlers/get_holder.rs @@ -1,6 +1,6 @@ use crate::api_server::handlers::process_error; use crate::commands::get_holder as GetHolderCommand; -use crate::{api_context, types::GetHolderRequest, NeonApiState}; +use crate::{types::GetHolderRequest, NeonApiState}; use actix_request_identifier::RequestId; use actix_web::post; use actix_web::web::Json; @@ -16,18 +16,14 @@ pub async fn get_holder_account_data( request_id: RequestId, Json(req_params): Json, ) -> impl Responder { - let rpc_client = match api_context::build_rpc_client(&state, req_params.slot, None).await { - Ok(rpc_client) => rpc_client, + let rpc = match state.build_rpc(req_params.slot, None).await { + Ok(rpc) => rpc, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; process_result( - &GetHolderCommand::execute( - rpc_client.as_ref(), - &state.config.evm_loader, - req_params.pubkey, - ) - .await - .map_err(Into::into), + &GetHolderCommand::execute(&rpc, &state.config.evm_loader, req_params.pubkey) + .await + .map_err(Into::into), ) } diff --git a/evm_loader/api/src/api_server/handlers/get_storage_at.rs b/evm_loader/api/src/api_server/handlers/get_storage_at.rs index 71440e49b..c1ed2b5d0 100644 --- a/evm_loader/api/src/api_server/handlers/get_storage_at.rs +++ b/evm_loader/api/src/api_server/handlers/get_storage_at.rs @@ -1,5 +1,5 @@ use crate::api_server::handlers::process_error; -use crate::{api_context, types::GetStorageAtRequest, NeonApiState}; +use crate::{types::GetStorageAtRequest, NeonApiState}; use actix_request_identifier::RequestId; use actix_web::post; use actix_web::web::Json; @@ -17,14 +17,14 @@ pub async fn get_storage_at( request_id: RequestId, Json(req_params): Json, ) -> impl Responder { - let rpc_client = match api_context::build_rpc_client(&state, req_params.slot, None).await { - Ok(rpc_client) => rpc_client, + let rpc = match state.build_rpc(req_params.slot, None).await { + Ok(rpc) => rpc, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; process_result( &GetStorageAtCommand::execute( - rpc_client.as_ref(), + &rpc, &state.config.evm_loader, req_params.contract, req_params.index, diff --git a/evm_loader/api/src/api_server/handlers/trace.rs b/evm_loader/api/src/api_server/handlers/trace.rs index 586811a56..d766a03b5 100644 --- a/evm_loader/api/src/api_server/handlers/trace.rs +++ b/evm_loader/api/src/api_server/handlers/trace.rs @@ -4,7 +4,7 @@ use std::convert::Into; use crate::api_server::handlers::process_error; use crate::commands::trace::trace_transaction; -use crate::{api_context, types::EmulateApiRequest, NeonApiState}; +use crate::{types::EmulateApiRequest, NeonApiState}; use super::process_result; @@ -18,18 +18,14 @@ pub async fn trace( let slot = trace_request.slot; let index = trace_request.tx_index_in_block; - let rpc_client = match api_context::build_rpc_client(&state, slot, index).await { - Ok(rpc_client) => rpc_client, + let rpc = match state.build_rpc(slot, index).await { + Ok(rpc) => rpc, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; process_result( - &trace_transaction( - rpc_client.as_ref(), - state.config.evm_loader, - trace_request.body, - ) - .await - .map_err(Into::into), + &trace_transaction(&rpc, state.config.evm_loader, trace_request.body) + .await + .map_err(Into::into), ) } diff --git a/evm_loader/api/src/api_server/state.rs b/evm_loader/api/src/api_server/state.rs index 1205a9b00..9c9f60fc3 100644 --- a/evm_loader/api/src/api_server/state.rs +++ b/evm_loader/api/src/api_server/state.rs @@ -1,24 +1,34 @@ use crate::Config; +use neon_lib::rpc::{CallDbClient, CloneRpcClient, RpcEnum}; use neon_lib::types::TracerDb; -use solana_client::nonblocking::rpc_client::RpcClient; -use std::sync::Arc; +use neon_lib::NeonError; pub struct State { pub tracer_db: TracerDb, - pub rpc_client: Arc, + pub rpc_client: CloneRpcClient, pub config: Config, } impl State { pub fn new(config: Config) -> Self { - let db_config = config.db_config.as_ref().expect("db-config not found"); Self { - tracer_db: TracerDb::new(db_config), - rpc_client: Arc::new(RpcClient::new_with_commitment( - config.json_rpc_url.clone(), - config.commitment, - )), + tracer_db: TracerDb::new(&config), + rpc_client: config.build_clone_solana_rpc_client(), config, } } + + pub async fn build_rpc( + &self, + slot: Option, + tx_index_in_block: Option, + ) -> Result { + Ok(if let Some(slot) = slot { + RpcEnum::CallDbClient( + CallDbClient::new(self.tracer_db.clone(), slot, tx_index_in_block).await?, + ) + } else { + RpcEnum::CloneRpcClient(self.rpc_client.clone()) + }) + } } diff --git a/evm_loader/api/src/main.rs b/evm_loader/api/src/main.rs index 5aebb4978..eb2f84368 100644 --- a/evm_loader/api/src/main.rs +++ b/evm_loader/api/src/main.rs @@ -1,6 +1,5 @@ #![deny(warnings)] #![deny(clippy::all, clippy::pedantic)] -mod api_context; mod api_options; mod api_server; #[allow(clippy::module_name_repetitions)] @@ -12,7 +11,6 @@ use actix_web::HttpServer; use api_server::handlers::NeonApiError; pub use neon_lib::commands; pub use neon_lib::config; -pub use neon_lib::context; pub use neon_lib::errors; pub use neon_lib::types; use tracing_appender::non_blocking::NonBlockingBuilder; @@ -31,7 +29,6 @@ use crate::api_server::handlers::get_storage_at::get_storage_at; use crate::api_server::handlers::trace::trace; use crate::build_info::get_build_info; pub use config::Config; -pub use context::Context; use tracing::info; type NeonApiResult = Result; diff --git a/evm_loader/cli/src/main.rs b/evm_loader/cli/src/main.rs index 73b12a703..4f26347b8 100644 --- a/evm_loader/cli/src/main.rs +++ b/evm_loader/cli/src/main.rs @@ -12,197 +12,208 @@ use neon_lib::{ cancel_trx, collect_treasury, emulate, get_balance, get_config, get_contract, get_holder, get_neon_elf, get_storage_at, init_environment, trace, }, - errors, rpc, types::{BalanceAddress, EmulateRequest}, + Config, }; use clap::ArgMatches; -pub use config::Config; use std::io::Read; use ethnum::U256; use log::debug; use serde_json::json; use solana_clap_utils::input_parsers::{pubkey_of, value_of}; -use solana_client::nonblocking::rpc_client::RpcClient; use tokio::time::Instant; -pub use neon_lib::context::*; -use neon_lib::rpc::CallDbClient; - use crate::build_info::get_build_info; -use crate::errors::NeonError; use evm_loader::types::Address; +use neon_lib::errors::NeonError; +use neon_lib::rpc::{CallDbClient, RpcEnum}; use neon_lib::types::TracerDb; +use solana_clap_utils::keypair::signer_from_path; +use solana_sdk::signature::Signer; type NeonCliResult = Result; -async fn run<'a>(options: &'a ArgMatches<'a>) -> NeonCliResult { - let slot: Option = options - .value_of("slot") - .map(|slot_str| slot_str.parse().expect("slot parse error")); - - let config = config::create(options)?; - - let (cmd, params) = options.subcommand(); - - let rpc_client: Box = if let Some(slot) = slot { - Box::new( - CallDbClient::new( - TracerDb::new(config.db_config.as_ref().expect("db-config not found")), - slot, - None, - ) - .await?, - ) - } else { - Box::new(RpcClient::new_with_commitment( - config.json_rpc_url.clone(), - config.commitment, - )) - }; - - let context = Context::new(&*rpc_client, &config); - - execute(cmd, params, &config, &context).await -} - -fn print_result(result: &NeonCliResult) { - let logs = { - let context = logs::CONTEXT.lock().unwrap(); - context.clone() - }; - - let result = match result { - Ok(value) => serde_json::json!({ - "result": "success", - "value": value, - "logs": logs - }), - Err(e) => serde_json::json!({ - "result": "error", - "error": e.to_string(), - "logs": logs - }), - }; - - println!("{}", serde_json::to_string_pretty(&result).unwrap()); -} - -#[tokio::main(flavor = "current_thread")] -async fn main() { - let time_start = Instant::now(); - - let options = program_options::parse(); - - logs::init(&options).expect("logs init error"); - std::panic::set_hook(Box::new(|info| { - let message = std::format!("Panic: {info}"); - print_result(&Err(NeonError::Panic(message))); - })); - - debug!("{}", get_build_info()); - - let result = run(&options).await; - - let execution_time = Instant::now().duration_since(time_start); - log::info!("execution time: {} sec", execution_time.as_secs_f64()); - print_result(&result); - if let Err(e) = result { - std::process::exit(e.error_code()); - }; -} - #[allow(clippy::too_many_lines)] -async fn execute<'a>( - cmd: &str, - params: Option<&'a ArgMatches<'a>>, - config: &'a Config, - context: &'a Context<'_>, -) -> NeonCliResult { - match (cmd, params) { +async fn run(options: &ArgMatches<'_>) -> NeonCliResult { + let config = &config::create(options)?; + + match options.subcommand() { ("emulate", Some(_)) => { + let rpc = build_rpc(options, config).await?; + let request = read_tx_from_stdin()?; - emulate::execute(context.rpc_client, config.evm_loader, request, None) + emulate::execute(&rpc, config.evm_loader, request, None) .await .map(|result| json!(result)) } ("trace", Some(_)) => { + let rpc = build_rpc(options, config).await?; + let request = read_tx_from_stdin()?; - trace::trace_transaction(context.rpc_client, config.evm_loader, request) + trace::trace_transaction(&rpc, config.evm_loader, request) .await .map(|trace| json!(trace)) } ("get-ether-account-data", Some(params)) => { + let rpc = build_rpc(options, config).await?; + let address = address_of(params, "ether").unwrap(); let chain_id = value_of(params, "chain_id").unwrap(); let account = BalanceAddress { address, chain_id }; let accounts = std::slice::from_ref(&account); - get_balance::execute(context.rpc_client, &config.evm_loader, accounts) + get_balance::execute(&rpc, &config.evm_loader, accounts) .await .map(|result| json!(result)) } ("get-contract-account-data", Some(params)) => { + let rpc = build_rpc(options, config).await?; + let account = address_of(params, "address").unwrap(); let accounts = std::slice::from_ref(&account); - get_contract::execute(context.rpc_client, &config.evm_loader, accounts) + get_contract::execute(&rpc, &config.evm_loader, accounts) .await .map(|result| json!(result)) } ("get-holder-account-data", Some(params)) => { + let rpc = build_rpc(options, config).await?; + let account = pubkey_of(params, "account").unwrap(); - get_holder::execute(context.rpc_client, &config.evm_loader, account) + get_holder::execute(&rpc, &config.evm_loader, account) .await .map(|result| json!(result)) } ("cancel-trx", Some(params)) => { + let rpc_client = config.build_solana_rpc_client(); + let signer = build_signer(config)?; + let storage_account = pubkey_of(params, "storage_account").expect("storage_account parse error"); - cancel_trx::execute( - context.rpc_client, - context.signer()?.as_ref(), - config.evm_loader, - &storage_account, - ) - .await - .map(|result| json!(result)) + cancel_trx::execute(&rpc_client, &*signer, config.evm_loader, &storage_account) + .await + .map(|result| json!(result)) } ("neon-elf-params", Some(params)) => { + let rpc = build_rpc(options, config).await?; + let program_location = params.value_of("program_location"); - get_neon_elf::execute(config, context, program_location) + get_neon_elf::execute(config, &rpc, program_location) + .await + .map(|result| json!(result)) + } + ("collect-treasury", Some(_)) => { + let rpc_client = config.build_clone_solana_rpc_client(); + let signer = build_signer(config)?; + + collect_treasury::execute(config, &rpc_client, &*signer) .await .map(|result| json!(result)) } - ("collect-treasury", Some(_)) => collect_treasury::execute(config, context) - .await - .map(|result| json!(result)), ("init-environment", Some(params)) => { + let rpc_client = config.build_clone_solana_rpc_client(); + let signer = build_signer(config)?; + let file = params.value_of("file"); let send_trx = params.is_present("send-trx"); let force = params.is_present("force"); let keys_dir = params.value_of("keys-dir"); - init_environment::execute(config, context, send_trx, force, keys_dir, file) - .await - .map(|result| json!(result)) + + init_environment::execute( + config, + &rpc_client, + &*signer, + send_trx, + force, + keys_dir, + file, + ) + .await + .map(|result| json!(result)) } ("get-storage-at", Some(params)) => { + let rpc = build_rpc(options, config).await?; + let contract_id = address_of(params, "contract_id").expect("contract_it parse error"); let index = u256_of(params, "index").expect("index parse error"); - get_storage_at::execute(context.rpc_client, &config.evm_loader, contract_id, index) + + get_storage_at::execute(&rpc, &config.evm_loader, contract_id, index) .await .map(|hash| json!(hex::encode(hash.0))) } - ("config", Some(_)) => get_config::execute(context.rpc_client, config.evm_loader) - .await - .map(|result| json!(result)), + ("config", Some(_)) => { + let rpc = build_rpc(options, config).await?; + + get_config::execute(&rpc, config.evm_loader) + .await + .map(|result| json!(result)) + } _ => unreachable!(), } } +async fn build_rpc(options: &ArgMatches<'_>, config: &Config) -> Result { + let slot: Option = options + .value_of("slot") + .map(|slot_str| slot_str.parse().expect("slot parse error")); + + Ok(if let Some(slot) = slot { + RpcEnum::CallDbClient(CallDbClient::new(TracerDb::new(config), slot, None).await?) + } else { + RpcEnum::CloneRpcClient(config.build_clone_solana_rpc_client()) + }) +} + +fn print_result(result: &NeonCliResult) { + let logs = { + let context = logs::CONTEXT.lock().unwrap(); + context.clone() + }; + + let result = match result { + Ok(value) => json!({ + "result": "success", + "value": value, + "logs": logs + }), + Err(e) => json!({ + "result": "error", + "error": e.to_string(), + "logs": logs + }), + }; + + println!("{}", serde_json::to_string_pretty(&result).unwrap()); +} + +#[tokio::main(flavor = "current_thread")] +async fn main() { + let time_start = Instant::now(); + + let options = program_options::parse(); + + logs::init(&options).expect("logs init error"); + std::panic::set_hook(Box::new(|info| { + let message = std::format!("Panic: {info}"); + print_result(&Err(NeonError::Panic(message))); + })); + + debug!("{}", get_build_info()); + + let result = run(&options).await; + + let execution_time = Instant::now().duration_since(time_start); + log::info!("execution time: {} sec", execution_time.as_secs_f64()); + print_result(&result); + if let Err(e) = result { + std::process::exit(e.error_code()); + }; +} + fn read_tx_from_stdin() -> Result { let mut stdin_buffer = String::new(); std::io::stdin().read_to_string(&mut stdin_buffer)?; @@ -225,3 +236,18 @@ fn u256_of(matches: &ArgMatches<'_>, name: &str) -> Option { U256::from_str_prefixed(value).unwrap() }) } + +/// # Errors +fn build_signer(config: &Config) -> Result, NeonError> { + let mut wallet_manager = None; + + let signer = signer_from_path( + &ArgMatches::default(), + &config.keypair_path, + "keypair", + &mut wallet_manager, + ) + .map_err(|_| NeonError::KeypairNotSpecified)?; + + Ok(signer) +} diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 5de90dcd3..f4a1d6a32 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -35,6 +35,7 @@ clickhouse = "0.11.5" tracing = "0.1" async-trait = "0.1.73" build-info = "0.0.31" +enum_dispatch = "0.3.12" [build-dependencies] build-info-build = "0.0.31" diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index 9b3694fd1..499b0f8df 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -26,6 +26,7 @@ use solana_client::client_error; use solana_sdk::{account::Account, account_info::AccountInfo, pubkey, pubkey::Pubkey}; use crate::commands::get_config::ChainInfo; +use crate::rpc::RpcEnum; use crate::tracing::{AccountOverride, AccountOverrides, BlockOverrides}; use serde_with::{serde_as, DisplayFromStr}; @@ -46,7 +47,7 @@ pub struct SolanaAccount { pub struct EmulatorAccountStorage<'rpc> { pub accounts: RefCell>, pub gas: u64, - rpc_client: &'rpc dyn Rpc, + rpc: &'rpc RpcEnum, program_id: Pubkey, chains: Vec, block_number: u64, @@ -56,7 +57,7 @@ pub struct EmulatorAccountStorage<'rpc> { impl<'rpc> EmulatorAccountStorage<'rpc> { pub async fn new( - rpc_client: &'rpc dyn Rpc, + rpc: &'rpc RpcEnum, program_id: Pubkey, chains: Option>, block_overrides: Option, @@ -65,17 +66,17 @@ impl<'rpc> EmulatorAccountStorage<'rpc> { trace!("backend::new"); let block_number = match block_overrides.as_ref().and_then(|o| o.number) { - None => rpc_client.get_slot().await?, + None => rpc.get_slot().await?, Some(number) => number, }; let block_timestamp = match block_overrides.as_ref().and_then(|o| o.time) { - None => rpc_client.get_block_time(block_number).await?, + None => rpc.get_block_time(block_number).await?, Some(time) => time, }; let chains = match chains { - None => crate::commands::get_config::read_chains(rpc_client, program_id).await?, + None => crate::commands::get_config::read_chains(rpc, program_id).await?, Some(chains) => chains, }; @@ -84,7 +85,7 @@ impl<'rpc> EmulatorAccountStorage<'rpc> { program_id, chains, gas: 0, - rpc_client, + rpc, block_number, block_timestamp, state_overrides, @@ -92,21 +93,14 @@ impl<'rpc> EmulatorAccountStorage<'rpc> { } pub async fn with_accounts( - rpc_client: &'rpc dyn Rpc, + rpc: &'rpc RpcEnum, program_id: Pubkey, accounts: &[Pubkey], chains: Option>, block_overrides: Option, state_overrides: Option, ) -> Result, NeonError> { - let storage = Self::new( - rpc_client, - program_id, - chains, - block_overrides, - state_overrides, - ) - .await?; + let storage = Self::new(rpc, program_id, chains, block_overrides, state_overrides).await?; storage.download_accounts(accounts).await?; @@ -114,7 +108,7 @@ impl<'rpc> EmulatorAccountStorage<'rpc> { } async fn download_accounts(&self, pubkeys: &[Pubkey]) -> Result<(), NeonError> { - let accounts = self.rpc_client.get_multiple_accounts(pubkeys).await?; + let accounts = self.rpc.get_multiple_accounts(pubkeys).await?; let mut cache = self.accounts.borrow_mut(); @@ -146,7 +140,7 @@ impl<'rpc> EmulatorAccountStorage<'rpc> { return Ok(account.data.clone()); } - let response = self.rpc_client.get_account(&pubkey).await?; + let response = self.rpc.get_account(&pubkey).await?; let account = response.value; self.accounts.borrow_mut().insert( diff --git a/evm_loader/lib/src/commands/cancel_trx.rs b/evm_loader/lib/src/commands/cancel_trx.rs index b7663eeec..22e288c41 100644 --- a/evm_loader/lib/src/commands/cancel_trx.rs +++ b/evm_loader/lib/src/commands/cancel_trx.rs @@ -2,6 +2,7 @@ use evm_loader::account::StateAccount; use log::info; use serde::{Deserialize, Serialize}; +use solana_client::nonblocking::rpc_client::RpcClient; use solana_sdk::{ instruction::{AccountMeta, Instruction}, pubkey::Pubkey, @@ -9,9 +10,7 @@ use solana_sdk::{ signer::Signer, }; -use crate::{ - account_storage::account_info, commands::send_transaction, rpc::Rpc, NeonError, NeonResult, -}; +use crate::{account_storage::account_info, commands::send_transaction, NeonResult}; #[derive(Debug, Serialize, Deserialize)] pub struct CancelTrxReturn { @@ -19,14 +18,12 @@ pub struct CancelTrxReturn { } pub async fn execute( - rpc_client: &dyn Rpc, + rpc_client: &RpcClient, signer: &dyn Signer, evm_loader: Pubkey, storage_account: &Pubkey, ) -> NeonResult { - let Some(mut acc) = rpc_client.get_account(storage_account).await?.value else { - return Err(NeonError::AccountNotFound(*storage_account)) - }; + let mut acc = rpc_client.get_account(storage_account).await?; let storage_info = account_info(storage_account, &mut acc); let storage = StateAccount::from_account(&evm_loader, storage_info)?; diff --git a/evm_loader/lib/src/commands/collect_treasury.rs b/evm_loader/lib/src/commands/collect_treasury.rs index 8938e15d8..2059ed187 100644 --- a/evm_loader/lib/src/commands/collect_treasury.rs +++ b/evm_loader/lib/src/commands/collect_treasury.rs @@ -1,12 +1,11 @@ -use crate::rpc::check_account_for_fee; +use crate::rpc::{check_account_for_fee, CloneRpcClient, Rpc}; use crate::{ - commands::get_neon_elf::read_elf_parameters_from_account, errors::NeonError, Config, Context, - NeonResult, + commands::get_neon_elf::read_elf_parameters_from_account, errors::NeonError, Config, NeonResult, }; use evm_loader::account::{MainTreasury, Treasury}; use log::{info, warn}; use serde::{Deserialize, Serialize}; -use solana_client::nonblocking::rpc_client::RpcClient; +use solana_sdk::signature::Signer; use solana_sdk::{ instruction::{AccountMeta, Instruction}, message::Message, @@ -14,6 +13,7 @@ use solana_sdk::{ transaction::Transaction, }; use spl_token::instruction::sync_native; +use std::ops::Deref; #[derive(Debug, Serialize, Deserialize)] pub struct CollectTreasuryReturn { @@ -21,9 +21,12 @@ pub struct CollectTreasuryReturn { pub balance: u64, } -pub async fn execute(config: &Config, context: &Context<'_>) -> NeonResult { - let neon_params = read_elf_parameters_from_account(config, context).await?; - let signer = context.signer()?; +pub async fn execute( + config: &Config, + rpc_client: &CloneRpcClient, + signer: &dyn Signer, +) -> NeonResult { + let neon_params = read_elf_parameters_from_account(config, &rpc_client.clone().into()).await?; let pool_count: u32 = neon_params .get("NEON_TREASURY_POOL_COUNT") @@ -34,23 +37,15 @@ pub async fn execute(config: &Config, context: &Context<'_>) -> NeonResult() - .expect("cast to solana_client::rpc_client::RpcClient error"); - for i in 0..pool_count { let (aux_balance_address, _) = Treasury::address(&config.evm_loader, i); - if let Some(aux_balance_account) = context - .rpc_client + if let Some(aux_balance_account) = rpc_client .get_account_with_commitment(&aux_balance_address, config.commitment) .await? .value { - let minimal_balance = context - .rpc_client + let minimal_balance = rpc_client .get_minimum_balance_for_rent_exemption(aux_balance_account.data.len()) .await?; let available_lamports = aux_balance_account.lamports.saturating_sub(minimal_balance); @@ -71,15 +66,14 @@ pub async fn execute(config: &Config, context: &Context<'_>) -> NeonResult) -> NeonResult, @@ -65,7 +65,7 @@ pub async fn execute( .and_then(|t| t.state_overrides.clone()); let mut storage = EmulatorAccountStorage::with_accounts( - rpc_client, + rpc, program_id, &config.accounts, config.chains, @@ -76,7 +76,7 @@ pub async fn execute( let step_limit = config.step_limit.unwrap_or(100000); - setup_emulator_syscall_stubs(rpc_client).await?; + setup_emulator_syscall_stubs(rpc).await?; emulate_trx(config.tx, &mut storage, step_limit, tracer).await } diff --git a/evm_loader/lib/src/commands/get_balance.rs b/evm_loader/lib/src/commands/get_balance.rs index 760018ee9..e1d0da6c5 100644 --- a/evm_loader/lib/src/commands/get_balance.rs +++ b/evm_loader/lib/src/commands/get_balance.rs @@ -6,6 +6,7 @@ use solana_sdk::{account::Account, pubkey::Pubkey}; use crate::{account_storage::account_info, rpc::Rpc, types::BalanceAddress, NeonResult}; +use crate::rpc::RpcEnum; use serde_with::{serde_as, DisplayFromStr}; use super::get_config::ChainInfo; @@ -91,14 +92,14 @@ fn is_legacy_chain_id(id: u64, chains: &[ChainInfo]) -> bool { } pub async fn execute( - rpc_client: &dyn Rpc, + rpc: &RpcEnum, program_id: &Pubkey, address: &[BalanceAddress], ) -> NeonResult> { - let chain_ids = super::get_config::read_chains(rpc_client, *program_id).await?; + let chain_ids = super::get_config::read_chains(rpc, *program_id).await?; let pubkeys: Vec<_> = address.iter().map(|a| a.find_pubkey(program_id)).collect(); - let accounts = rpc_client.get_multiple_accounts(&pubkeys).await?; + let accounts = rpc.get_multiple_accounts(&pubkeys).await?; let mut result = Vec::with_capacity(accounts.len()); for (key, account) in address.iter().zip(accounts) { @@ -106,7 +107,7 @@ pub async fn execute( read_account(program_id, key, account)? } else if is_legacy_chain_id(key.chain_id, &chain_ids) { let contract_pubkey = key.find_contract_pubkey(program_id); - if let Some(contract_account) = rpc_client.get_account(&contract_pubkey).await?.value { + if let Some(contract_account) = rpc.get_account(&contract_pubkey).await?.value { read_legacy_account(program_id, key, contract_account)? } else { GetBalanceResponse::empty(program_id, key) diff --git a/evm_loader/lib/src/commands/get_config.rs b/evm_loader/lib/src/commands/get_config.rs index 5c70e85e8..0a642cc0c 100644 --- a/evm_loader/lib/src/commands/get_config.rs +++ b/evm_loader/lib/src/commands/get_config.rs @@ -18,7 +18,9 @@ use solana_sdk::{ use crate::{rpc::Rpc, NeonError, NeonResult}; +use crate::rpc::{CallDbClient, RpcEnum, SolanaRpc}; use serde_with::{serde_as, DisplayFromStr}; +use solana_client::nonblocking::rpc_client::RpcClient; #[derive(Debug, Serialize)] pub enum Status { @@ -50,10 +52,10 @@ pub struct GetConfigResponse { static PROGRAM_TEST: OnceCell> = OnceCell::const_new(); async fn read_program_data_from_account( - rpc_client: &dyn Rpc, + rpc: &CallDbClient, program_id: Pubkey, ) -> NeonResult> { - let Some(account) = rpc_client.get_account(&program_id).await?.value else { + let Some(account) = rpc.get_account(&program_id).await?.value else { return Err(NeonError::AccountNotFound(program_id)); }; @@ -69,7 +71,7 @@ async fn read_program_data_from_account( programdata_address, }) = account.state() { - let Some(programdata_account) = rpc_client.get_account(&programdata_address).await?.value else { + let Some(programdata_account) = rpc.get_account(&programdata_address).await?.value else { return Err(NeonError::AssociatedPdaNotFound(programdata_address, program_id)); }; @@ -113,26 +115,26 @@ async fn lock_program_test( } enum ConfigSimulator<'r> { - Rpc(Pubkey, &'r dyn Rpc), + Rpc(Pubkey, &'r RpcClient), ProgramTest(MutexGuard<'static, ProgramTestContext>), } impl<'r> ConfigSimulator<'r> { - pub async fn new( - rpc_client: &'r dyn Rpc, - program_id: Pubkey, - ) -> NeonResult> { - let simulator = if rpc_client.can_simulate_transaction() { - let identity = rpc_client.get_account_with_sol().await?; - Self::Rpc(identity, rpc_client) - } else { - let program_data = read_program_data_from_account(rpc_client, program_id).await?; - let mut program_test = lock_program_test(program_id, program_data).await; - program_test.get_new_latest_blockhash().await?; - - Self::ProgramTest(program_test) + pub async fn new(rpc: &'r RpcEnum, program_id: Pubkey) -> NeonResult> { + let simulator = match rpc { + RpcEnum::CloneRpcClient(clone_rpc_client) => Self::Rpc( + clone_rpc_client.get_account_with_sol().await?, + clone_rpc_client, + ), + RpcEnum::CallDbClient(call_db_client) => { + let program_data = + read_program_data_from_account(call_db_client, program_id).await?; + let mut program_test = lock_program_test(program_id, program_data).await; + program_test.get_new_latest_blockhash().await?; + + Self::ProgramTest(program_test) + } }; - Ok(simulator) } @@ -151,7 +153,7 @@ impl<'r> ConfigSimulator<'r> { let logs = match self { ConfigSimulator::Rpc(signer, rpc) => { let result = rpc - .simulate_transaction( + .simulate_transaction_with_instructions( Some(*signer), &[Instruction::new_with_bytes(program_id, &input, vec![])], ) @@ -266,8 +268,8 @@ async fn get_properties( Ok(result) } -pub async fn execute(rpc_client: &dyn Rpc, program_id: Pubkey) -> NeonResult { - let mut simulator = ConfigSimulator::new(rpc_client, program_id).await?; +pub async fn execute(rpc: &RpcEnum, program_id: Pubkey) -> NeonResult { + let mut simulator = ConfigSimulator::new(rpc, program_id).await?; let (version, revision) = get_version(&mut simulator, program_id).await?; @@ -281,8 +283,8 @@ pub async fn execute(rpc_client: &dyn Rpc, program_id: Pubkey) -> NeonResult NeonResult> { - let mut simulator = ConfigSimulator::new(rpc_client, program_id).await?; +pub async fn read_chains(rpc: &RpcEnum, program_id: Pubkey) -> NeonResult> { + let mut simulator = ConfigSimulator::new(rpc, program_id).await?; let chains = get_chains(&mut simulator, program_id).await?; Ok(chains) diff --git a/evm_loader/lib/src/commands/get_contract.rs b/evm_loader/lib/src/commands/get_contract.rs index 4d275d634..842bebb52 100644 --- a/evm_loader/lib/src/commands/get_contract.rs +++ b/evm_loader/lib/src/commands/get_contract.rs @@ -7,6 +7,7 @@ use solana_sdk::{account::Account, pubkey::Pubkey}; use crate::{account_storage::account_info, rpc::Rpc, NeonResult}; +use crate::rpc::RpcEnum; use serde_with::{hex::Hex, serde_as, DisplayFromStr}; use super::get_config::ChainInfo; @@ -74,11 +75,11 @@ fn read_account( } pub async fn execute( - rpc_client: &dyn Rpc, + rpc: &RpcEnum, program_id: &Pubkey, accounts: &[Address], ) -> NeonResult> { - let chain_ids = super::get_config::read_chains(rpc_client, *program_id).await?; + let chain_ids = super::get_config::read_chains(rpc, *program_id).await?; let legacy_chain_id = find_legacy_chain_id(&chain_ids); let pubkeys: Vec<_> = accounts @@ -86,7 +87,7 @@ pub async fn execute( .map(|a| a.find_solana_address(program_id).0) .collect(); - let accounts = rpc_client.get_multiple_accounts(&pubkeys).await?; + let accounts = rpc.get_multiple_accounts(&pubkeys).await?; let mut result = Vec::with_capacity(accounts.len()); for (key, account) in pubkeys.into_iter().zip(accounts) { diff --git a/evm_loader/lib/src/commands/get_holder.rs b/evm_loader/lib/src/commands/get_holder.rs index fc3db7cbc..13fa2bcd1 100644 --- a/evm_loader/lib/src/commands/get_holder.rs +++ b/evm_loader/lib/src/commands/get_holder.rs @@ -12,6 +12,7 @@ use std::fmt::Display; use crate::{account_storage::account_info, rpc::Rpc, NeonResult}; +use crate::rpc::RpcEnum; use serde_with::{hex::Hex, serde_as, skip_serializing_none, DisplayFromStr}; #[derive(Debug, Default, Serialize)] @@ -140,11 +141,11 @@ pub fn read_holder(program_id: &Pubkey, info: AccountInfo) -> NeonResult NeonResult { - let response = rpc_client.get_account(&address).await?; + let response = rpc.get_account(&address).await?; let Some(mut account) = response.value else { return Ok(GetHolderResponse::empty()) }; diff --git a/evm_loader/lib/src/commands/get_neon_elf.rs b/evm_loader/lib/src/commands/get_neon_elf.rs index 882a96a98..a710656ee 100644 --- a/evm_loader/lib/src/commands/get_neon_elf.rs +++ b/evm_loader/lib/src/commands/get_neon_elf.rs @@ -7,7 +7,8 @@ use solana_sdk::{ }; use std::{collections::HashMap, convert::TryFrom, fs::File, io::Read}; -use crate::{context::Context, errors::NeonError, Config, NeonResult}; +use crate::rpc::{Rpc, RpcEnum}; +use crate::{errors::NeonError, Config, NeonResult}; pub type GetNeonElfReturn = HashMap; @@ -16,9 +17,9 @@ pub struct CachedElfParams { } impl CachedElfParams { - pub async fn new(config: &Config, context: &Context<'_>) -> Self { + pub async fn new(config: &Config, rpc: &RpcEnum) -> Self { Self { - elf_params: read_elf_parameters_from_account(config, context) + elf_params: read_elf_parameters_from_account(config, rpc) .await .expect("read elf_params error"), } @@ -143,20 +144,18 @@ pub fn get_elf_parameter(data: &[u8], elf_parameter: &str) -> Result { pub async fn read_elf_parameters_from_account( config: &Config, - context: &Context<'_>, + rpc: &RpcEnum, ) -> Result { - let (_, program_data) = - read_program_data_from_account(config, context, &config.evm_loader).await?; + let (_, program_data) = read_program_data_from_account(config, rpc, &config.evm_loader).await?; Ok(read_elf_parameters(config, &program_data)) } pub async fn read_program_data_from_account( config: &Config, - context: &Context<'_>, + rpc: &RpcEnum, evm_loader: &Pubkey, ) -> Result<(Option, Vec), NeonError> { - let account = context - .rpc_client + let account = rpc .get_account_with_commitment(evm_loader, config.commitment) .await? .value @@ -169,8 +168,7 @@ pub async fn read_program_data_from_account( programdata_address, }) = account.state() { - let programdata_account = context - .rpc_client + let programdata_account = rpc .get_account_with_commitment(&programdata_address, config.commitment) .await? .value @@ -226,19 +224,19 @@ fn read_program_params_from_file( async fn read_program_params_from_account( config: &Config, - context: &Context<'_>, + rpc: &RpcEnum, ) -> NeonResult { - read_elf_parameters_from_account(config, context).await + read_elf_parameters_from_account(config, rpc).await } pub async fn execute( config: &Config, - context: &Context<'_>, + rpc: &RpcEnum, program_location: Option<&str>, ) -> NeonResult { if let Some(program_location) = program_location { read_program_params_from_file(config, program_location) } else { - read_program_params_from_account(config, context).await + read_program_params_from_account(config, rpc).await } } diff --git a/evm_loader/lib/src/commands/get_storage_at.rs b/evm_loader/lib/src/commands/get_storage_at.rs index 83dd0cee3..feaf4dc79 100644 --- a/evm_loader/lib/src/commands/get_storage_at.rs +++ b/evm_loader/lib/src/commands/get_storage_at.rs @@ -4,18 +4,19 @@ use solana_sdk::pubkey::Pubkey; use evm_loader::{account_storage::AccountStorage, types::Address}; -use crate::{account_storage::EmulatorAccountStorage, rpc::Rpc, NeonResult}; +use crate::rpc::RpcEnum; +use crate::{account_storage::EmulatorAccountStorage, NeonResult}; #[derive(Debug, Default, Serialize, Deserialize)] pub struct GetStorageAtReturn(pub [u8; 32]); pub async fn execute( - rpc_client: &dyn Rpc, + rpc: &RpcEnum, program_id: &Pubkey, address: Address, index: U256, ) -> NeonResult { - let value = EmulatorAccountStorage::new(rpc_client, *program_id, None, None, None) + let value = EmulatorAccountStorage::new(rpc, *program_id, None, None, None) .await? .storage(address, index) .await; diff --git a/evm_loader/lib/src/commands/init_environment.rs b/evm_loader/lib/src/commands/init_environment.rs index 11bb8e6a6..fdcb02aee 100644 --- a/evm_loader/lib/src/commands/init_environment.rs +++ b/evm_loader/lib/src/commands/init_environment.rs @@ -2,8 +2,9 @@ use std::rc::Rc; use serde::{Deserialize, Serialize}; -use crate::{context::Context, NeonResult}; +use crate::NeonResult; +use crate::rpc::CloneRpcClient; use { crate::{ commands::{ @@ -103,29 +104,24 @@ fn read_keys_dir(keys_dir: &str) -> Result, NeonError> #[allow(clippy::too_many_lines)] pub async fn execute( config: &Config, - context: &Context<'_>, + client: &CloneRpcClient, + signer: &dyn Signer, send_trx: bool, force: bool, keys_dir: Option<&str>, file: Option<&str>, ) -> NeonResult { - let signer = context.signer()?; info!( "Signer: {}, send_trx: {}, force: {}", signer.pubkey(), send_trx, force ); - let second_signer: &dyn Signer = &*context.signer()?; let fee_payer: &dyn Signer = match config.fee_payer.as_ref() { Some(fee_payer) => fee_payer, - None => second_signer, + None => signer, }; - let executor = Rc::new(TransactionExecutor::new( - context.rpc_client, - fee_payer, - send_trx, - )); + let executor = Rc::new(TransactionExecutor::new(client, fee_payer, send_trx)); let keys = keys_dir.map_or(Ok(HashMap::new()), read_keys_dir)?; let program_data_address = Pubkey::find_program_address( @@ -133,8 +129,9 @@ pub async fn execute( &bpf_loader_upgradeable::id(), ) .0; + let rpc_enum = client.clone().into(); let (program_upgrade_authority, program_data) = - read_program_data_from_account(config, context, &config.evm_loader).await?; + read_program_data_from_account(config, &rpc_enum, &config.evm_loader).await?; let data = file.map_or(Ok(program_data), read_program_data)?; let program_parameters = Parameters::new(read_elf_parameters(config, &data)); @@ -154,14 +151,12 @@ pub async fn execute( //====================== Create NEON-token mint =================================================================== let executor_clone = executor.clone(); - let second_signer = context.signer()?; let create_token = move |mint: Pubkey, decimals: u8| async move { let mint_signer = keys .get(&mint) .ok_or(EnvironmentError::MissingPrivateKey(mint))?; let data_len = spl_token::state::Mint::LEN; - let lamports = context - .rpc_client + let lamports = client .get_minimum_balance_for_rent_exemption(data_len) .await?; let parameters = &[ @@ -175,7 +170,7 @@ pub async fn execute( spl_token::instruction::initialize_mint2( &spl_token::id(), &mint, - &second_signer.pubkey(), + &signer.pubkey(), None, decimals, )?, @@ -209,7 +204,7 @@ pub async fn execute( //====================== Create 'Deposit' NEON-token balance ====================================================== let (deposit_authority, _) = Pubkey::find_program_address(&[b"Deposit"], &config.evm_loader); - let chains = super::get_config::read_chains(context.rpc_client, config.evm_loader).await?; + let chains = super::get_config::read_chains(&rpc_enum, config.evm_loader).await?; for chain in chains { let pool = get_associated_token_address(&deposit_authority, &chain.token); @@ -277,7 +272,7 @@ pub async fn execute( AccountMeta::new(executor.fee_payer.pubkey(), true), ], )], - &[&*signer], + &[signer], ) .await?; Ok(Some(transaction)) @@ -288,10 +283,7 @@ pub async fn execute( //====================== Create auxiliary treasury balances ======================================================= let treasury_pool_count = program_parameters.get::("NEON_TREASURY_POOL_COUNT")?; for i in 0..treasury_pool_count { - let minimum_balance = context - .rpc_client - .get_minimum_balance_for_rent_exemption(0) - .await?; + let minimum_balance = client.get_minimum_balance_for_rent_exemption(0).await?; let aux_balance_address = Treasury::address(&config.evm_loader, i).0; let executor_clone = executor.clone(); executor @@ -326,7 +318,7 @@ pub async fn execute( .await?; } - executor.checkpoint(context.rpc_client.commitment()).await?; + executor.checkpoint(client.commitment()).await?; { let stats = executor.stats.borrow(); diff --git a/evm_loader/lib/src/commands/mod.rs b/evm_loader/lib/src/commands/mod.rs index 805071eb1..801b7b7c7 100644 --- a/evm_loader/lib/src/commands/mod.rs +++ b/evm_loader/lib/src/commands/mod.rs @@ -1,4 +1,4 @@ -use crate::rpc::Rpc; +use solana_client::nonblocking::rpc_client::RpcClient; use solana_client::{ client_error::Result as SolanaClientResult, rpc_config::RpcSendTransactionConfig, }; @@ -25,7 +25,7 @@ pub mod trace; mod transaction_executor; pub async fn send_transaction( - rpc_client: &dyn Rpc, + rpc_client: &RpcClient, signer: &dyn Signer, instructions: &[Instruction], ) -> SolanaClientResult { diff --git a/evm_loader/lib/src/commands/trace.rs b/evm_loader/lib/src/commands/trace.rs index 8dcc48d20..1496f41d9 100644 --- a/evm_loader/lib/src/commands/trace.rs +++ b/evm_loader/lib/src/commands/trace.rs @@ -3,12 +3,13 @@ use std::rc::Rc; use serde_json::Value; use solana_sdk::pubkey::Pubkey; +use crate::errors::NeonError; +use crate::rpc::RpcEnum; use crate::tracing::tracers::new_tracer; use crate::types::EmulateRequest; -use crate::{errors::NeonError, rpc::Rpc}; pub async fn trace_transaction( - rpc_client: &dyn Rpc, + rpc: &RpcEnum, program_id: Pubkey, config: EmulateRequest, ) -> Result { @@ -21,7 +22,7 @@ pub async fn trace_transaction( let tracer = new_tracer(&trace_config)?; let emulation_tracer = Some(Rc::clone(&tracer)); - let r = super::emulate::execute(rpc_client, program_id, config, emulation_tracer).await?; + let r = super::emulate::execute(rpc, program_id, config, emulation_tracer).await?; let mut traces = Rc::try_unwrap(tracer) .expect("There is must be only one reference") diff --git a/evm_loader/lib/src/commands/transaction_executor.rs b/evm_loader/lib/src/commands/transaction_executor.rs index b57ec31e5..158b89874 100644 --- a/evm_loader/lib/src/commands/transaction_executor.rs +++ b/evm_loader/lib/src/commands/transaction_executor.rs @@ -2,9 +2,10 @@ use std::cell::RefCell; use std::future::Future; use serde::{Deserialize, Serialize}; +use solana_client::nonblocking::rpc_client::RpcClient; use { - crate::{errors::NeonError, rpc}, + crate::errors::NeonError, log::{debug, error, info, warn}, solana_sdk::{ account::Account, @@ -46,7 +47,7 @@ impl Stats { } } pub struct TransactionExecutor<'a, 'b> { - pub client: &'a dyn rpc::Rpc, + pub client: &'a RpcClient, pub send_trx: bool, pub signatures: RefCell>, pub stats: RefCell, @@ -54,7 +55,7 @@ pub struct TransactionExecutor<'a, 'b> { } impl<'a, 'b> TransactionExecutor<'a, 'b> { - pub fn new(client: &'a dyn rpc::Rpc, fee_payer: &'b dyn Signer, send_trx: bool) -> Self { + pub fn new(client: &'a RpcClient, fee_payer: &'b dyn Signer, send_trx: bool) -> Self { Self { client, send_trx, diff --git a/evm_loader/lib/src/config.rs b/evm_loader/lib/src/config.rs index ab12bc955..ae1c5fa72 100644 --- a/evm_loader/lib/src/config.rs +++ b/evm_loader/lib/src/config.rs @@ -1,11 +1,13 @@ use std::{env, str::FromStr}; +use crate::rpc::CloneRpcClient; use crate::{types::ChDbConfig, NeonError}; use serde::{Deserialize, Serialize}; use solana_clap_utils::{ input_validators::normalize_to_url_if_moniker, keypair::keypair_from_path, }; use solana_cli_config::Config as SolanaConfig; +use solana_client::nonblocking::rpc_client::RpcClient; use solana_sdk::{commitment_config::CommitmentConfig, pubkey::Pubkey, signature::Keypair}; #[derive(Debug)] @@ -19,11 +21,15 @@ pub struct Config { pub keypair_path: String, } -// impl Debug for Config { -// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { -// write!(f, "evm_loader={:?}", self.evm_loader) -// } -// } +impl Config { + pub fn build_solana_rpc_client(&self) -> RpcClient { + RpcClient::new_with_commitment(self.json_rpc_url.clone(), self.commitment) + } + + pub fn build_clone_solana_rpc_client(&self) -> CloneRpcClient { + CloneRpcClient::new(self.build_solana_rpc_client()) + } +} /// # Errors pub fn create_from_api_config(api_config: &APIOptions) -> Result { diff --git a/evm_loader/lib/src/context.rs b/evm_loader/lib/src/context.rs deleted file mode 100644 index 91793531e..000000000 --- a/evm_loader/lib/src/context.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::{ - rpc::{self}, - Config, NeonError, -}; -use solana_clap_utils::keypair::signer_from_path; -use solana_sdk::signature::Signer; - -pub fn truncate_0x(in_str: &str) -> &str { - if &in_str[..2] == "0x" { - &in_str[2..] - } else { - in_str - } -} - -pub struct Context<'a> { - pub rpc_client: &'a dyn rpc::Rpc, - signer_config: &'a Config, -} - -impl<'a> Context<'a> { - pub fn signer(&self) -> Result, NeonError> { - build_signer(self.signer_config) - } - - pub fn new(rpc_client: &'a dyn rpc::Rpc, signer_config: &'a Config) -> Context<'a> { - Self { - rpc_client, - signer_config, - } - } -} - -/// # Errors -pub fn build_signer(config: &Config) -> Result, NeonError> { - let mut wallet_manager = None; - - let signer = signer_from_path( - &Default::default(), - &config.keypair_path, - "keypair", - &mut wallet_manager, - ) - .map_err(|_| NeonError::KeypairNotSpecified)?; - - Ok(signer) -} diff --git a/evm_loader/lib/src/lib.rs b/evm_loader/lib/src/lib.rs index 3cea4c495..eb80c7e78 100644 --- a/evm_loader/lib/src/lib.rs +++ b/evm_loader/lib/src/lib.rs @@ -3,7 +3,6 @@ pub mod build_info; pub mod build_info_common; pub mod commands; pub mod config; -pub mod context; pub mod errors; pub mod rpc; pub mod syscall_stubs; @@ -11,7 +10,6 @@ pub mod tracing; pub mod types; pub use config::Config; -pub use context::Context; pub use errors::NeonError; pub type NeonResult = Result; diff --git a/evm_loader/lib/src/rpc/db_call_client.rs b/evm_loader/lib/src/rpc/db_call_client.rs index 605676dd4..b16fc9944 100644 --- a/evm_loader/lib/src/rpc/db_call_client.rs +++ b/evm_loader/lib/src/rpc/db_call_client.rs @@ -5,23 +5,14 @@ use async_trait::async_trait; use solana_client::{ client_error::Result as ClientResult, client_error::{ClientError, ClientErrorKind}, - rpc_config::{RpcSendTransactionConfig, RpcTransactionConfig}, - rpc_response::{Response, RpcResponseContext, RpcResult, RpcSimulateTransactionResult}, + rpc_response::{Response, RpcResponseContext, RpcResult}, }; use solana_sdk::{ account::Account, clock::{Slot, UnixTimestamp}, commitment_config::CommitmentConfig, - hash::Hash, - instruction::Instruction, pubkey::Pubkey, - signature::Signature, - transaction::Transaction, }; -use solana_transaction_status::{ - EncodedConfirmedBlock, EncodedConfirmedTransactionWithStatusMeta, TransactionStatus, -}; -use std::any::Any; pub struct CallDbClient { tracer_db: TracerDb, @@ -49,28 +40,29 @@ impl CallDbClient { tx_index_in_block, }) } -} -#[async_trait(?Send)] -impl Rpc for CallDbClient { - fn commitment(&self) -> CommitmentConfig { - CommitmentConfig::default() + async fn get_account(&self, key: &Pubkey) -> RpcResult> { + Ok(Response { + context: RpcResponseContext { + slot: self.slot, + api_version: None, + }, + value: self.get_account_at(key).await?, + }) } - async fn confirm_transaction_with_spinner( - &self, - _signature: &Signature, - _recent_blockhash: &Hash, - _commitment_config: CommitmentConfig, - ) -> ClientResult<()> { - Err(e!( - "confirm_transaction_with_spinner() not implemented for db_call_client" - )) + async fn get_account_at(&self, key: &Pubkey) -> ClientResult> { + self.tracer_db + .get_account_at(key, self.slot, self.tx_index_in_block) + .await + .map_err(|e| e!("load account error", key, e)) } +} +#[async_trait(?Send)] +impl Rpc for CallDbClient { async fn get_account(&self, key: &Pubkey) -> RpcResult> { - self.get_account_with_commitment(key, self.commitment()) - .await + self.get_account(key).await } async fn get_account_with_commitment( @@ -78,20 +70,7 @@ impl Rpc for CallDbClient { key: &Pubkey, _: CommitmentConfig, ) -> RpcResult> { - let account = self - .tracer_db - .get_account_at(key, self.slot, self.tx_index_in_block) - .await - .map_err(|e| e!("load account error", key, e))?; - - let context = RpcResponseContext { - slot: self.slot, - api_version: None, - }; - Ok(Response { - context, - value: account, - }) + self.get_account(key).await } async fn get_multiple_accounts( @@ -100,29 +79,11 @@ impl Rpc for CallDbClient { ) -> ClientResult>> { let mut result = Vec::new(); for key in pubkeys { - let account = self - .tracer_db - .get_account_at(key, self.slot, self.tx_index_in_block) - .await - .map_err(|e| e!("load account error", key, e))?; - result.push(account); + result.push(self.get_account_at(key).await?); } Ok(result) } - async fn get_account_data(&self, key: &Pubkey) -> ClientResult> { - let response = self.get_account(key).await?; - if let Some(account) = response.value { - Ok(account.data) - } else { - Ok(Vec::new()) - } - } - - async fn get_block(&self, _slot: Slot) -> ClientResult { - Err(e!("get_block() not implemented for db_call_client")) - } - async fn get_block_time(&self, slot: Slot) -> ClientResult { self.tracer_db .get_block_time(slot) @@ -130,101 +91,7 @@ impl Rpc for CallDbClient { .map_err(|e| e!("get_block_time error", slot, e)) } - async fn get_latest_blockhash(&self) -> ClientResult { - Err(e!( - "get_latest_blockhash() not implemented for db_call_client" - )) - } - - async fn get_minimum_balance_for_rent_exemption(&self, _data_len: usize) -> ClientResult { - Err(e!( - "get_minimum_balance_for_rent_exemption() not implemented for db_call_client" - )) - } - async fn get_slot(&self) -> ClientResult { Ok(self.slot) } - - async fn get_signature_statuses( - &self, - _signatures: &[Signature], - ) -> RpcResult>> { - Err(e!( - "get_signature_statuses() not implemented for db_call_client" - )) - } - - async fn get_transaction_with_config( - &self, - _signature: &Signature, - _config: RpcTransactionConfig, - ) -> ClientResult { - Err(e!( - "get_transaction_with_config() not implemented for db_call_client" - )) - } - - async fn send_transaction(&self, _transaction: &Transaction) -> ClientResult { - Err(e!("send_transaction() not implemented for db_call_client")) - } - - async fn send_and_confirm_transaction_with_spinner( - &self, - _transaction: &Transaction, - ) -> ClientResult { - Err(e!( - "send_and_confirm_transaction_with_spinner() not implemented for db_call_client" - )) - } - - async fn send_and_confirm_transaction_with_spinner_and_commitment( - &self, - _transaction: &Transaction, - _commitment: CommitmentConfig, - ) -> ClientResult { - Err(e!("send_and_confirm_transaction_with_spinner_and_commitment() not implemented for db_call_client")) - } - - async fn send_and_confirm_transaction_with_spinner_and_config( - &self, - _transaction: &Transaction, - _commitment: CommitmentConfig, - _config: RpcSendTransactionConfig, - ) -> ClientResult { - Err(e!("send_and_confirm_transaction_with_spinner_and_config() not implemented for db_call_client")) - } - - async fn get_latest_blockhash_with_commitment( - &self, - _commitment: CommitmentConfig, - ) -> ClientResult<(Hash, u64)> { - Err(e!( - "get_latest_blockhash_with_commitment() not implemented for db_call_client" - )) - } - - fn can_simulate_transaction(&self) -> bool { - false - } - - async fn simulate_transaction( - &self, - _signer: Option, - _instructions: &[Instruction], - ) -> RpcResult { - Err(e!( - "simulate_transaction() not implemented for db_call_client" - )) - } - - async fn get_account_with_sol(&self) -> ClientResult { - Err(e!( - "get_account_with_sol() not implemented for db_call_client" - )) - } - - fn as_any(&self) -> &dyn Any { - self - } } diff --git a/evm_loader/lib/src/rpc/mod.rs b/evm_loader/lib/src/rpc/mod.rs index 8b6dd1c89..799305ce4 100644 --- a/evm_loader/lib/src/rpc/mod.rs +++ b/evm_loader/lib/src/rpc/mod.rs @@ -2,41 +2,26 @@ mod db_call_client; mod validator_client; pub use db_call_client::CallDbClient; +pub use validator_client::CloneRpcClient; +pub use validator_client::SolanaRpc; use crate::{NeonError, NeonResult}; use async_trait::async_trait; +use enum_dispatch::enum_dispatch; use solana_cli::cli::CliError; -use solana_client::{ - client_error::Result as ClientResult, - nonblocking::rpc_client::RpcClient, - rpc_config::{RpcSendTransactionConfig, RpcTransactionConfig}, - rpc_response::{RpcResult, RpcSimulateTransactionResult}, -}; +use solana_client::{client_error::Result as ClientResult, rpc_response::RpcResult}; +use solana_sdk::message::Message; use solana_sdk::native_token::lamports_to_sol; use solana_sdk::{ account::Account, clock::{Slot, UnixTimestamp}, commitment_config::CommitmentConfig, - hash::Hash, pubkey::Pubkey, - signature::Signature, - transaction::Transaction, -}; -use solana_sdk::{instruction::Instruction, message::Message}; -use solana_transaction_status::{ - EncodedConfirmedBlock, EncodedConfirmedTransactionWithStatusMeta, TransactionStatus, }; -use std::any::Any; #[async_trait(?Send)] +#[enum_dispatch] pub trait Rpc { - fn commitment(&self) -> CommitmentConfig; - async fn confirm_transaction_with_spinner( - &self, - signature: &Signature, - recent_blockhash: &Hash, - commitment_config: CommitmentConfig, - ) -> ClientResult<()>; async fn get_account(&self, key: &Pubkey) -> RpcResult>; async fn get_account_with_commitment( &self, @@ -45,53 +30,14 @@ pub trait Rpc { ) -> RpcResult>; async fn get_multiple_accounts(&self, pubkeys: &[Pubkey]) -> ClientResult>>; - async fn get_account_data(&self, key: &Pubkey) -> ClientResult>; - async fn get_block(&self, slot: Slot) -> ClientResult; async fn get_block_time(&self, slot: Slot) -> ClientResult; - async fn get_latest_blockhash(&self) -> ClientResult; - async fn get_minimum_balance_for_rent_exemption(&self, data_len: usize) -> ClientResult; async fn get_slot(&self) -> ClientResult; - async fn get_signature_statuses( - &self, - signatures: &[Signature], - ) -> RpcResult>>; - async fn get_transaction_with_config( - &self, - signature: &Signature, - config: RpcTransactionConfig, - ) -> ClientResult; - async fn send_transaction(&self, transaction: &Transaction) -> ClientResult; - async fn send_and_confirm_transaction_with_spinner( - &self, - transaction: &Transaction, - ) -> ClientResult; - async fn send_and_confirm_transaction_with_spinner_and_commitment( - &self, - transaction: &Transaction, - commitment: CommitmentConfig, - ) -> ClientResult; - async fn send_and_confirm_transaction_with_spinner_and_config( - &self, - transaction: &Transaction, - commitment: CommitmentConfig, - config: RpcSendTransactionConfig, - ) -> ClientResult; - async fn get_latest_blockhash_with_commitment( - &self, - commitment: CommitmentConfig, - ) -> ClientResult<(Hash, u64)>; - - fn can_simulate_transaction(&self) -> bool; - - async fn simulate_transaction( - &self, - signer: Option, - instructions: &[Instruction], - ) -> RpcResult; - - async fn get_account_with_sol(&self) -> ClientResult; +} - fn as_any(&self) -> &dyn Any; +#[enum_dispatch(Rpc)] +pub enum RpcEnum { + CloneRpcClient, + CallDbClient, } macro_rules! e { @@ -108,10 +54,11 @@ macro_rules! e { ))) }; } + pub(crate) use e; pub(crate) async fn check_account_for_fee( - rpc_client: &RpcClient, + rpc_client: &CloneRpcClient, account_pubkey: &Pubkey, message: &Message, ) -> NeonResult<()> { diff --git a/evm_loader/lib/src/rpc/validator_client.rs b/evm_loader/lib/src/rpc/validator_client.rs index 1a5be4b69..9e75de53c 100644 --- a/evm_loader/lib/src/rpc/validator_client.rs +++ b/evm_loader/lib/src/rpc/validator_client.rs @@ -3,45 +3,43 @@ use async_trait::async_trait; use solana_client::{ client_error::Result as ClientResult, nonblocking::rpc_client::RpcClient, - rpc_config::{ - RpcLargestAccountsConfig, RpcSendTransactionConfig, RpcSimulateTransactionConfig, - RpcTransactionConfig, - }, + rpc_config::{RpcLargestAccountsConfig, RpcSimulateTransactionConfig}, rpc_response::{RpcResult, RpcSimulateTransactionResult}, }; use solana_sdk::{ account::Account, clock::{Slot, UnixTimestamp}, commitment_config::CommitmentConfig, - hash::Hash, instruction::Instruction, pubkey::Pubkey, - signature::Signature, transaction::Transaction, }; -use solana_transaction_status::{ - EncodedConfirmedBlock, EncodedConfirmedTransactionWithStatusMeta, TransactionStatus, -}; -use std::{any::Any, str::FromStr}; +use std::ops::Deref; +use std::str::FromStr; +use std::sync::Arc; -#[async_trait(?Send)] -impl Rpc for RpcClient { - fn commitment(&self) -> CommitmentConfig { - self.commitment() +#[derive(Clone)] +pub struct CloneRpcClient(Arc); + +impl CloneRpcClient { + pub fn new(rpc_client: RpcClient) -> Self { + Self(Arc::new(rpc_client)) } +} - async fn confirm_transaction_with_spinner( - &self, - signature: &Signature, - recent_blockhash: &Hash, - commitment_config: CommitmentConfig, - ) -> ClientResult<()> { - self.confirm_transaction_with_spinner(signature, recent_blockhash, commitment_config) - .await +impl Deref for CloneRpcClient { + type Target = RpcClient; + + fn deref(&self) -> &Self::Target { + &self.0 } +} +#[async_trait(?Send)] +impl Rpc for CloneRpcClient { async fn get_account(&self, key: &Pubkey) -> RpcResult> { - self.get_account_with_commitment(key, self.commitment()) + self.0 + .get_account_with_commitment(key, self.commitment()) .await } @@ -50,7 +48,7 @@ impl Rpc for RpcClient { key: &Pubkey, commitment: CommitmentConfig, ) -> RpcResult> { - self.get_account_with_commitment(key, commitment).await + self.0.get_account_with_commitment(key, commitment).await } async fn get_multiple_accounts( @@ -59,95 +57,36 @@ impl Rpc for RpcClient { ) -> ClientResult>> { let mut result: Vec> = Vec::new(); for chunk in pubkeys.chunks(100) { - let mut accounts = self.get_multiple_accounts(chunk).await?; + let mut accounts = self.0.get_multiple_accounts(chunk).await?; result.append(&mut accounts); } Ok(result) } - async fn get_account_data(&self, key: &Pubkey) -> ClientResult> { - Ok(self.get_account(key).await?.data) - } - - async fn get_block(&self, slot: Slot) -> ClientResult { - self.get_block(slot).await - } - async fn get_block_time(&self, slot: Slot) -> ClientResult { - self.get_block_time(slot).await - } - - async fn get_latest_blockhash(&self) -> ClientResult { - self.get_latest_blockhash().await - } - - async fn get_minimum_balance_for_rent_exemption(&self, data_len: usize) -> ClientResult { - self.get_minimum_balance_for_rent_exemption(data_len).await + self.0.get_block_time(slot).await } async fn get_slot(&self) -> ClientResult { - self.get_slot().await - } - - async fn get_signature_statuses( - &self, - signatures: &[Signature], - ) -> RpcResult>> { - self.get_signature_statuses(signatures).await - } - - async fn get_transaction_with_config( - &self, - signature: &Signature, - config: RpcTransactionConfig, - ) -> ClientResult { - self.get_transaction_with_config(signature, config).await - } - - async fn send_transaction(&self, transaction: &Transaction) -> ClientResult { - self.send_transaction(transaction).await - } - - async fn send_and_confirm_transaction_with_spinner( - &self, - transaction: &Transaction, - ) -> ClientResult { - self.send_and_confirm_transaction_with_spinner(transaction) - .await - } - - async fn send_and_confirm_transaction_with_spinner_and_commitment( - &self, - transaction: &Transaction, - commitment: CommitmentConfig, - ) -> ClientResult { - self.send_and_confirm_transaction_with_spinner_and_commitment(transaction, commitment) - .await - } - - async fn send_and_confirm_transaction_with_spinner_and_config( - &self, - transaction: &Transaction, - commitment: CommitmentConfig, - config: RpcSendTransactionConfig, - ) -> ClientResult { - self.send_and_confirm_transaction_with_spinner_and_config(transaction, commitment, config) - .await + self.0.get_slot().await } +} - async fn get_latest_blockhash_with_commitment( +#[async_trait(?Send)] +pub trait SolanaRpc { + async fn simulate_transaction_with_instructions( &self, - commitment: CommitmentConfig, - ) -> ClientResult<(Hash, u64)> { - self.get_latest_blockhash_with_commitment(commitment).await - } + signer: Option, + instructions: &[Instruction], + ) -> RpcResult; - fn can_simulate_transaction(&self) -> bool { - true - } + async fn get_account_with_sol(&self) -> ClientResult; +} - async fn simulate_transaction( +#[async_trait(?Send)] +impl SolanaRpc for RpcClient { + async fn simulate_transaction_with_instructions( &self, signer: Option, instructions: &[Instruction], @@ -182,8 +121,4 @@ impl Rpc for RpcClient { let pubkey = Pubkey::from_str(&r.value[0].address).unwrap(); Ok(pubkey) } - - fn as_any(&self) -> &dyn Any { - self - } } diff --git a/evm_loader/lib/src/syscall_stubs.rs b/evm_loader/lib/src/syscall_stubs.rs index 37aa81852..d2608edd7 100644 --- a/evm_loader/lib/src/syscall_stubs.rs +++ b/evm_loader/lib/src/syscall_stubs.rs @@ -1,6 +1,7 @@ use log::info; use solana_sdk::{program_error::ProgramError, program_stubs::SyscallStubs, sysvar::rent::Rent}; +use crate::rpc::RpcEnum; use crate::{errors::NeonError, rpc::Rpc}; pub struct DefaultStubs; @@ -12,9 +13,14 @@ pub struct EmulatorStubs { } impl EmulatorStubs { - pub async fn new(rpc_client: &dyn Rpc) -> Result, NeonError> { + pub async fn new(rpc: &RpcEnum) -> Result, NeonError> { let rent_pubkey = solana_sdk::sysvar::rent::id(); - let data = rpc_client.get_account_data(&rent_pubkey).await?; + let data = rpc + .get_account(&rent_pubkey) + .await? + .value + .map(|a| a.data) + .unwrap_or_default(); let rent = bincode::deserialize(&data).map_err(|_| ProgramError::InvalidArgument)?; Ok(Box::new(Self { rent })) @@ -51,8 +57,8 @@ impl SyscallStubs for EmulatorStubs { } } -pub async fn setup_emulator_syscall_stubs(rpc_client: &dyn Rpc) -> Result<(), NeonError> { - let syscall_stubs = EmulatorStubs::new(rpc_client).await?; +pub async fn setup_emulator_syscall_stubs(rpc: &RpcEnum) -> Result<(), NeonError> { + let syscall_stubs = EmulatorStubs::new(rpc).await?; solana_sdk::program_stubs::set_syscall_stubs(syscall_stubs); Ok(()) diff --git a/evm_loader/lib/src/types/tracer_ch_db.rs b/evm_loader/lib/src/types/tracer_ch_db.rs index f9140fc41..f2ee5f454 100644 --- a/evm_loader/lib/src/types/tracer_ch_db.rs +++ b/evm_loader/lib/src/types/tracer_ch_db.rs @@ -1,12 +1,10 @@ use crate::{ commands::get_neon_elf::get_elf_parameter, types::tracer_ch_common::{AccountRow, ChError, RevisionRow, SlotParent, ROOT_BLOCK_DELAY}, + Config, }; -use super::{ - tracer_ch_common::{ChResult, EthSyncStatus, EthSyncing, RevisionMap, SlotParentRooted}, - ChDbConfig, -}; +use super::tracer_ch_common::{ChResult, EthSyncStatus, EthSyncing, RevisionMap, SlotParentRooted}; use clickhouse::Client; use log::{debug, error, info}; @@ -30,7 +28,9 @@ pub struct ClickHouseDb { } impl ClickHouseDb { - pub fn new(config: &ChDbConfig) -> Self { + pub fn new(config: &Config) -> Self { + let config = config.db_config.as_ref().expect("db-config not found"); + let url_id = rand::thread_rng().gen_range(0..config.clickhouse_url.len()); let url = config.clickhouse_url.get(url_id).unwrap(); From 2c0a080c02b27195b741fdfb171c6417ea34f6b2 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Thu, 7 Dec 2023 13:48:27 +0200 Subject: [PATCH 074/318] NDEV-2374: Fixes for tracer-api multiple tokens support (#242) * NDEV-2374: Use StructLoggerResult and fix failed field logic * NDEV-2374: Enable RUST_LOG env var log filtering * NDEV-2374: Slimmer tracing spans * NDEV-2374: Decouple ClickHouseDb::new() from Config --- .../api/src/api_server/handlers/emulate.rs | 5 ++++- .../src/api_server/handlers/get_balance.rs | 11 +++++++---- .../api/src/api_server/handlers/get_config.rs | 2 +- .../src/api_server/handlers/get_contract.rs | 19 +++++++++++++------ .../api/src/api_server/handlers/get_holder.rs | 11 +++++++---- .../src/api_server/handlers/get_storage_at.rs | 13 ++++++++----- .../api/src/api_server/handlers/trace.rs | 5 ++++- evm_loader/api/src/api_server/state.rs | 2 +- evm_loader/api/src/main.rs | 6 +++++- evm_loader/cli/src/main.rs | 9 ++++++++- .../lib/src/tracing/tracers/struct_logger.rs | 18 ++++++++---------- evm_loader/lib/src/types/tracer_ch_db.rs | 6 ++---- 12 files changed, 68 insertions(+), 39 deletions(-) diff --git a/evm_loader/api/src/api_server/handlers/emulate.rs b/evm_loader/api/src/api_server/handlers/emulate.rs index d3483efd5..6d5015e15 100644 --- a/evm_loader/api/src/api_server/handlers/emulate.rs +++ b/evm_loader/api/src/api_server/handlers/emulate.rs @@ -1,19 +1,22 @@ use actix_request_identifier::RequestId; use actix_web::{http::StatusCode, post, web::Json, Responder}; use std::convert::Into; +use tracing::info; use crate::api_server::handlers::process_error; use crate::{commands::emulate as EmulateCommand, types::EmulateApiRequest, NeonApiState}; use super::process_result; -#[tracing::instrument(skip(state, request_id), fields(id = request_id.as_str()))] +#[tracing::instrument(skip_all, fields(id = request_id.as_str()))] #[post("/emulate")] pub async fn emulate( state: NeonApiState, request_id: RequestId, Json(emulate_request): Json, ) -> impl Responder { + info!("emulate_request={:?}", emulate_request); + let slot = emulate_request.slot; let index = emulate_request.tx_index_in_block; diff --git a/evm_loader/api/src/api_server/handlers/get_balance.rs b/evm_loader/api/src/api_server/handlers/get_balance.rs index 1c7fca2b5..d09a77430 100644 --- a/evm_loader/api/src/api_server/handlers/get_balance.rs +++ b/evm_loader/api/src/api_server/handlers/get_balance.rs @@ -5,23 +5,26 @@ use actix_request_identifier::RequestId; use actix_web::web::Json; use actix_web::{http::StatusCode, post, Responder}; use std::convert::Into; +use tracing::log::info; use super::process_result; -#[tracing::instrument(skip(state, request_id), fields(id = request_id.as_str()))] +#[tracing::instrument(skip_all, fields(id = request_id.as_str()))] #[post("/balance")] pub async fn get_balance( state: NeonApiState, request_id: RequestId, - Json(req_params): Json, + Json(get_balance_request): Json, ) -> impl Responder { - let rpc = match state.build_rpc(req_params.slot, None).await { + info!("get_balance_request={:?}", get_balance_request); + + let rpc = match state.build_rpc(get_balance_request.slot, None).await { Ok(rpc) => rpc, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; process_result( - &GetBalanceCommand::execute(&rpc, &state.config.evm_loader, &req_params.account) + &GetBalanceCommand::execute(&rpc, &state.config.evm_loader, &get_balance_request.account) .await .map_err(Into::into), ) diff --git a/evm_loader/api/src/api_server/handlers/get_config.rs b/evm_loader/api/src/api_server/handlers/get_config.rs index ce0fdf7b3..a0d7f6e90 100644 --- a/evm_loader/api/src/api_server/handlers/get_config.rs +++ b/evm_loader/api/src/api_server/handlers/get_config.rs @@ -9,7 +9,7 @@ use crate::commands::get_config as GetConfigCommand; use super::process_result; -#[tracing::instrument(skip(state, request_id), fields(id = request_id.as_str()))] +#[tracing::instrument(skip_all, fields(id = request_id.as_str()))] #[routes] #[post("/config")] #[get("/config")] diff --git a/evm_loader/api/src/api_server/handlers/get_contract.rs b/evm_loader/api/src/api_server/handlers/get_contract.rs index e8e96d686..217831e12 100644 --- a/evm_loader/api/src/api_server/handlers/get_contract.rs +++ b/evm_loader/api/src/api_server/handlers/get_contract.rs @@ -6,24 +6,31 @@ use actix_web::post; use actix_web::web::Json; use actix_web::{http::StatusCode, Responder}; use std::convert::Into; +use tracing::info; use super::process_result; -#[tracing::instrument(skip(state, request_id), fields(id = request_id.as_str()))] +#[tracing::instrument(skip_all, fields(id = request_id.as_str()))] #[post("/contract")] pub async fn get_contract( state: NeonApiState, request_id: RequestId, - Json(req_params): Json, + Json(get_contract_request): Json, ) -> impl Responder { - let rpc = match state.build_rpc(req_params.slot, None).await { + info!("get_contract_request={:?}", get_contract_request); + + let rpc = match state.build_rpc(get_contract_request.slot, None).await { Ok(rpc) => rpc, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; process_result( - &GetContractCommand::execute(&rpc, &state.config.evm_loader, &req_params.contract) - .await - .map_err(Into::into), + &GetContractCommand::execute( + &rpc, + &state.config.evm_loader, + &get_contract_request.contract, + ) + .await + .map_err(Into::into), ) } diff --git a/evm_loader/api/src/api_server/handlers/get_holder.rs b/evm_loader/api/src/api_server/handlers/get_holder.rs index f9dc34400..663868b90 100644 --- a/evm_loader/api/src/api_server/handlers/get_holder.rs +++ b/evm_loader/api/src/api_server/handlers/get_holder.rs @@ -6,23 +6,26 @@ use actix_web::post; use actix_web::web::Json; use actix_web::{http::StatusCode, Responder}; use std::convert::Into; +use tracing::info; use super::process_result; -#[tracing::instrument(skip(state, request_id), fields(id = request_id.as_str()))] +#[tracing::instrument(skip_all, fields(id = request_id.as_str()))] #[post("/holder")] pub async fn get_holder_account_data( state: NeonApiState, request_id: RequestId, - Json(req_params): Json, + Json(get_holder_request): Json, ) -> impl Responder { - let rpc = match state.build_rpc(req_params.slot, None).await { + info!("get_holder_request={:?}", get_holder_request); + + let rpc = match state.build_rpc(get_holder_request.slot, None).await { Ok(rpc) => rpc, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; process_result( - &GetHolderCommand::execute(&rpc, &state.config.evm_loader, req_params.pubkey) + &GetHolderCommand::execute(&rpc, &state.config.evm_loader, get_holder_request.pubkey) .await .map_err(Into::into), ) diff --git a/evm_loader/api/src/api_server/handlers/get_storage_at.rs b/evm_loader/api/src/api_server/handlers/get_storage_at.rs index c1ed2b5d0..ba673e96e 100644 --- a/evm_loader/api/src/api_server/handlers/get_storage_at.rs +++ b/evm_loader/api/src/api_server/handlers/get_storage_at.rs @@ -5,19 +5,22 @@ use actix_web::post; use actix_web::web::Json; use actix_web::{http::StatusCode, Responder}; use std::convert::Into; +use tracing::info; use crate::commands::get_storage_at as GetStorageAtCommand; use super::process_result; -#[tracing::instrument(skip(state, request_id), fields(id = request_id.as_str()))] +#[tracing::instrument(skip_all, fields(id = request_id.as_str()))] #[post("/storage")] pub async fn get_storage_at( state: NeonApiState, request_id: RequestId, - Json(req_params): Json, + Json(get_storage_at_request): Json, ) -> impl Responder { - let rpc = match state.build_rpc(req_params.slot, None).await { + info!("get_storage_at_request={:?}", get_storage_at_request); + + let rpc = match state.build_rpc(get_storage_at_request.slot, None).await { Ok(rpc) => rpc, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; @@ -26,8 +29,8 @@ pub async fn get_storage_at( &GetStorageAtCommand::execute( &rpc, &state.config.evm_loader, - req_params.contract, - req_params.index, + get_storage_at_request.contract, + get_storage_at_request.index, ) .await .map_err(Into::into), diff --git a/evm_loader/api/src/api_server/handlers/trace.rs b/evm_loader/api/src/api_server/handlers/trace.rs index d766a03b5..c2cc84ec5 100644 --- a/evm_loader/api/src/api_server/handlers/trace.rs +++ b/evm_loader/api/src/api_server/handlers/trace.rs @@ -1,6 +1,7 @@ use actix_request_identifier::RequestId; use actix_web::{http::StatusCode, post, web::Json, Responder}; use std::convert::Into; +use tracing::info; use crate::api_server::handlers::process_error; use crate::commands::trace::trace_transaction; @@ -8,13 +9,15 @@ use crate::{types::EmulateApiRequest, NeonApiState}; use super::process_result; -#[tracing::instrument(skip(state, request_id), fields(id = request_id.as_str()))] +#[tracing::instrument(skip_all, fields(id = request_id.as_str()))] #[post("/trace")] pub async fn trace( state: NeonApiState, request_id: RequestId, Json(trace_request): Json, ) -> impl Responder { + info!("trace_request={:?}", trace_request); + let slot = trace_request.slot; let index = trace_request.tx_index_in_block; diff --git a/evm_loader/api/src/api_server/state.rs b/evm_loader/api/src/api_server/state.rs index 9c9f60fc3..efd5ab362 100644 --- a/evm_loader/api/src/api_server/state.rs +++ b/evm_loader/api/src/api_server/state.rs @@ -12,7 +12,7 @@ pub struct State { impl State { pub fn new(config: Config) -> Self { Self { - tracer_db: TracerDb::new(&config), + tracer_db: TracerDb::new(config.db_config.as_ref().expect("db-config not found")), rpc_client: config.build_clone_solana_rpc_client(), config, } diff --git a/evm_loader/api/src/main.rs b/evm_loader/api/src/main.rs index eb2f84368..682058be9 100644 --- a/evm_loader/api/src/main.rs +++ b/evm_loader/api/src/main.rs @@ -30,6 +30,7 @@ use crate::api_server::handlers::trace::trace; use crate::build_info::get_build_info; pub use config::Config; use tracing::info; +use tracing_subscriber::EnvFilter; type NeonApiResult = Result; type NeonApiState = Data; @@ -43,7 +44,10 @@ async fn main() -> NeonApiResult<()> { .lossy(false) .finish(std::io::stdout()); - tracing_subscriber::fmt().with_writer(non_blocking).init(); + tracing_subscriber::fmt() + .with_env_filter(EnvFilter::from_default_env()) + .with_writer(non_blocking) + .init(); info!("{}", get_build_info()); diff --git a/evm_loader/cli/src/main.rs b/evm_loader/cli/src/main.rs index 4f26347b8..edcab4691 100644 --- a/evm_loader/cli/src/main.rs +++ b/evm_loader/cli/src/main.rs @@ -162,7 +162,14 @@ async fn build_rpc(options: &ArgMatches<'_>, config: &Config) -> Result) -> Value { let exit_status = self.exit_status.expect("Emulation is not completed"); - json!({ - "struct_logs": self.logs, - "failed": exit_status + let result = StructLoggerResult { + gas: 0, + failed: !exit_status .is_succeed() .expect("Emulation is not completed"), - "return_value": hex::encode( - exit_status - .into_result() - .unwrap_or_default(), - ) - }) + return_value: hex::encode(exit_status.into_result().unwrap_or_default()), + struct_logs: self.logs, + }; + serde_json::to_value(result).expect("serialization should not fail") } } diff --git a/evm_loader/lib/src/types/tracer_ch_db.rs b/evm_loader/lib/src/types/tracer_ch_db.rs index f2ee5f454..f8ab57eee 100644 --- a/evm_loader/lib/src/types/tracer_ch_db.rs +++ b/evm_loader/lib/src/types/tracer_ch_db.rs @@ -1,11 +1,11 @@ use crate::{ commands::get_neon_elf::get_elf_parameter, types::tracer_ch_common::{AccountRow, ChError, RevisionRow, SlotParent, ROOT_BLOCK_DELAY}, - Config, }; use super::tracer_ch_common::{ChResult, EthSyncStatus, EthSyncing, RevisionMap, SlotParentRooted}; +use crate::types::ChDbConfig; use clickhouse::Client; use log::{debug, error, info}; use rand::Rng; @@ -28,9 +28,7 @@ pub struct ClickHouseDb { } impl ClickHouseDb { - pub fn new(config: &Config) -> Self { - let config = config.db_config.as_ref().expect("db-config not found"); - + pub fn new(config: &ChDbConfig) -> Self { let url_id = rand::thread_rng().gen_range(0..config.clickhouse_url.len()); let url = config.clickhouse_url.get(url_id).unwrap(); From 2557607fbc2b66ab05e6188a6dd37547417a27d2 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Mon, 11 Dec 2023 16:40:36 +0200 Subject: [PATCH 075/318] NDEV-2391: Update Solana to v1.16.23 (#244) --- .github/workflows/deploy.py | 4 +- evm_loader/Cargo.lock | 199 +++++++++++++++++----------------- evm_loader/api/Cargo.toml | 4 +- evm_loader/cli/Cargo.toml | 8 +- evm_loader/lib/Cargo.toml | 14 +-- evm_loader/program/Cargo.toml | 2 +- 6 files changed, 117 insertions(+), 114 deletions(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index 63d8d1582..b619675be 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -31,8 +31,8 @@ DOCKER_PASSWORD = os.environ.get("DHUBP") IMAGE_NAME = os.environ.get("IMAGE_NAME") RUN_LINK_REPO = os.environ.get("RUN_LINK_REPO") -SOLANA_NODE_VERSION = 'v1.16.18' -SOLANA_BPF_VERSION = 'v1.16.18' +SOLANA_NODE_VERSION = 'v1.16.23' +SOLANA_BPF_VERSION = 'v1.16.23' VERSION_BRANCH_TEMPLATE = r"[vt]{1}\d{1,2}\.\d{1,2}\.x.*" docker_client = docker.APIClient() diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 34163a487..54eba6087 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -4561,9 +4561,9 @@ dependencies = [ [[package]] name = "solana-account-decoder" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83da6908b4865a9680c4fcb5e77d319467fdc5ab96a6ccc8361e7110ebcd206e" +checksum = "815b7eeb8cfc0cc27c3500658845bc0adbfb51a9212814af522f4912e1bdab2e" dependencies = [ "Inflector", "base64 0.21.4", @@ -4586,9 +4586,9 @@ dependencies = [ [[package]] name = "solana-address-lookup-table-program" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9102429e980b8e58f05e39a2aceb799fc1fd7b81e440bc70322854e0debb21dc" +checksum = "9137f2199f70e082f15f91076f31fa6e67d98d40168de759feab12c6b60542a8" dependencies = [ "bincode", "bytemuck", @@ -4607,9 +4607,9 @@ dependencies = [ [[package]] name = "solana-banks-client" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f375ffcef8cd5ee12a2324a2e3887c99c54c50f3b9f2bb7a43b23ba13f77fd" +checksum = "785bca4464357f3d7aad38b3f57b1dcec5fc47f7eb3e0c1ffba907ce15aae66c" dependencies = [ "borsh 0.10.3", "futures", @@ -4624,9 +4624,9 @@ dependencies = [ [[package]] name = "solana-banks-interface" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a07ac3b05f89f26f7ff41541f82a53a3252f60f2313bd608da7b59c14fdbc3c2" +checksum = "cb13f6fff944f56df1c5b4bb708676efb856991bc368c969c436cc444e6f5e83" dependencies = [ "serde", "solana-sdk", @@ -4635,9 +4635,9 @@ dependencies = [ [[package]] name = "solana-banks-server" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13027d9e0bedf46b921783b7b99ff4c6be6f202546b534ee1132c6e737fe2d78" +checksum = "893926dda1a8d1594b55b753298df54fb9ed9ed1e802cac69ad3a225b7cdc63e" dependencies = [ "bincode", "crossbeam-channel", @@ -4654,9 +4654,9 @@ dependencies = [ [[package]] name = "solana-bpf-loader-program" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "009b84c1ac3f6b9cb53a8f133c43efeaa4a6e8e46f9ddfa616f9d1f04c551a76" +checksum = "eb0ed3691420f8ca6c7d58eb1335ecb0b73b1b6188039b7b631bcd0253b24377" dependencies = [ "bincode", "byteorder", @@ -4673,9 +4673,9 @@ dependencies = [ [[package]] name = "solana-bucket-map" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d0f77fbc9836e4f87ebf9b92cc5083172bd7eadf050a5255b3276be925f6347" +checksum = "33b64e2a282391cffdd2985971abf571922fd58db5f2743014f8a0428f719af2" dependencies = [ "bv", "log", @@ -4690,9 +4690,9 @@ dependencies = [ [[package]] name = "solana-clap-utils" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe15843171a435eed014e7180f62c0d5e7e8178f7eaf4da0077ea21354506e2a" +checksum = "6a99a1aa397ec62a9b10f2f072fb95d78c6f4303bbca11d6af5f3f198e3d62e8" dependencies = [ "chrono", "clap 2.34.0", @@ -4708,9 +4708,9 @@ dependencies = [ [[package]] name = "solana-cli" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15d042a7d26b5c0152dbb2ab3dbbbf62ea13e238e3344fcd7d3790a4f6abd04f" +checksum = "789d04c0c7ca0e7a023153416ddda71fc506077b976d2c262990a99a703e4db7" dependencies = [ "bincode", "bs58", @@ -4759,9 +4759,9 @@ dependencies = [ [[package]] name = "solana-cli-config" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6430afcc4444bd3b7b16b9314f0ae533344d0cd9bbbd160fb47cb45f9689a801" +checksum = "864dce71e749d7a523eca56f8ee22c35fe8dae4c182c50a4a9e7acd49313ac48" dependencies = [ "dirs-next", "lazy_static", @@ -4775,9 +4775,9 @@ dependencies = [ [[package]] name = "solana-cli-output" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88e1902f40e61a873317c3f296e56333bb52258ca717813990eac1ae8ba8670c" +checksum = "2d6338b80376eb99f4dbffed10a5f2efea2894704106f1a9c09891fab924770b" dependencies = [ "Inflector", "base64 0.21.4", @@ -4802,9 +4802,9 @@ dependencies = [ [[package]] name = "solana-client" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38917c4655a42881fd2998c5c7626fa4cee9f95d5877592b347b213782782145" +checksum = "8dd1d1b50f6937ec5b7b05faa171956dc052ad593d058de5046e325cc0ec4c23" dependencies = [ "async-trait", "bincode", @@ -4835,9 +4835,9 @@ dependencies = [ [[package]] name = "solana-compute-budget-program" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14bddd710a43491be07ac493703617290e8781a9bd92fc33fcc9a8e4345928dd" +checksum = "674cbca707a6a38dc860cef40b988debb24e0347a04cd123bd2b05cb6f75eed4" dependencies = [ "solana-program-runtime", "solana-sdk", @@ -4845,9 +4845,9 @@ dependencies = [ [[package]] name = "solana-config-program" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8c2804d121a6d87f4b0cb861dc26e677e76953f4888a43292e34c5e6c5f2852" +checksum = "7448528e2fd237e7d7ca93d4d8541a8a9f346b9f947405799d9a6dd5c22aa41c" dependencies = [ "bincode", "chrono", @@ -4859,9 +4859,9 @@ dependencies = [ [[package]] name = "solana-connection-cache" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fe0460a6005bb2d9ee1d4bce9379ff50c1b438f6f1c8dc867d8b74141f68349" +checksum = "6a51fe3a80fc59a93392a103e6ab492305a6ac614abee70cde6e34fe74fc55dd" dependencies = [ "async-trait", "bincode", @@ -4880,9 +4880,9 @@ dependencies = [ [[package]] name = "solana-faucet" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7bfbf4c31ec25ef12ca89a93ad10e23909249a6bf91f2ad7ca9ce3d510019bb" +checksum = "a69ac334bdd52ef3207d00bb2bc1a035b7161a3a06d20ecf110bd4e5cca26069" dependencies = [ "bincode", "byteorder", @@ -4904,9 +4904,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a63aebf4beac713a1949216ae180355c044df9cc3db9a58ca153bb10bb5843b" +checksum = "ee8e68a37635d475c40f026bfbc39df3298ce91ec0f4db848979b1dbcd9bc675" dependencies = [ "ahash 0.8.3", "blake3", @@ -4937,9 +4937,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi-macro" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bced1b3c0421605312fd7eae7ceb6850d3b1d2e939da349c928e6d46a945c829" +checksum = "07ea45edfe53a4d95f18bd627f1b60e200611a436afd0c58c9c529c085af8965" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", @@ -4949,9 +4949,9 @@ dependencies = [ [[package]] name = "solana-loader-v4-program" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5af55ee96c942cf4f3d088621c7a265b1a0a3558fafd0f5851c8637b7e1170a9" +checksum = "4091f5bc56ecd65473ad5ae4f0bae43a5ea26b916a824eaf74909ed0b0154a7d" dependencies = [ "log", "rand 0.7.3", @@ -4963,9 +4963,9 @@ dependencies = [ [[package]] name = "solana-logger" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c95311f23906f0fa4a6d995f3c39593db18e4d943e4d3fbf082a510d0881d7af" +checksum = "9db83d89279b0620958ae1278fd52f340c68be79980a5f6ebfb3d4e4623d7241" dependencies = [ "env_logger", "lazy_static", @@ -4974,9 +4974,9 @@ dependencies = [ [[package]] name = "solana-measure" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "944244553c62855c57d05ac049140762f1e095188a0e5b973b859947ac1d00bf" +checksum = "8f6745b818b9d2d88b0011ac5532e3dcd4cde0bd1613464ee1bcb98db423ab97" dependencies = [ "log", "solana-sdk", @@ -4984,9 +4984,9 @@ dependencies = [ [[package]] name = "solana-metrics" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f02b2244ee93fd282f057146ce779987a96cdeba5615d43dc0b6347b96134772" +checksum = "d5b3782e709a4546a77354e6b0fbc176a34f19b420e65c0d9c9c48f93459fbab" dependencies = [ "crossbeam-channel", "gethostname", @@ -4998,9 +4998,9 @@ dependencies = [ [[package]] name = "solana-net-utils" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1dad26635fb41e948f56e1b896eab10e84cc62e00c59109a428a95c78fd6560" +checksum = "d2ea302ba1a7186826fecace83da4adce9b288e97ea370999a9aee2bfc71129b" dependencies = [ "bincode", "clap 3.2.23", @@ -5020,9 +5020,9 @@ dependencies = [ [[package]] name = "solana-perf" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b03a0782c2b62c476c3fafd4e002ad8d91a2e36ca952df8e965d81dbf1dc158d" +checksum = "42a5d5de014354c112349667c51f80ce01bca0c6b0bfa027cbc069e972c1c0c7" dependencies = [ "ahash 0.8.3", "bincode", @@ -5047,9 +5047,9 @@ dependencies = [ [[package]] name = "solana-program" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1f5c12cb15108734adae20be5e922c2db09d9623099541dcc61790703c6271c" +checksum = "2560d24192b60301c1219c054a34bcd9d9723bb64ec9b5b987882d86c32868e6" dependencies = [ "ark-bn254", "ark-ec", @@ -5102,9 +5102,9 @@ dependencies = [ [[package]] name = "solana-program-runtime" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb7d1b8df43a93c410456be7d41c0dca9e2c460530a075243a98f556391d2bf9" +checksum = "1726697292d3f551898537f921749352e965510a9cfe7e7b2ff7f1a0fcc6e1db" dependencies = [ "base64 0.21.4", "bincode", @@ -5130,9 +5130,9 @@ dependencies = [ [[package]] name = "solana-program-test" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2971fc318678d5be14bf33356f0eff69f6d39fd75385d0f33db68d15cb1eb7c8" +checksum = "c66d071392c72f4e12527fa5e13e9ab9bd23a785eda1331a597277ee8f8c0800" dependencies = [ "assert_matches", "async-trait", @@ -5157,9 +5157,9 @@ dependencies = [ [[package]] name = "solana-pubsub-client" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b06d8521ac6edf8e8080cb5411f3b831a400341274036528a6364d52f2a97a4" +checksum = "f134152897fe6d3fad3da9945ae452dfc6c2d71465ddce1ad8a423d54ad38bee" dependencies = [ "crossbeam-channel", "futures-util", @@ -5182,9 +5182,9 @@ dependencies = [ [[package]] name = "solana-quic-client" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cba7522b79c889136f99aef825f874be07e94afef561b85a13e9ea3c012d778" +checksum = "409c0182a32bb11acdf84c96361cff4628e93e7e8b293a8cc43e5ef354ffa46a" dependencies = [ "async-mutex", "async-trait", @@ -5210,9 +5210,9 @@ dependencies = [ [[package]] name = "solana-rayon-threadlimit" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd2081d1ed74301999e73e437c25c17dca82038e5472e104caf34b2657b3ba4a" +checksum = "8ce5c2d7f4e92580e6dd18877f0cd5f152e662dbda9c2eed69d29ae9a6f6e5d0" dependencies = [ "lazy_static", "num_cpus", @@ -5220,9 +5220,9 @@ dependencies = [ [[package]] name = "solana-remote-wallet" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a08a9c833b21fe9ec6ab74ea271de236cf7fd2602f34283752bba9c25d62304" +checksum = "2a9e49486e3f31009cfd24869de318e0fac261257f0e87e6f692e0bbf6a053b6" dependencies = [ "console", "dialoguer", @@ -5240,9 +5240,9 @@ dependencies = [ [[package]] name = "solana-rpc-client" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1301ef82a9e87afb28bfccab1b3ebf8f10d6d2ee42c5b1d793ab989d70f83e27" +checksum = "336cdd2dbb4dcfdb7c905eb45fdd32de30f594b12f00d894160a8e4d12fc76a3" dependencies = [ "async-trait", "base64 0.21.4", @@ -5266,9 +5266,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-api" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ffdfe666315851d1a5c3d426a688dccfd2af19b46667140ea59b9ddf3988038" +checksum = "b0cc64f5092d9c3e0bbfbd459689ffc17617b9f52773ffb7e26a2483a33d5ace" dependencies = [ "base64 0.21.4", "bs58", @@ -5288,9 +5288,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-nonce-utils" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d45f9be345ea2d29eb2c43d4b9a4c5181513f0af3e366be8b5e478ef451177be" +checksum = "2c54440695e2a3b14749b52f2021172aeb2387f8bd95f4e0cc2f97e5d27b5ea4" dependencies = [ "clap 2.34.0", "solana-clap-utils", @@ -5301,11 +5301,12 @@ dependencies = [ [[package]] name = "solana-runtime" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0da45b4f58bb45ae1d92b5980ddf90bfabc52342eba4d0f5c1ecacab3a87fb2e" +checksum = "63578440eb0526fc3b3155be56c33dec115d8739e0964ec563a8ae8c80b4ffd2" dependencies = [ "arrayref", + "base64 0.21.4", "bincode", "blake3", "bv", @@ -5339,6 +5340,7 @@ dependencies = [ "rustc_version", "serde", "serde_derive", + "serde_json", "solana-address-lookup-table-program", "solana-bpf-loader-program", "solana-bucket-map", @@ -5355,6 +5357,7 @@ dependencies = [ "solana-sdk", "solana-stake-program", "solana-system-program", + "solana-version", "solana-vote-program", "solana-zk-token-proof-program", "solana-zk-token-sdk", @@ -5370,9 +5373,9 @@ dependencies = [ [[package]] name = "solana-sdk" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "051b93dc7737a7fb530c1e74f135a652bb69f5554c8804b2ebf55d6fb6a30f26" +checksum = "97fc9581f8345a67da71386274084d9a2e35f25689871ad644f5992c786df7c7" dependencies = [ "assert_matches", "base64 0.21.4", @@ -5423,9 +5426,9 @@ dependencies = [ [[package]] name = "solana-sdk-macro" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1fae2d1f62d655f88280a39711db401973d1bbe54fec9f795be80b9d76837ae" +checksum = "6d749979b74d6ca1d8b0f1da1d0333332cfac425a34d71ed1149cccc322e0533" dependencies = [ "bs58", "proc-macro2 1.0.66", @@ -5436,9 +5439,9 @@ dependencies = [ [[package]] name = "solana-send-transaction-service" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e41bc95062870f354eb1e66b7eec5f00cea3d1769fc887b6631b35ddff70db7" +checksum = "a9dad2cb6f9462e7e1c9900df76b9ad601b199aab3d26855d28bf8494698def3" dependencies = [ "crossbeam-channel", "log", @@ -5452,9 +5455,9 @@ dependencies = [ [[package]] name = "solana-stake-program" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b127ba7a3419335051e84ed6d46c1597a6eeaa741831e25e6f0588c72a6e3cc2" +checksum = "0ec54610fafa934717e90e8ab0774867b054d4c3852b5ca24d5947edf14a61e1" dependencies = [ "bincode", "log", @@ -5467,9 +5470,9 @@ dependencies = [ [[package]] name = "solana-streamer" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9cf11ed42da5fd14f4fd197d325951d2d7890aab8e25a7782f8b7540918d3a1" +checksum = "c4a848b9b56af99988e6273ccf79f2bd816633dc3da9ea0eb4488a5b0f8ec820" dependencies = [ "async-channel", "bytes", @@ -5500,9 +5503,9 @@ dependencies = [ [[package]] name = "solana-system-program" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "599877167e03e4da09e2eff42efed7720615d1f2f5e8b9c52a057dc1d7067ee4" +checksum = "a427a441f95ee0b9d8e2065a2978d86142c6fa40cbdccd1de724f77b6cc885af" dependencies = [ "bincode", "log", @@ -5514,9 +5517,9 @@ dependencies = [ [[package]] name = "solana-thin-client" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bffbc01cdc316ff88398afbcd3befa78919049362bfe1a8a5794c942ce34bd96" +checksum = "5db5ba7eddcc0cefc3c5c116387097cb81bb13d7598fbdb3b40c5a964105e879" dependencies = [ "bincode", "log", @@ -5529,9 +5532,9 @@ dependencies = [ [[package]] name = "solana-tpu-client" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8209c111aff1fcf3028a8ee39c7c2171012fda5b31a72b2427d2c2d989dc6d3c" +checksum = "0bdf56494fd1b509c5428f969a10e4e0865b3eaf40aac1640c8f72dac3112b89" dependencies = [ "async-trait", "bincode", @@ -5554,9 +5557,9 @@ dependencies = [ [[package]] name = "solana-transaction-status" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdad82a1e22d7c3fc1e009eeec4e8841697f6cce1902b7a1d5b73baf2bcca2e5" +checksum = "5d3c52eaa1977b0121a099243de4b5b44de936e67869d3298400fb6e974a2f7b" dependencies = [ "Inflector", "base64 0.21.4", @@ -5580,9 +5583,9 @@ dependencies = [ [[package]] name = "solana-udp-client" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a48721c6347353071589e3fbade33079e7ebade6087bb5b10edc788ad41b1ae2" +checksum = "1225fb057b8b5e5aa5b0ee01b974e6ef2c6f01727dfd217c23b89b6547a8b17b" dependencies = [ "async-trait", "solana-connection-cache", @@ -5595,9 +5598,9 @@ dependencies = [ [[package]] name = "solana-version" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de7e99eb16bdc91861829bf0a6e361dd87ab898673b3708ebacf4ba27ca4d242" +checksum = "32f7b09ffc8f5446bee6ee1ab4ce4c98504d23222313de1d0ed762f736a3ffe3" dependencies = [ "log", "rustc_version", @@ -5611,9 +5614,9 @@ dependencies = [ [[package]] name = "solana-vote-program" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22b1a3a2d9807a4141f0a550fdb3fa61a4aac4b4e7ea31694739509a43b9fa23" +checksum = "2be239ebe1d73af268ce9ba5111ce9595a430aa98576105e87b00e92a5ef2a0b" dependencies = [ "bincode", "log", @@ -5633,9 +5636,9 @@ dependencies = [ [[package]] name = "solana-zk-token-proof-program" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d3db5213b9dc063e95f94bc0b66748942786e48ed5e259bcf617897f1b86087" +checksum = "1a813c2c577b9eb24b62d7149d1e5340425f55650f3ff6a01eb2ded828a95774" dependencies = [ "bytemuck", "getrandom 0.1.16", @@ -5648,9 +5651,9 @@ dependencies = [ [[package]] name = "solana-zk-token-sdk" -version = "1.16.18" +version = "1.16.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad3cc2b931a39510b1c90dc876a93ae315b9712a8338296e4b60519d09e57be9" +checksum = "fc4b0547480462cfec9dddaa8adcf2fa7c8b022021738bf71c790c0c7be54a34" dependencies = [ "aes-gcm-siv", "base64 0.21.4", diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index ad7557ec9..417f7ceba 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -8,8 +8,8 @@ edition = "2021" [dependencies] clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } -solana-sdk = "=1.16.18" -solana-client = "=1.16.18" +solana-sdk = "=1.16.23" +solana-client = "=1.16.23" serde = "1.0.186" serde_json = { version = "1.0.107", features = ["preserve_order"] } ethnum = { version = "1.4", default-features = false, features = ["serde"] } diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index 4f2b552e7..d638202e8 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -8,10 +8,10 @@ edition = "2021" [dependencies] clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } -solana-sdk = "=1.16.18" -solana-client = "=1.16.18" -solana-clap-utils = "=1.16.18" -solana-cli-config = "=1.16.18" +solana-sdk = "=1.16.23" +solana-client = "=1.16.23" +solana-clap-utils = "=1.16.23" +solana-cli-config = "=1.16.23" hex = "0.4.2" serde = "1.0.186" serde_json = { version = "1.0.107", features = ["preserve_order"] } diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index f4a1d6a32..b0313def2 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -10,13 +10,13 @@ thiserror = "1.0" anyhow = "1.0" bincode = "1.3.1" evm-loader = { path = "../program", default-features = false, features = ["log", "async-trait", "serde_json"] } -solana-sdk = "=1.16.18" -solana-client = "=1.16.18" -solana-clap-utils = "=1.16.18" -solana-cli-config = "=1.16.18" -solana-cli = "=1.16.18" -solana-transaction-status = "=1.16.18" -solana-program-test = "=1.16.18" +solana-sdk = "=1.16.23" +solana-client = "=1.16.23" +solana-clap-utils = "=1.16.23" +solana-cli-config = "=1.16.23" +solana-cli = "=1.16.23" +solana-transaction-status = "=1.16.23" +solana-program-test = "=1.16.23" spl-token = { version = "~3.5", default-features = false, features = ["no-entrypoint"] } spl-associated-token-account = { version = "~1.1", default-features = false, features = ["no-entrypoint"] } bs58 = "0.4.0" diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 8c6ef2093..b19e38ed4 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -37,7 +37,7 @@ default = ["custom-heap"] [dependencies] linked_list_allocator = { version = "0.10", default-features = false } evm-loader-macro = { path = "../program-macro" } -solana-program = { version = "=1.16.18", default-features = false } +solana-program = { version = "=1.16.23", default-features = false } spl-token = { version = "~3.5", default-features = false, features = ["no-entrypoint"] } spl-associated-token-account = { version = "~1.1", default-features = false, features = ["no-entrypoint"] } mpl-token-metadata = { version = "1.13.2", default-features = false, features = ["no-entrypoint"] } From acf2ef1951c830586eb0a9b6587453702406aca6 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Tue, 12 Dec 2023 11:27:55 +0200 Subject: [PATCH 076/318] NDEV-2438: Simplify Rpc trait usage (#245) - Extracted BuildConfigSimulator trait - Converted ConfigSimulator functions to methods --- evm_loader/lib/src/account_storage.rs | 23 +-- .../lib/src/commands/collect_treasury.rs | 2 +- evm_loader/lib/src/commands/emulate.rs | 21 ++- evm_loader/lib/src/commands/get_balance.rs | 5 +- evm_loader/lib/src/commands/get_config.rs | 172 +++++++++--------- evm_loader/lib/src/commands/get_contract.rs | 5 +- evm_loader/lib/src/commands/get_holder.rs | 3 +- evm_loader/lib/src/commands/get_neon_elf.rs | 12 +- evm_loader/lib/src/commands/get_storage_at.rs | 5 +- .../lib/src/commands/init_environment.rs | 5 +- evm_loader/lib/src/commands/trace.rs | 11 +- evm_loader/lib/src/rpc/mod.rs | 3 +- evm_loader/lib/src/syscall_stubs.rs | 5 +- 13 files changed, 138 insertions(+), 134 deletions(-) diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index 499b0f8df..8485dcbf5 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -25,8 +25,7 @@ use serde::{Deserialize, Serialize}; use solana_client::client_error; use solana_sdk::{account::Account, account_info::AccountInfo, pubkey, pubkey::Pubkey}; -use crate::commands::get_config::ChainInfo; -use crate::rpc::RpcEnum; +use crate::commands::get_config::{BuildConfigSimulator, ChainInfo}; use crate::tracing::{AccountOverride, AccountOverrides, BlockOverrides}; use serde_with::{serde_as, DisplayFromStr}; @@ -44,10 +43,10 @@ pub struct SolanaAccount { } #[allow(clippy::module_name_repetitions)] -pub struct EmulatorAccountStorage<'rpc> { +pub struct EmulatorAccountStorage<'rpc, T: Rpc> { pub accounts: RefCell>, pub gas: u64, - rpc: &'rpc RpcEnum, + rpc: &'rpc T, program_id: Pubkey, chains: Vec, block_number: u64, @@ -55,14 +54,14 @@ pub struct EmulatorAccountStorage<'rpc> { state_overrides: Option, } -impl<'rpc> EmulatorAccountStorage<'rpc> { +impl<'rpc, T: Rpc + BuildConfigSimulator> EmulatorAccountStorage<'rpc, T> { pub async fn new( - rpc: &'rpc RpcEnum, + rpc: &'rpc T, program_id: Pubkey, chains: Option>, block_overrides: Option, state_overrides: Option, - ) -> Result, NeonError> { + ) -> Result, NeonError> { trace!("backend::new"); let block_number = match block_overrides.as_ref().and_then(|o| o.number) { @@ -93,20 +92,22 @@ impl<'rpc> EmulatorAccountStorage<'rpc> { } pub async fn with_accounts( - rpc: &'rpc RpcEnum, + rpc: &'rpc T, program_id: Pubkey, accounts: &[Pubkey], chains: Option>, block_overrides: Option, state_overrides: Option, - ) -> Result, NeonError> { + ) -> Result, NeonError> { let storage = Self::new(rpc, program_id, chains, block_overrides, state_overrides).await?; storage.download_accounts(accounts).await?; Ok(storage) } +} +impl EmulatorAccountStorage<'_, T> { async fn download_accounts(&self, pubkeys: &[Pubkey]) -> Result<(), NeonError> { let accounts = self.rpc.get_multiple_accounts(pubkeys).await?; @@ -503,8 +504,8 @@ impl<'rpc> EmulatorAccountStorage<'rpc> { } } -#[async_trait(? Send)] -impl<'a> AccountStorage for EmulatorAccountStorage<'a> { +#[async_trait(?Send)] +impl AccountStorage for EmulatorAccountStorage<'_, T> { fn program_id(&self) -> &Pubkey { debug!("program_id"); &self.program_id diff --git a/evm_loader/lib/src/commands/collect_treasury.rs b/evm_loader/lib/src/commands/collect_treasury.rs index 2059ed187..709df6a5e 100644 --- a/evm_loader/lib/src/commands/collect_treasury.rs +++ b/evm_loader/lib/src/commands/collect_treasury.rs @@ -26,7 +26,7 @@ pub async fn execute( rpc_client: &CloneRpcClient, signer: &dyn Signer, ) -> NeonResult { - let neon_params = read_elf_parameters_from_account(config, &rpc_client.clone().into()).await?; + let neon_params = read_elf_parameters_from_account(config, rpc_client).await?; let pool_count: u32 = neon_params .get("NEON_TREASURY_POOL_COUNT") diff --git a/evm_loader/lib/src/commands/emulate.rs b/evm_loader/lib/src/commands/emulate.rs index 651c7efb0..0271b6248 100644 --- a/evm_loader/lib/src/commands/emulate.rs +++ b/evm_loader/lib/src/commands/emulate.rs @@ -5,7 +5,8 @@ use serde::{Deserialize, Serialize}; use solana_sdk::entrypoint::MAX_PERMITTED_DATA_INCREASE; use solana_sdk::pubkey::Pubkey; -use crate::rpc::RpcEnum; +use crate::commands::get_config::BuildConfigSimulator; +use crate::rpc::Rpc; use crate::syscall_stubs::setup_emulator_syscall_stubs; use crate::types::{EmulateRequest, TxParams}; use crate::{ @@ -50,16 +51,16 @@ impl EmulateResponse { } pub async fn execute( - rpc: &RpcEnum, + rpc: &(impl Rpc + BuildConfigSimulator), program_id: Pubkey, - config: EmulateRequest, + emulate_request: EmulateRequest, tracer: Option, ) -> NeonResult { - let block_overrides = config + let block_overrides = emulate_request .trace_config .as_ref() .and_then(|t| t.block_overrides.clone()); - let state_overrides = config + let state_overrides = emulate_request .trace_config .as_ref() .and_then(|t| t.state_overrides.clone()); @@ -67,22 +68,22 @@ pub async fn execute( let mut storage = EmulatorAccountStorage::with_accounts( rpc, program_id, - &config.accounts, - config.chains, + &emulate_request.accounts, + emulate_request.chains, block_overrides, state_overrides, ) .await?; - let step_limit = config.step_limit.unwrap_or(100000); + let step_limit = emulate_request.step_limit.unwrap_or(100000); setup_emulator_syscall_stubs(rpc).await?; - emulate_trx(config.tx, &mut storage, step_limit, tracer).await + emulate_trx(emulate_request.tx, &mut storage, step_limit, tracer).await } async fn emulate_trx( tx_params: TxParams, - storage: &mut EmulatorAccountStorage<'_>, + storage: &mut EmulatorAccountStorage<'_, impl Rpc>, step_limit: u64, tracer: Option, ) -> NeonResult { diff --git a/evm_loader/lib/src/commands/get_balance.rs b/evm_loader/lib/src/commands/get_balance.rs index e1d0da6c5..e9d6561a9 100644 --- a/evm_loader/lib/src/commands/get_balance.rs +++ b/evm_loader/lib/src/commands/get_balance.rs @@ -6,10 +6,9 @@ use solana_sdk::{account::Account, pubkey::Pubkey}; use crate::{account_storage::account_info, rpc::Rpc, types::BalanceAddress, NeonResult}; -use crate::rpc::RpcEnum; use serde_with::{serde_as, DisplayFromStr}; -use super::get_config::ChainInfo; +use super::get_config::{BuildConfigSimulator, ChainInfo}; #[derive(Debug, Serialize, Deserialize)] pub enum BalanceStatus { @@ -92,7 +91,7 @@ fn is_legacy_chain_id(id: u64, chains: &[ChainInfo]) -> bool { } pub async fn execute( - rpc: &RpcEnum, + rpc: &(impl Rpc + BuildConfigSimulator), program_id: &Pubkey, address: &[BalanceAddress], ) -> NeonResult> { diff --git a/evm_loader/lib/src/commands/get_config.rs b/evm_loader/lib/src/commands/get_config.rs index 0a642cc0c..e697de497 100644 --- a/evm_loader/lib/src/commands/get_config.rs +++ b/evm_loader/lib/src/commands/get_config.rs @@ -1,4 +1,6 @@ +use async_trait::async_trait; use base64::Engine; +use enum_dispatch::enum_dispatch; use std::collections::BTreeMap; use tokio::sync::{Mutex, MutexGuard, OnceCell}; @@ -18,7 +20,7 @@ use solana_sdk::{ use crate::{rpc::Rpc, NeonError, NeonResult}; -use crate::rpc::{CallDbClient, RpcEnum, SolanaRpc}; +use crate::rpc::{CallDbClient, CloneRpcClient, SolanaRpc}; use serde_with::{serde_as, DisplayFromStr}; use solana_client::nonblocking::rpc_client::RpcClient; @@ -114,30 +116,39 @@ async fn lock_program_test( context } -enum ConfigSimulator<'r> { +pub enum ConfigSimulator<'r> { Rpc(Pubkey, &'r RpcClient), ProgramTest(MutexGuard<'static, ProgramTestContext>), } -impl<'r> ConfigSimulator<'r> { - pub async fn new(rpc: &'r RpcEnum, program_id: Pubkey) -> NeonResult> { - let simulator = match rpc { - RpcEnum::CloneRpcClient(clone_rpc_client) => Self::Rpc( - clone_rpc_client.get_account_with_sol().await?, - clone_rpc_client, - ), - RpcEnum::CallDbClient(call_db_client) => { - let program_data = - read_program_data_from_account(call_db_client, program_id).await?; - let mut program_test = lock_program_test(program_id, program_data).await; - program_test.get_new_latest_blockhash().await?; - - Self::ProgramTest(program_test) - } - }; - Ok(simulator) +#[async_trait(?Send)] +#[enum_dispatch] +pub trait BuildConfigSimulator { + async fn build_config_simulator(&self, program_id: Pubkey) -> NeonResult; +} + +#[async_trait(?Send)] +impl BuildConfigSimulator for CloneRpcClient { + async fn build_config_simulator(&self, _program_id: Pubkey) -> NeonResult { + Ok(ConfigSimulator::Rpc( + self.get_account_with_sol().await?, + self, + )) } +} + +#[async_trait(?Send)] +impl BuildConfigSimulator for CallDbClient { + async fn build_config_simulator(&self, program_id: Pubkey) -> NeonResult { + let program_data = read_program_data_from_account(self, program_id).await?; + let mut program_test = lock_program_test(program_id, program_data).await; + program_test.get_new_latest_blockhash().await?; + Ok(ConfigSimulator::ProgramTest(program_test)) + } +} + +impl ConfigSimulator<'_> { async fn simulate_config( &mut self, program_id: Pubkey, @@ -195,97 +206,90 @@ impl<'r> ConfigSimulator<'r> { Ok(return_data) } -} -async fn get_version( - context: &mut ConfigSimulator<'_>, - program_id: Pubkey, -) -> NeonResult<(String, String)> { - let return_data = context.simulate_config(program_id, 0xA7, &[]).await?; - let (version, revision) = bincode::deserialize(&return_data)?; + async fn get_version(&mut self, program_id: Pubkey) -> NeonResult<(String, String)> { + let return_data = self.simulate_config(program_id, 0xA7, &[]).await?; + let (version, revision) = bincode::deserialize(&return_data)?; - Ok((version, revision)) -} + Ok((version, revision)) + } -async fn get_status(context: &mut ConfigSimulator<'_>, program_id: Pubkey) -> NeonResult { - let return_data = context.simulate_config(program_id, 0xA6, &[]).await?; - match return_data[0] { - 0 => Ok(Status::Emergency), - 1 => Ok(Status::Ok), - _ => Ok(Status::Unknown), + async fn get_status(&mut self, program_id: Pubkey) -> NeonResult { + let return_data = self.simulate_config(program_id, 0xA6, &[]).await?; + match return_data[0] { + 0 => Ok(Status::Emergency), + 1 => Ok(Status::Ok), + _ => Ok(Status::Unknown), + } } -} -async fn get_environment( - context: &mut ConfigSimulator<'_>, - program_id: Pubkey, -) -> NeonResult { - let return_data = context.simulate_config(program_id, 0xA2, &[]).await?; - let environment = String::from_utf8(return_data)?; + async fn get_environment(&mut self, program_id: Pubkey) -> NeonResult { + let return_data = self.simulate_config(program_id, 0xA2, &[]).await?; + let environment = String::from_utf8(return_data)?; - Ok(environment) -} + Ok(environment) + } -async fn get_chains( - context: &mut ConfigSimulator<'_>, - program_id: Pubkey, -) -> NeonResult> { - let mut result = Vec::new(); + async fn get_chains(&mut self, program_id: Pubkey) -> NeonResult> { + let mut result = Vec::new(); + + let return_data = self.simulate_config(program_id, 0xA0, &[]).await?; + let chain_count = return_data.as_slice().try_into()?; + let chain_count = usize::from_le_bytes(chain_count); - let return_data = context.simulate_config(program_id, 0xA0, &[]).await?; - let chain_count = return_data.as_slice().try_into()?; - let chain_count = usize::from_le_bytes(chain_count); + for i in 0..chain_count { + let index = i.to_le_bytes(); + let return_data = self.simulate_config(program_id, 0xA1, &index).await?; - for i in 0..chain_count { - let index = i.to_le_bytes(); - let return_data = context.simulate_config(program_id, 0xA1, &index).await?; + let (id, name, token) = bincode::deserialize(&return_data)?; + result.push(ChainInfo { id, name, token }); + } - let (id, name, token) = bincode::deserialize(&return_data)?; - result.push(ChainInfo { id, name, token }); + Ok(result) } - Ok(result) -} + async fn get_properties(&mut self, program_id: Pubkey) -> NeonResult> { + let mut result = BTreeMap::new(); -async fn get_properties( - context: &mut ConfigSimulator<'_>, - program_id: Pubkey, -) -> NeonResult> { - let mut result = BTreeMap::new(); + let return_data = self.simulate_config(program_id, 0xA3, &[]).await?; + let count = return_data.as_slice().try_into()?; + let count = usize::from_le_bytes(count); - let return_data = context.simulate_config(program_id, 0xA3, &[]).await?; - let count = return_data.as_slice().try_into()?; - let count = usize::from_le_bytes(count); + for i in 0..count { + let index = i.to_le_bytes(); + let return_data = self.simulate_config(program_id, 0xA4, &index).await?; - for i in 0..count { - let index = i.to_le_bytes(); - let return_data = context.simulate_config(program_id, 0xA4, &index).await?; + let (name, value) = bincode::deserialize(&return_data)?; + result.insert(name, value); + } - let (name, value) = bincode::deserialize(&return_data)?; - result.insert(name, value); + Ok(result) } - - Ok(result) } -pub async fn execute(rpc: &RpcEnum, program_id: Pubkey) -> NeonResult { - let mut simulator = ConfigSimulator::new(rpc, program_id).await?; +pub async fn execute( + rpc: &impl BuildConfigSimulator, + program_id: Pubkey, +) -> NeonResult { + let mut simulator = rpc.build_config_simulator(program_id).await?; - let (version, revision) = get_version(&mut simulator, program_id).await?; + let (version, revision) = simulator.get_version(program_id).await?; Ok(GetConfigResponse { version, revision, - status: get_status(&mut simulator, program_id).await?, - environment: get_environment(&mut simulator, program_id).await?, - chains: get_chains(&mut simulator, program_id).await?, - config: get_properties(&mut simulator, program_id).await?, + status: simulator.get_status(program_id).await?, + environment: simulator.get_environment(program_id).await?, + chains: simulator.get_chains(program_id).await?, + config: simulator.get_properties(program_id).await?, }) } -pub async fn read_chains(rpc: &RpcEnum, program_id: Pubkey) -> NeonResult> { - let mut simulator = ConfigSimulator::new(rpc, program_id).await?; +pub async fn read_chains( + rpc: &impl BuildConfigSimulator, + program_id: Pubkey, +) -> NeonResult> { + let mut simulator = rpc.build_config_simulator(program_id).await?; - let chains = get_chains(&mut simulator, program_id).await?; - Ok(chains) + simulator.get_chains(program_id).await } diff --git a/evm_loader/lib/src/commands/get_contract.rs b/evm_loader/lib/src/commands/get_contract.rs index 842bebb52..6f1a3d324 100644 --- a/evm_loader/lib/src/commands/get_contract.rs +++ b/evm_loader/lib/src/commands/get_contract.rs @@ -7,10 +7,9 @@ use solana_sdk::{account::Account, pubkey::Pubkey}; use crate::{account_storage::account_info, rpc::Rpc, NeonResult}; -use crate::rpc::RpcEnum; use serde_with::{hex::Hex, serde_as, DisplayFromStr}; -use super::get_config::ChainInfo; +use super::get_config::{BuildConfigSimulator, ChainInfo}; #[serde_as] #[derive(Debug, Serialize, Deserialize)] @@ -75,7 +74,7 @@ fn read_account( } pub async fn execute( - rpc: &RpcEnum, + rpc: &(impl Rpc + BuildConfigSimulator), program_id: &Pubkey, accounts: &[Address], ) -> NeonResult> { diff --git a/evm_loader/lib/src/commands/get_holder.rs b/evm_loader/lib/src/commands/get_holder.rs index 13fa2bcd1..1ad6aff13 100644 --- a/evm_loader/lib/src/commands/get_holder.rs +++ b/evm_loader/lib/src/commands/get_holder.rs @@ -12,7 +12,6 @@ use std::fmt::Display; use crate::{account_storage::account_info, rpc::Rpc, NeonResult}; -use crate::rpc::RpcEnum; use serde_with::{hex::Hex, serde_as, skip_serializing_none, DisplayFromStr}; #[derive(Debug, Default, Serialize)] @@ -141,7 +140,7 @@ pub fn read_holder(program_id: &Pubkey, info: AccountInfo) -> NeonResult NeonResult { diff --git a/evm_loader/lib/src/commands/get_neon_elf.rs b/evm_loader/lib/src/commands/get_neon_elf.rs index a710656ee..5e88bcaaa 100644 --- a/evm_loader/lib/src/commands/get_neon_elf.rs +++ b/evm_loader/lib/src/commands/get_neon_elf.rs @@ -7,7 +7,7 @@ use solana_sdk::{ }; use std::{collections::HashMap, convert::TryFrom, fs::File, io::Read}; -use crate::rpc::{Rpc, RpcEnum}; +use crate::rpc::Rpc; use crate::{errors::NeonError, Config, NeonResult}; pub type GetNeonElfReturn = HashMap; @@ -17,7 +17,7 @@ pub struct CachedElfParams { } impl CachedElfParams { - pub async fn new(config: &Config, rpc: &RpcEnum) -> Self { + pub async fn new(config: &Config, rpc: &impl Rpc) -> Self { Self { elf_params: read_elf_parameters_from_account(config, rpc) .await @@ -144,7 +144,7 @@ pub fn get_elf_parameter(data: &[u8], elf_parameter: &str) -> Result { pub async fn read_elf_parameters_from_account( config: &Config, - rpc: &RpcEnum, + rpc: &impl Rpc, ) -> Result { let (_, program_data) = read_program_data_from_account(config, rpc, &config.evm_loader).await?; Ok(read_elf_parameters(config, &program_data)) @@ -152,7 +152,7 @@ pub async fn read_elf_parameters_from_account( pub async fn read_program_data_from_account( config: &Config, - rpc: &RpcEnum, + rpc: &impl Rpc, evm_loader: &Pubkey, ) -> Result<(Option, Vec), NeonError> { let account = rpc @@ -224,14 +224,14 @@ fn read_program_params_from_file( async fn read_program_params_from_account( config: &Config, - rpc: &RpcEnum, + rpc: &impl Rpc, ) -> NeonResult { read_elf_parameters_from_account(config, rpc).await } pub async fn execute( config: &Config, - rpc: &RpcEnum, + rpc: &impl Rpc, program_location: Option<&str>, ) -> NeonResult { if let Some(program_location) = program_location { diff --git a/evm_loader/lib/src/commands/get_storage_at.rs b/evm_loader/lib/src/commands/get_storage_at.rs index feaf4dc79..24cee229d 100644 --- a/evm_loader/lib/src/commands/get_storage_at.rs +++ b/evm_loader/lib/src/commands/get_storage_at.rs @@ -4,14 +4,15 @@ use solana_sdk::pubkey::Pubkey; use evm_loader::{account_storage::AccountStorage, types::Address}; -use crate::rpc::RpcEnum; +use crate::commands::get_config::BuildConfigSimulator; +use crate::rpc::Rpc; use crate::{account_storage::EmulatorAccountStorage, NeonResult}; #[derive(Debug, Default, Serialize, Deserialize)] pub struct GetStorageAtReturn(pub [u8; 32]); pub async fn execute( - rpc: &RpcEnum, + rpc: &(impl Rpc + BuildConfigSimulator), program_id: &Pubkey, address: Address, index: U256, diff --git a/evm_loader/lib/src/commands/init_environment.rs b/evm_loader/lib/src/commands/init_environment.rs index fdcb02aee..044dfc52e 100644 --- a/evm_loader/lib/src/commands/init_environment.rs +++ b/evm_loader/lib/src/commands/init_environment.rs @@ -129,9 +129,8 @@ pub async fn execute( &bpf_loader_upgradeable::id(), ) .0; - let rpc_enum = client.clone().into(); let (program_upgrade_authority, program_data) = - read_program_data_from_account(config, &rpc_enum, &config.evm_loader).await?; + read_program_data_from_account(config, client, &config.evm_loader).await?; let data = file.map_or(Ok(program_data), read_program_data)?; let program_parameters = Parameters::new(read_elf_parameters(config, &data)); @@ -204,7 +203,7 @@ pub async fn execute( //====================== Create 'Deposit' NEON-token balance ====================================================== let (deposit_authority, _) = Pubkey::find_program_address(&[b"Deposit"], &config.evm_loader); - let chains = super::get_config::read_chains(&rpc_enum, config.evm_loader).await?; + let chains = super::get_config::read_chains(client, config.evm_loader).await?; for chain in chains { let pool = get_associated_token_address(&deposit_authority, &chain.token); diff --git a/evm_loader/lib/src/commands/trace.rs b/evm_loader/lib/src/commands/trace.rs index 1496f41d9..b6f8251fb 100644 --- a/evm_loader/lib/src/commands/trace.rs +++ b/evm_loader/lib/src/commands/trace.rs @@ -3,17 +3,18 @@ use std::rc::Rc; use serde_json::Value; use solana_sdk::pubkey::Pubkey; +use crate::commands::get_config::BuildConfigSimulator; use crate::errors::NeonError; -use crate::rpc::RpcEnum; +use crate::rpc::Rpc; use crate::tracing::tracers::new_tracer; use crate::types::EmulateRequest; pub async fn trace_transaction( - rpc: &RpcEnum, + rpc: &(impl Rpc + BuildConfigSimulator), program_id: Pubkey, - config: EmulateRequest, + emulate_request: EmulateRequest, ) -> Result { - let trace_config = config + let trace_config = emulate_request .trace_config .as_ref() .map(|c| c.trace_config.clone()) @@ -22,7 +23,7 @@ pub async fn trace_transaction( let tracer = new_tracer(&trace_config)?; let emulation_tracer = Some(Rc::clone(&tracer)); - let r = super::emulate::execute(rpc, program_id, config, emulation_tracer).await?; + let r = super::emulate::execute(rpc, program_id, emulate_request, emulation_tracer).await?; let mut traces = Rc::try_unwrap(tracer) .expect("There is must be only one reference") diff --git a/evm_loader/lib/src/rpc/mod.rs b/evm_loader/lib/src/rpc/mod.rs index 799305ce4..0a641e027 100644 --- a/evm_loader/lib/src/rpc/mod.rs +++ b/evm_loader/lib/src/rpc/mod.rs @@ -5,6 +5,7 @@ pub use db_call_client::CallDbClient; pub use validator_client::CloneRpcClient; pub use validator_client::SolanaRpc; +use crate::commands::get_config::{BuildConfigSimulator, ConfigSimulator}; use crate::{NeonError, NeonResult}; use async_trait::async_trait; use enum_dispatch::enum_dispatch; @@ -34,7 +35,7 @@ pub trait Rpc { async fn get_slot(&self) -> ClientResult; } -#[enum_dispatch(Rpc)] +#[enum_dispatch(BuildConfigSimulator, Rpc)] pub enum RpcEnum { CloneRpcClient, CallDbClient, diff --git a/evm_loader/lib/src/syscall_stubs.rs b/evm_loader/lib/src/syscall_stubs.rs index d2608edd7..4f996e4c1 100644 --- a/evm_loader/lib/src/syscall_stubs.rs +++ b/evm_loader/lib/src/syscall_stubs.rs @@ -1,7 +1,6 @@ use log::info; use solana_sdk::{program_error::ProgramError, program_stubs::SyscallStubs, sysvar::rent::Rent}; -use crate::rpc::RpcEnum; use crate::{errors::NeonError, rpc::Rpc}; pub struct DefaultStubs; @@ -13,7 +12,7 @@ pub struct EmulatorStubs { } impl EmulatorStubs { - pub async fn new(rpc: &RpcEnum) -> Result, NeonError> { + pub async fn new(rpc: &impl Rpc) -> Result, NeonError> { let rent_pubkey = solana_sdk::sysvar::rent::id(); let data = rpc .get_account(&rent_pubkey) @@ -57,7 +56,7 @@ impl SyscallStubs for EmulatorStubs { } } -pub async fn setup_emulator_syscall_stubs(rpc: &RpcEnum) -> Result<(), NeonError> { +pub async fn setup_emulator_syscall_stubs(rpc: &impl Rpc) -> Result<(), NeonError> { let syscall_stubs = EmulatorStubs::new(rpc).await?; solana_sdk::program_stubs::set_syscall_stubs(syscall_stubs); From 426543f132197eefeba42fc53d50eedf782db4f0 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Tue, 12 Dec 2023 16:49:36 +0200 Subject: [PATCH 077/318] NDEV-2439: Replace HexBytes with web3::types::Bytes (#246) --- evm_loader/Cargo.lock | 342 +++++++++++++++++- evm_loader/lib/Cargo.toml | 3 +- evm_loader/lib/src/account_storage.rs | 2 +- evm_loader/lib/src/tracing/mod.rs | 4 +- .../lib/src/tracing/tracers/struct_logger.rs | 4 +- evm_loader/program/src/types/hexbytes.rs | 90 ----- evm_loader/program/src/types/mod.rs | 2 - 7 files changed, 347 insertions(+), 100 deletions(-) delete mode 100644 evm_loader/program/src/types/hexbytes.rs diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 54eba6087..d0f3102cd 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -623,6 +623,18 @@ dependencies = [ "typenum", ] +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "blake3" version = "1.4.1" @@ -869,6 +881,12 @@ dependencies = [ "serde", ] +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + [[package]] name = "bytemuck" version = "1.14.0" @@ -1787,6 +1805,50 @@ dependencies = [ "libc", ] +[[package]] +name = "ethabi" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" +dependencies = [ + "ethereum-types", + "hex", + "once_cell", + "regex", + "serde", + "serde_json", + "sha3 0.10.7", + "thiserror", + "uint", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-rlp", + "impl-serde", + "tiny-keccak", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-rlp", + "impl-serde", + "primitive-types", + "uint", +] + [[package]] name = "ethnum" version = "1.4.0" @@ -1879,6 +1941,18 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand 0.8.5", + "rustc-hex", + "static_assertions", +] + [[package]] name = "flate2" version = "1.0.27" @@ -1925,6 +1999,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "futures" version = "0.3.28" @@ -1996,6 +2076,12 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +[[package]] +name = "futures-timer" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" + [[package]] name = "futures-util" version = "0.3.28" @@ -2163,6 +2249,30 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +[[package]] +name = "headers" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" +dependencies = [ + "base64 0.21.4", + "bytes", + "headers-core", + "http", + "httpdate", + "mime", + "sha1", +] + +[[package]] +name = "headers-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +dependencies = [ + "http", +] + [[package]] name = "heck" version = "0.3.3" @@ -2390,6 +2500,16 @@ dependencies = [ "unicode-normalization", ] +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "im" version = "15.1.0" @@ -2406,6 +2526,44 @@ dependencies = [ "version_check", ] +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 1.0.109", +] + [[package]] name = "index_list" version = "0.2.7" @@ -3023,6 +3181,7 @@ dependencies = [ "thiserror", "tokio", "tracing", + "web3", ] [[package]] @@ -3378,6 +3537,32 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "parity-scale-codec" +version = "3.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8e946cc0cc711189c0b0249fb8b599cbeeab9784d83c415719368bb8d4ac64" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a296c3079b5fefbc499e1de58dc26c09b1b9a5952d26694ee89f04a43ebbb3e" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 1.0.109", +] + [[package]] name = "parking_lot" version = "0.12.1" @@ -3544,6 +3729,19 @@ dependencies = [ "yansi", ] +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "uint", +] + [[package]] name = "proc-macro-crate" version = "0.1.5" @@ -3682,6 +3880,12 @@ dependencies = [ "proc-macro2 1.0.66", ] +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "rand" version = "0.4.6" @@ -3923,10 +4127,12 @@ dependencies = [ "http-body", "hyper", "hyper-rustls", + "hyper-tls", "ipnet", "js-sys", "log", "mime", + "native-tls", "once_cell", "percent-encoding", "pin-project-lite", @@ -3936,6 +4142,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "tokio", + "tokio-native-tls", "tokio-rustls 0.24.1", "tokio-util 0.7.7", "tower-service", @@ -4213,6 +4420,24 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "secp256k1" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" +dependencies = [ + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" +dependencies = [ + "cc", +] + [[package]] name = "security-framework" version = "2.8.2" @@ -4382,6 +4607,19 @@ dependencies = [ "unsafe-libyaml", ] +[[package]] +name = "sha-1" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + [[package]] name = "sha-1" version = "0.10.1" @@ -4559,6 +4797,21 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "soketto" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" +dependencies = [ + "base64 0.13.1", + "bytes", + "futures", + "httparse", + "log", + "rand 0.8.5", + "sha-1 0.9.8", +] + [[package]] name = "solana-account-decoder" version = "1.16.23" @@ -6060,6 +6313,12 @@ dependencies = [ "unicode-xid 0.2.4", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "tar" version = "0.4.40" @@ -6236,6 +6495,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinyvec" version = "1.6.0" @@ -6378,6 +6646,7 @@ checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" dependencies = [ "bytes", "futures-core", + "futures-io", "futures-sink", "pin-project-lite", "tokio", @@ -6571,7 +6840,7 @@ dependencies = [ "log", "rand 0.8.5", "rustls 0.20.8", - "sha-1", + "sha-1 0.10.1", "thiserror", "url", "utf-8", @@ -6585,6 +6854,18 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + [[package]] name = "unicode-bidi" version = "0.3.13" @@ -6678,7 +6959,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" dependencies = [ "form_urlencoded", - "idna", + "idna 0.3.0", "percent-encoding", ] @@ -6841,6 +7122,54 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web3" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5388522c899d1e1c96a4c307e3797e0f697ba7c77dd8e0e625ecba9dd0342937" +dependencies = [ + "arrayvec", + "base64 0.21.4", + "bytes", + "derive_more", + "ethabi", + "ethereum-types", + "futures", + "futures-timer", + "headers", + "hex", + "idna 0.4.0", + "jsonrpc-core", + "log", + "once_cell", + "parking_lot", + "pin-project", + "reqwest", + "rlp", + "secp256k1", + "serde", + "serde_json", + "soketto", + "tiny-keccak", + "tokio", + "tokio-stream", + "tokio-util 0.7.7", + "url", + "web3-async-native-tls", +] + +[[package]] +name = "web3-async-native-tls" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f6d8d1636b2627fe63518d5a9b38a569405d9c9bc665c43c9c341de57227ebb" +dependencies = [ + "native-tls", + "thiserror", + "tokio", + "url", +] + [[package]] name = "webpki" version = "0.22.0" @@ -7081,6 +7410,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "x509-parser" version = "0.14.0" diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index b0313def2..7ecba68df 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -34,8 +34,9 @@ tokio = { version = "1", features = ["full"] } clickhouse = "0.11.5" tracing = "0.1" async-trait = "0.1.73" -build-info = "0.0.31" +build-info = { version = "0.0.31", features = ["serde"] } enum_dispatch = "0.3.12" +web3 = "0.19.0" [build-dependencies] build-info-build = "0.0.31" diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index 8485dcbf5..0e2d3bfd8 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -657,7 +657,7 @@ impl AccountStorage for EmulatorAccountStorage<'_, T> { let code_override = self.account_override(address, |a| a.code.clone()); if let Some(code_override) = code_override { - return Buffer::from_vec(code_override.into()); + return Buffer::from_vec(code_override.0); } let code = self diff --git a/evm_loader/lib/src/tracing/mod.rs b/evm_loader/lib/src/tracing/mod.rs index 4b99e2d01..a42ff140c 100644 --- a/evm_loader/lib/src/tracing/mod.rs +++ b/evm_loader/lib/src/tracing/mod.rs @@ -1,8 +1,8 @@ use ethnum::U256; -use evm_loader::types::hexbytes::HexBytes; use evm_loader::types::Address; use serde_json::Value; use std::collections::HashMap; +use web3::types::Bytes; pub mod tracers; @@ -29,7 +29,7 @@ pub struct BlockOverrides { #[serde(rename_all = "camelCase")] pub struct AccountOverride { pub nonce: Option, - pub code: Option, + pub code: Option, pub balance: Option, pub state: Option>, pub state_diff: Option>, diff --git a/evm_loader/lib/src/tracing/tracers/struct_logger.rs b/evm_loader/lib/src/tracing/tracers/struct_logger.rs index e704b742d..a842557f6 100644 --- a/evm_loader/lib/src/tracing/tracers/struct_logger.rs +++ b/evm_loader/lib/src/tracing/tracers/struct_logger.rs @@ -4,11 +4,11 @@ use ethnum::U256; use evm_loader::evm::ExitStatus; use serde::Serialize; use serde_json::Value; +use web3::types::Bytes; use crate::tracing::TraceConfig; use evm_loader::evm::opcode_table::OPNAMES; use evm_loader::evm::tracing::{Event, EventListener}; -use evm_loader::types::hexbytes::HexBytes; /// `StructLoggerResult` groups all structured logs emitted by the EVM /// while replaying a transaction in debug mode as well as transaction @@ -49,7 +49,7 @@ pub struct StructLog { #[serde(skip_serializing_if = "Option::is_none")] stack: Option>, #[serde(skip_serializing_if = "Option::is_none")] - return_data: Option, + return_data: Option, /// Snapshot of the current memory sate #[serde(skip_serializing_if = "Option::is_none")] memory: Option>, // chunks of 32 bytes diff --git a/evm_loader/program/src/types/hexbytes.rs b/evm_loader/program/src/types/hexbytes.rs deleted file mode 100644 index 60601beb2..000000000 --- a/evm_loader/program/src/types/hexbytes.rs +++ /dev/null @@ -1,90 +0,0 @@ -use hex::FromHex; -use serde::de::Visitor; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; -use std::fmt; -use std::ops::Deref; - -/// TODO Maybe replace with #[serde(with = "hex")], but pay attention to "0x" prefix missing from "hex" serialization -/// Wrapper structure around vector of bytes. -#[derive(Debug, PartialEq, Eq, Default, Hash, Clone)] -pub struct HexBytes(pub Vec); - -impl HexBytes { - /// Simple constructor. - #[must_use] - pub fn new(bytes: Vec) -> HexBytes { - HexBytes(bytes) - } -} - -impl Deref for HexBytes { - type Target = Vec; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl From> for HexBytes { - fn from(bytes: Vec) -> HexBytes { - HexBytes(bytes) - } -} - -impl From for Vec { - fn from(value: HexBytes) -> Self { - value.0 - } -} - -impl Serialize for HexBytes { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let mut value = "0x".to_owned(); - value.push_str(hex::encode(&self.0).as_str()); - serializer.serialize_str(value.as_ref()) - } -} - -impl<'a> Deserialize<'a> for HexBytes { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'a>, - { - deserializer.deserialize_any(BytesVisitor) - } -} - -struct BytesVisitor; - -impl<'a> Visitor<'a> for BytesVisitor { - type Value = HexBytes; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - write!(formatter, "a 0x-prefixed, hex-encoded vector of bytes") - } - - fn visit_str(self, value: &str) -> Result - where - E: serde::de::Error, - { - if value.len() >= 2 && value.starts_with("0x") && value.len() & 1 == 0 { - Ok(HexBytes::new(FromHex::from_hex(&value[2..]).map_err( - |e| serde::de::Error::custom(format!("Invalid hex: {e}")), - )?)) - } else { - Err(serde::de::Error::custom( - "Invalid bytes format. Expected a 0x-prefixed hex string with even length", - )) - } - } - - fn visit_string(self, value: String) -> Result - where - E: serde::de::Error, - { - self.visit_str(value.as_ref()) - } -} diff --git a/evm_loader/program/src/types/mod.rs b/evm_loader/program/src/types/mod.rs index 06000d18f..04afe313f 100644 --- a/evm_loader/program/src/types/mod.rs +++ b/evm_loader/program/src/types/mod.rs @@ -6,6 +6,4 @@ pub use transaction::Transaction; pub use transaction::TransactionPayload; mod address; -#[cfg(not(target_os = "solana"))] -pub mod hexbytes; mod transaction; From 2b0b7aed4b4967d4b30c2d057f5b49f50e6bfd83 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Wed, 13 Dec 2023 08:34:58 +0200 Subject: [PATCH 078/318] NDEV-2441: Remove type parameter duplication in precompile_extension module (#247) * NDEV-2441: Convert functions to methods in metaplex module * NDEV-2441: Convert metaplex function to method * NDEV-2441: Merge impl blocks in metaplex * NDEV-2441: Convert functions to methods in neon_token module * NDEV-2441: Convert functions to methods in query_account module * NDEV-2441: Convert functions to methods in spl_token * NDEV-2441: Convert spl_token function to method * NDEV-2441: Merge impl blocks in spl_token --- .../executor/precompile_extension/metaplex.rs | 480 +++--- .../src/executor/precompile_extension/mod.rs | 10 +- .../precompile_extension/neon_token.rs | 204 +-- .../precompile_extension/query_account.rs | 357 +++-- .../precompile_extension/spl_token.rs | 1293 ++++++++--------- 5 files changed, 1154 insertions(+), 1190 deletions(-) diff --git a/evm_loader/program/src/executor/precompile_extension/metaplex.rs b/evm_loader/program/src/executor/precompile_extension/metaplex.rs index b0fc2626d..aaca012ee 100644 --- a/evm_loader/program/src/executor/precompile_extension/metaplex.rs +++ b/evm_loader/program/src/executor/precompile_extension/metaplex.rs @@ -25,81 +25,6 @@ use crate::{ // "[0x69, 0x1f, 0x34, 0x31]": "name(bytes32)" // "[0x6b, 0xaa, 0x03, 0x30]": "symbol(bytes32)" -#[maybe_async] -pub async fn metaplex( - state: &mut ExecutorState<'_, B>, - address: &Address, - input: &[u8], - context: &crate::evm::Context, - is_static: bool, -) -> Result> { - if context.value != 0 { - return Err(Error::Custom("Metaplex: value != 0".to_string())); - } - - if &context.contract != address { - return Err(Error::Custom( - "Metaplex: callcode or delegatecall is not allowed".to_string(), - )); - } - - let (selector, input) = input.split_at(4); - let selector: [u8; 4] = selector.try_into()?; - - match selector { - [0xc5, 0x73, 0x50, 0xc6] => { - // "createMetadata(bytes32,string,string,string)" - if is_static { - return Err(Error::StaticModeViolation(*address)); - } - - let mint = read_pubkey(input)?; - let name = read_string(input, 32, 256)?; - let symbol = read_string(input, 64, 256)?; - let uri = read_string(input, 96, 1024)?; - - create_metadata(context, state, mint, name, symbol, uri) - } - [0x4a, 0xe8, 0xb6, 0x6b] => { - // "createMasterEdition(bytes32,uint64)" - if is_static { - return Err(Error::StaticModeViolation(*address)); - } - - let mint = read_pubkey(input)?; - let max_supply = read_u64(&input[32..])?; - - create_master_edition(context, state, mint, Some(max_supply)) - } - [0xf7, 0xb6, 0x37, 0xbb] => { - // "isInitialized(bytes32)" - let mint = read_pubkey(input)?; - is_initialized(context, state, mint).await - } - [0x23, 0x5b, 0x2b, 0x94] => { - // "isNFT(bytes32)" - let mint = read_pubkey(input)?; - is_nft(context, state, mint).await - } - [0x9e, 0xd1, 0x9d, 0xdb] => { - // "uri(bytes32)" - let mint = read_pubkey(input)?; - uri(context, state, mint).await - } - [0x69, 0x1f, 0x34, 0x31] => { - // "name(bytes32)" - let mint = read_pubkey(input)?; - token_name(context, state, mint).await - } - [0x6b, 0xaa, 0x03, 0x30] => { - // "symbol(bytes32)" - let mint = read_pubkey(input)?; - symbol(context, state, mint).await - } - _ => Err(Error::UnknownPrecompileMethodSelector(*address, selector)), - } -} - #[inline] fn read_u64(input: &[u8]) -> Result { if input.len() < 32 { @@ -143,184 +68,249 @@ fn read_string(input: &[u8], offset_position: usize, max_length: usize) -> Resul String::from_utf8(data).map_err(|_| Error::Custom("Invalid utf8 string".to_string())) } -fn create_metadata( - context: &crate::evm::Context, - state: &mut ExecutorState, - mint: Pubkey, - name: String, - symbol: String, - uri: String, -) -> Result> { - let signer = context.caller; - let (signer_pubkey, bump_seed) = state.backend.contract_pubkey(signer); - - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], - ]; - - let (metadata_pubkey, _) = mpl_token_metadata::pda::find_metadata_account(&mint); - - let instruction = mpl_token_metadata::instruction::create_metadata_accounts_v3( - mpl_token_metadata::ID, - metadata_pubkey, - mint, - signer_pubkey, - state.backend.operator(), - signer_pubkey, - name, - symbol, - uri, - Some(vec![ - Creator { - address: *state.backend.program_id(), - verified: false, - share: 0, - }, - Creator { - address: signer_pubkey, - verified: true, - share: 100, - }, - ]), - 0, // Seller Fee - true, // Update Authority == Mint Authority - false, // Is Mutable - None, // Collection - None, // Uses - None, // Collection Details - ); - - let rent = Rent::get()?; - let fee = rent.minimum_balance(MAX_METADATA_LEN) + CREATE_FEE; - - state.queue_external_instruction(instruction, seeds, fee); - - Ok(metadata_pubkey.to_bytes().to_vec()) -} +impl ExecutorState<'_, B> { + #[maybe_async] + pub async fn metaplex( + &mut self, + address: &Address, + input: &[u8], + context: &crate::evm::Context, + is_static: bool, + ) -> Result> { + if context.value != 0 { + return Err(Error::Custom("Metaplex: value != 0".to_string())); + } -fn create_master_edition( - context: &crate::evm::Context, - state: &mut ExecutorState, - mint: Pubkey, - max_supply: Option, -) -> Result> { - let signer = context.caller; - let (signer_pubkey, bump_seed) = state.backend.contract_pubkey(signer); - - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], - ]; - - let (metadata_pubkey, _) = mpl_token_metadata::pda::find_metadata_account(&mint); - let (edition_pubkey, _) = mpl_token_metadata::pda::find_master_edition_account(&mint); - - let instruction = mpl_token_metadata::instruction::create_master_edition_v3( - mpl_token_metadata::ID, - edition_pubkey, - mint, - signer_pubkey, - signer_pubkey, - metadata_pubkey, - state.backend.operator(), - max_supply, - ); - - let rent = Rent::get()?; - let fee = rent.minimum_balance(MAX_MASTER_EDITION_LEN) + CREATE_FEE; - - state.queue_external_instruction(instruction, seeds, fee); - - Ok(edition_pubkey.to_bytes().to_vec()) -} + if &context.contract != address { + return Err(Error::Custom( + "Metaplex: callcode or delegatecall is not allowed".to_string(), + )); + } -#[maybe_async] -async fn is_initialized( - context: &crate::evm::Context, - state: &mut ExecutorState<'_, B>, - mint: Pubkey, -) -> Result> { - let is_initialized = metadata(context, state, mint) - .await? - .map_or_else(|| false, |_| true); - - Ok(to_solidity_bool(is_initialized)) -} + let (selector, input) = input.split_at(4); + let selector: [u8; 4] = selector.try_into()?; -#[maybe_async] -async fn is_nft( - context: &crate::evm::Context, - state: &mut ExecutorState<'_, B>, - mint: Pubkey, -) -> Result> { - let is_nft = metadata(context, state, mint).await?.map_or_else( - || false, - |m| m.token_standard == Some(TokenStandard::NonFungible), - ); - - Ok(to_solidity_bool(is_nft)) -} + match selector { + [0xc5, 0x73, 0x50, 0xc6] => { + // "createMetadata(bytes32,string,string,string)" + if is_static { + return Err(Error::StaticModeViolation(*address)); + } -#[maybe_async] -async fn uri( - context: &crate::evm::Context, - state: &mut ExecutorState<'_, B>, - mint: Pubkey, -) -> Result> { - let uri = metadata(context, state, mint) - .await? - .map_or_else(String::new, |m| m.data.uri); - - Ok(to_solidity_string(uri.trim_end_matches('\0'))) -} + let mint = read_pubkey(input)?; + let name = read_string(input, 32, 256)?; + let symbol = read_string(input, 64, 256)?; + let uri = read_string(input, 96, 1024)?; -#[maybe_async] -async fn token_name( - context: &crate::evm::Context, - state: &mut ExecutorState<'_, B>, - mint: Pubkey, -) -> Result> { - let token_name = metadata(context, state, mint) - .await? - .map_or_else(String::new, |m| m.data.name); - - Ok(to_solidity_string(token_name.trim_end_matches('\0'))) -} + self.create_metadata(context, mint, name, symbol, uri) + } + [0x4a, 0xe8, 0xb6, 0x6b] => { + // "createMasterEdition(bytes32,uint64)" + if is_static { + return Err(Error::StaticModeViolation(*address)); + } -#[maybe_async] -async fn symbol( - context: &crate::evm::Context, - state: &mut ExecutorState<'_, B>, - mint: Pubkey, -) -> Result> { - let symbol = metadata(context, state, mint) - .await? - .map_or_else(String::new, |m| m.data.symbol); - - Ok(to_solidity_string(symbol.trim_end_matches('\0'))) -} + let mint = read_pubkey(input)?; + let max_supply = read_u64(&input[32..])?; -#[maybe_async] -async fn metadata( - _context: &crate::evm::Context, - state: &mut ExecutorState<'_, B>, - mint: Pubkey, -) -> Result> { - let (metadata_pubkey, _) = mpl_token_metadata::pda::find_metadata_account(&mint); - let metadata_account = state.external_account(metadata_pubkey).await?; - - let result = { - if mpl_token_metadata::check_id(&metadata_account.owner) { - let metadata = Metadata::safe_deserialize(&metadata_account.data); - metadata.ok() - } else { - None + self.create_master_edition(context, mint, Some(max_supply)) + } + [0xf7, 0xb6, 0x37, 0xbb] => { + // "isInitialized(bytes32)" + let mint = read_pubkey(input)?; + self.is_initialized(context, mint).await + } + [0x23, 0x5b, 0x2b, 0x94] => { + // "isNFT(bytes32)" + let mint = read_pubkey(input)?; + self.is_nft(context, mint).await + } + [0x9e, 0xd1, 0x9d, 0xdb] => { + // "uri(bytes32)" + let mint = read_pubkey(input)?; + self.uri(context, mint).await + } + [0x69, 0x1f, 0x34, 0x31] => { + // "name(bytes32)" + let mint = read_pubkey(input)?; + self.token_name(context, mint).await + } + [0x6b, 0xaa, 0x03, 0x30] => { + // "symbol(bytes32)" + let mint = read_pubkey(input)?; + self.symbol(context, mint).await + } + _ => Err(Error::UnknownPrecompileMethodSelector(*address, selector)), } - }; - Ok(result) + } + + fn create_metadata( + &mut self, + context: &crate::evm::Context, + mint: Pubkey, + name: String, + symbol: String, + uri: String, + ) -> Result> { + let signer = context.caller; + let (signer_pubkey, bump_seed) = self.backend.contract_pubkey(signer); + + let seeds = vec![ + vec![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vec(), + vec![bump_seed], + ]; + + let (metadata_pubkey, _) = mpl_token_metadata::pda::find_metadata_account(&mint); + + let instruction = mpl_token_metadata::instruction::create_metadata_accounts_v3( + mpl_token_metadata::ID, + metadata_pubkey, + mint, + signer_pubkey, + self.backend.operator(), + signer_pubkey, + name, + symbol, + uri, + Some(vec![ + Creator { + address: *self.backend.program_id(), + verified: false, + share: 0, + }, + Creator { + address: signer_pubkey, + verified: true, + share: 100, + }, + ]), + 0, // Seller Fee + true, // Update Authority == Mint Authority + false, // Is Mutable + None, // Collection + None, // Uses + None, // Collection Details + ); + + let rent = Rent::get()?; + let fee = rent.minimum_balance(MAX_METADATA_LEN) + CREATE_FEE; + + self.queue_external_instruction(instruction, seeds, fee); + + Ok(metadata_pubkey.to_bytes().to_vec()) + } + + fn create_master_edition( + &mut self, + context: &crate::evm::Context, + mint: Pubkey, + max_supply: Option, + ) -> Result> { + let signer = context.caller; + let (signer_pubkey, bump_seed) = self.backend.contract_pubkey(signer); + + let seeds = vec![ + vec![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vec(), + vec![bump_seed], + ]; + + let (metadata_pubkey, _) = mpl_token_metadata::pda::find_metadata_account(&mint); + let (edition_pubkey, _) = mpl_token_metadata::pda::find_master_edition_account(&mint); + + let instruction = mpl_token_metadata::instruction::create_master_edition_v3( + mpl_token_metadata::ID, + edition_pubkey, + mint, + signer_pubkey, + signer_pubkey, + metadata_pubkey, + self.backend.operator(), + max_supply, + ); + + let rent = Rent::get()?; + let fee = rent.minimum_balance(MAX_MASTER_EDITION_LEN) + CREATE_FEE; + + self.queue_external_instruction(instruction, seeds, fee); + + Ok(edition_pubkey.to_bytes().to_vec()) + } + + #[maybe_async] + async fn is_initialized( + &mut self, + context: &crate::evm::Context, + mint: Pubkey, + ) -> Result> { + let is_initialized = self + .metadata(context, mint) + .await? + .map_or_else(|| false, |_| true); + + Ok(to_solidity_bool(is_initialized)) + } + + #[maybe_async] + async fn is_nft(&mut self, context: &crate::evm::Context, mint: Pubkey) -> Result> { + let is_nft = self.metadata(context, mint).await?.map_or_else( + || false, + |m| m.token_standard == Some(TokenStandard::NonFungible), + ); + + Ok(to_solidity_bool(is_nft)) + } + + #[maybe_async] + async fn uri(&mut self, context: &crate::evm::Context, mint: Pubkey) -> Result> { + let uri = self + .metadata(context, mint) + .await? + .map_or_else(String::new, |m| m.data.uri); + + Ok(to_solidity_string(uri.trim_end_matches('\0'))) + } + + #[maybe_async] + async fn token_name(&mut self, context: &crate::evm::Context, mint: Pubkey) -> Result> { + let token_name = self + .metadata(context, mint) + .await? + .map_or_else(String::new, |m| m.data.name); + + Ok(to_solidity_string(token_name.trim_end_matches('\0'))) + } + + #[maybe_async] + async fn symbol(&mut self, context: &crate::evm::Context, mint: Pubkey) -> Result> { + let symbol = self + .metadata(context, mint) + .await? + .map_or_else(String::new, |m| m.data.symbol); + + Ok(to_solidity_string(symbol.trim_end_matches('\0'))) + } + + #[maybe_async] + async fn metadata( + &mut self, + _context: &crate::evm::Context, + mint: Pubkey, + ) -> Result> { + let (metadata_pubkey, _) = mpl_token_metadata::pda::find_metadata_account(&mint); + let metadata_account = self.external_account(metadata_pubkey).await?; + + let result = { + if mpl_token_metadata::check_id(&metadata_account.owner) { + let metadata = Metadata::safe_deserialize(&metadata_account.data); + metadata.ok() + } else { + None + } + }; + Ok(result) + } } fn to_solidity_bool(v: bool) -> Vec { diff --git a/evm_loader/program/src/executor/precompile_extension/mod.rs b/evm_loader/program/src/executor/precompile_extension/mod.rs index 3936615b0..0d9eb91bd 100644 --- a/evm_loader/program/src/executor/precompile_extension/mod.rs +++ b/evm_loader/program/src/executor/precompile_extension/mod.rs @@ -8,7 +8,7 @@ mod neon_token; mod query_account; mod spl_token; -impl<'a, B: AccountStorage> ExecutorState<'a, B> { +impl ExecutorState<'_, B> { #[deprecated] const _SYSTEM_ACCOUNT_ERC20_WRAPPER: Address = Address([ 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01, @@ -45,16 +45,16 @@ impl<'a, B: AccountStorage> ExecutorState<'a, B> { ) -> Option>> { match *address { Self::SYSTEM_ACCOUNT_QUERY => { - Some(query_account::query_account(self, address, input, context, is_static).await) + Some(self.query_account(address, input, context, is_static).await) } Self::SYSTEM_ACCOUNT_NEON_TOKEN => { - Some(neon_token::neon_token(self, address, input, context, is_static).await) + Some(self.neon_token(address, input, context, is_static).await) } Self::SYSTEM_ACCOUNT_SPL_TOKEN => { - Some(spl_token::spl_token(self, address, input, context, is_static).await) + Some(self.spl_token(address, input, context, is_static).await) } Self::SYSTEM_ACCOUNT_METAPLEX => { - Some(metaplex::metaplex(self, address, input, context, is_static).await) + Some(self.metaplex(address, input, context, is_static).await) } _ => None, } diff --git a/evm_loader/program/src/executor/precompile_extension/neon_token.rs b/evm_loader/program/src/executor/precompile_extension/neon_token.rs index d1bafe6b5..31f6c2d70 100644 --- a/evm_loader/program/src/executor/precompile_extension/neon_token.rs +++ b/evm_loader/program/src/executor/precompile_extension/neon_token.rs @@ -22,124 +22,126 @@ use crate::{ //-------------------------------------------------- const NEON_TOKEN_METHOD_WITHDRAW_ID: &[u8; 4] = &[0x8e, 0x19, 0x89, 0x9e]; -#[maybe_async] -pub async fn neon_token( - state: &mut ExecutorState<'_, B>, - address: &Address, - input: &[u8], - context: &crate::evm::Context, - is_static: bool, -) -> Result> { - debug_print!("neon_token({})", hex::encode(input)); - - if &context.contract != address { - return Err(Error::Custom( - "Withdraw: callcode or delegatecall is not allowed".to_string(), - )); - } - - let (method_id, rest) = input.split_at(4); - let method_id: &[u8; 4] = method_id.try_into().unwrap_or(&[0_u8; 4]); - - if method_id == NEON_TOKEN_METHOD_WITHDRAW_ID { - if is_static { - return Err(Error::StaticModeViolation(*address)); +impl ExecutorState<'_, B> { + #[maybe_async] + pub async fn neon_token( + &mut self, + address: &Address, + input: &[u8], + context: &crate::evm::Context, + is_static: bool, + ) -> Result> { + debug_print!("neon_token({})", hex::encode(input)); + + if &context.contract != address { + return Err(Error::Custom( + "Withdraw: callcode or delegatecall is not allowed".to_string(), + )); } - let source = context.contract; - let chain_id = context.contract_chain_id; - let value = context.value; - // owner of the associated token account - let destination = array_ref![rest, 0, 32]; - let destination = Pubkey::new_from_array(*destination); + let (method_id, rest) = input.split_at(4); + let method_id: &[u8; 4] = method_id.try_into().unwrap_or(&[0_u8; 4]); - withdraw(state, source, chain_id, destination, value).await?; + if method_id == NEON_TOKEN_METHOD_WITHDRAW_ID { + if is_static { + return Err(Error::StaticModeViolation(*address)); + } - let mut output = vec![0_u8; 32]; - output[31] = 1; // return true + let source = context.contract; + let chain_id = context.contract_chain_id; + let value = context.value; + // owner of the associated token account + let destination = array_ref![rest, 0, 32]; + let destination = Pubkey::new_from_array(*destination); - return Ok(output); - }; + self.withdraw(source, chain_id, destination, value).await?; - debug_print!("neon_token UNKNOWN"); - Err(Error::UnknownPrecompileMethodSelector(*address, *method_id)) -} + let mut output = vec![0_u8; 32]; + output[31] = 1; // return true + + return Ok(output); + }; -#[maybe_async] -async fn withdraw( - state: &mut ExecutorState<'_, B>, - source: Address, - chain_id: u64, - target: Pubkey, - value: U256, -) -> Result<()> { - if value == 0 { - return Err(Error::Custom("Neon Withdraw: value == 0".to_string())); + debug_print!("neon_token UNKNOWN"); + Err(Error::UnknownPrecompileMethodSelector(*address, *method_id)) } - let mint_address = state.backend.chain_id_to_token(chain_id); + #[maybe_async] + async fn withdraw( + &mut self, + source: Address, + chain_id: u64, + target: Pubkey, + value: U256, + ) -> Result<()> { + if value == 0 { + return Err(Error::Custom("Neon Withdraw: value == 0".to_string())); + } - let mut mint_account = state.external_account(mint_address).await?; - let mint_data = { - let info = mint_account.into_account_info(); - token::Mint::from_account(&info)?.into_data() - }; + let mint_address = self.backend.chain_id_to_token(chain_id); - assert!(mint_data.decimals < 18); + let mut mint_account = self.external_account(mint_address).await?; + let mint_data = { + let info = mint_account.into_account_info(); + token::Mint::from_account(&info)?.into_data() + }; - let additional_decimals: u32 = (18 - mint_data.decimals).into(); - let min_amount: u128 = u128::pow(10, additional_decimals); + assert!(mint_data.decimals < 18); - let spl_amount = value / min_amount; - let remainder = value % min_amount; + let additional_decimals: u32 = (18 - mint_data.decimals).into(); + let min_amount: u128 = u128::pow(10, additional_decimals); - if spl_amount > U256::from(u64::MAX) { - return Err(Error::Custom( - "Neon Withdraw: value exceeds u64::max".to_string(), - )); - } + let spl_amount = value / min_amount; + let remainder = value % min_amount; - if remainder != 0 { - return Err(Error::Custom(std::format!( - "Neon Withdraw: value must be divisible by 10^{additional_decimals}" - ))); - } + if spl_amount > U256::from(u64::MAX) { + return Err(Error::Custom( + "Neon Withdraw: value exceeds u64::max".to_string(), + )); + } - let target_token = get_associated_token_address(&target, &mint_address); - let account = state.external_account(target_token).await?; - if !spl_token::check_id(&account.owner) { - use spl_associated_token_account::instruction::create_associated_token_account; + if remainder != 0 { + return Err(Error::Custom(std::format!( + "Neon Withdraw: value must be divisible by 10^{additional_decimals}" + ))); + } - let create_associated = create_associated_token_account( - &state.backend.operator(), - &target, - &mint_address, - &spl_token::ID, - ); + let target_token = get_associated_token_address(&target, &mint_address); + let account = self.external_account(target_token).await?; + if !spl_token::check_id(&account.owner) { + use spl_associated_token_account::instruction::create_associated_token_account; + + let create_associated = create_associated_token_account( + &self.backend.operator(), + &target, + &mint_address, + &spl_token::ID, + ); + + let rent = Rent::get()?; + let fee = rent.minimum_balance(spl_token::state::Account::LEN); + self.queue_external_instruction(create_associated, vec![], fee); + } - let rent = Rent::get()?; - let fee = rent.minimum_balance(spl_token::state::Account::LEN); - state.queue_external_instruction(create_associated, vec![], fee); - } + let (authority, bump_seed) = + Pubkey::find_program_address(&[b"Deposit"], self.backend.program_id()); + let pool = get_associated_token_address(&authority, &mint_address); - let (authority, bump_seed) = - Pubkey::find_program_address(&[b"Deposit"], state.backend.program_id()); - let pool = get_associated_token_address(&authority, &mint_address); - - let transfer = spl_token::instruction::transfer_checked( - &spl_token::ID, - &pool, - &mint_address, - &target_token, - &authority, - &[], - spl_amount.as_u64(), - mint_data.decimals, - )?; - let transfer_seeds = vec![b"Deposit".to_vec(), vec![bump_seed]]; - state.queue_external_instruction(transfer, transfer_seeds, 0); - - state.burn(source, chain_id, value); - - Ok(()) + let transfer = spl_token::instruction::transfer_checked( + &spl_token::ID, + &pool, + &mint_address, + &target_token, + &authority, + &[], + spl_amount.as_u64(), + mint_data.decimals, + )?; + let transfer_seeds = vec![b"Deposit".to_vec(), vec![bump_seed]]; + self.queue_external_instruction(transfer, transfer_seeds, 0); + + self.burn(source, chain_id, value); + + Ok(()) + } } diff --git a/evm_loader/program/src/executor/precompile_extension/query_account.rs b/evm_loader/program/src/executor/precompile_extension/query_account.rs index 37ae38f06..d08e97649 100644 --- a/evm_loader/program/src/executor/precompile_extension/query_account.rs +++ b/evm_loader/program/src/executor/precompile_extension/query_account.rs @@ -31,208 +31,191 @@ use crate::{ // "a9dbaf25": "length(bytes32)", // "7dd6c1a0": "data(bytes32,uint64,uint64)", -#[maybe_async] -pub async fn query_account( - state: &mut ExecutorState<'_, B>, - address: &Address, - input: &[u8], - context: &crate::evm::Context, - _is_static: bool, -) -> Result> { - debug_print!("query_account({})", hex::encode(input)); - - if context.value != 0 { - return Err(Error::Custom("Query Account: value != 0".to_string())); +impl ExecutorState<'_, B> { + #[maybe_async] + pub async fn query_account( + &mut self, + address: &Address, + input: &[u8], + context: &crate::evm::Context, + _is_static: bool, + ) -> Result> { + debug_print!("query_account({})", hex::encode(input)); + + if context.value != 0 { + return Err(Error::Custom("Query Account: value != 0".to_string())); + } + + let (method_id, rest) = input.split_at(4); + let method_id: [u8; 4] = method_id.try_into()?; + + let (account_address, rest) = rest.split_at(32); + let account_address = Pubkey::try_from(account_address)?; + + match method_id { + [0x2b, 0x3c, 0x83, 0x22] => { + // cache(uint256,uint64,uint64) + // deprecated + Ok(Vec::new()) + } + [0xa1, 0x23, 0xc3, 0x3e] | [0x02, 0x57, 0x1b, 0xe3] => { + debug_print!("query_account.owner({})", &account_address); + self.account_owner(&account_address).await + } + [0xaa, 0x8b, 0x99, 0xd2] | [0xa9, 0xdb, 0xaf, 0x25] => { + debug_print!("query_account.length({})", &account_address); + self.account_data_length(&account_address).await + } + [0x74, 0x8f, 0x2d, 0x8a] | [0x62, 0x73, 0x44, 0x8f] => { + debug_print!("query_account.lamports({})", &account_address); + self.account_lamports(&account_address).await + } + [0xc2, 0x19, 0xa7, 0x85] | [0xe6, 0xbe, 0xf4, 0x88] => { + debug_print!("query_account.executable({})", &account_address); + self.account_is_executable(&account_address).await + } + [0xc4, 0xd3, 0x69, 0xb5] | [0x8b, 0xb9, 0xe6, 0xf4] => { + debug_print!("query_account.rent_epoch({})", &account_address); + self.account_rent_epoch(&account_address).await + } + [0x43, 0xca, 0x51, 0x61] | [0x7d, 0xd6, 0xc1, 0xa0] => { + let arguments = array_ref![rest, 0, 64]; + let (offset, length) = array_refs!(arguments, 32, 32); + let offset = U256::from_be_bytes(*offset).try_into()?; + let length = U256::from_be_bytes(*length).try_into()?; + debug_print!( + "query_account.data({}, {}, {})", + account_address, + offset, + length + ); + self.account_data(&account_address, offset, length).await + } + [0xb6, 0x4a, 0x09, 0x7e] => { + debug_print!("query_account.info({})", &account_address); + self.account_info(&account_address).await + } + _ => { + debug_print!("query_account UNKNOWN {:?}", method_id); + Err(Error::UnknownPrecompileMethodSelector(*address, method_id)) + } + } } - let (method_id, rest) = input.split_at(4); - let method_id: [u8; 4] = method_id.try_into()?; + #[allow(clippy::unnecessary_wraps)] + #[maybe_async] + async fn account_owner(&mut self, address: &Pubkey) -> Result> { + let owner = self + .backend + .map_solana_account(address, |info| info.owner.to_bytes()) + .await; - let (account_address, rest) = rest.split_at(32); - let account_address = Pubkey::try_from(account_address)?; + Ok(owner.to_vec()) + } - match method_id { - [0x2b, 0x3c, 0x83, 0x22] => { - // cache(uint256,uint64,uint64) - // deprecated - Ok(Vec::new()) - } - [0xa1, 0x23, 0xc3, 0x3e] | [0x02, 0x57, 0x1b, 0xe3] => { - debug_print!("query_account.owner({})", &account_address); - account_owner(state, &account_address).await - } - [0xaa, 0x8b, 0x99, 0xd2] | [0xa9, 0xdb, 0xaf, 0x25] => { - debug_print!("query_account.length({})", &account_address); - account_data_length(state, &account_address).await - } - [0x74, 0x8f, 0x2d, 0x8a] | [0x62, 0x73, 0x44, 0x8f] => { - debug_print!("query_account.lamports({})", &account_address); - account_lamports(state, &account_address).await - } - [0xc2, 0x19, 0xa7, 0x85] | [0xe6, 0xbe, 0xf4, 0x88] => { - debug_print!("query_account.executable({})", &account_address); - account_is_executable(state, &account_address).await - } - [0xc4, 0xd3, 0x69, 0xb5] | [0x8b, 0xb9, 0xe6, 0xf4] => { - debug_print!("query_account.rent_epoch({})", &account_address); - account_rent_epoch(state, &account_address).await - } - [0x43, 0xca, 0x51, 0x61] | [0x7d, 0xd6, 0xc1, 0xa0] => { - let arguments = array_ref![rest, 0, 64]; - let (offset, length) = array_refs!(arguments, 32, 32); - let offset = U256::from_be_bytes(*offset).try_into()?; - let length = U256::from_be_bytes(*length).try_into()?; - debug_print!( - "query_account.data({}, {}, {})", - account_address, - offset, - length - ); - account_data(state, &account_address, offset, length).await - } - [0xb6, 0x4a, 0x09, 0x7e] => { - debug_print!("query_account.info({})", &account_address); - account_info(state, &account_address).await - } - _ => { - debug_print!("query_account UNKNOWN {:?}", method_id); - Err(Error::UnknownPrecompileMethodSelector(*address, method_id)) - } + #[allow(clippy::unnecessary_wraps)] + #[maybe_async] + async fn account_lamports(&mut self, address: &Pubkey) -> Result> { + let lamports: U256 = self + .backend + .map_solana_account(address, |info| **info.lamports.borrow()) + .await + .into(); + + let bytes = lamports.to_be_bytes().to_vec(); + + Ok(bytes) } -} -#[allow(clippy::unnecessary_wraps)] -#[maybe_async] -async fn account_owner( - state: &mut ExecutorState<'_, B>, - address: &Pubkey, -) -> Result> { - let owner = state - .backend - .map_solana_account(address, |info| info.owner.to_bytes()) - .await; - - Ok(owner.to_vec()) -} + #[allow(clippy::unnecessary_wraps)] + #[maybe_async] + async fn account_rent_epoch(&mut self, address: &Pubkey) -> Result> { + let epoch: U256 = self + .backend + .map_solana_account(address, |info| info.rent_epoch) + .await + .into(); -#[allow(clippy::unnecessary_wraps)] -#[maybe_async] -async fn account_lamports( - state: &mut ExecutorState<'_, B>, - address: &Pubkey, -) -> Result> { - let lamports: U256 = state - .backend - .map_solana_account(address, |info| **info.lamports.borrow()) - .await - .into(); - - let bytes = lamports.to_be_bytes().to_vec(); - - Ok(bytes) -} + let bytes = epoch.to_be_bytes().to_vec(); -#[allow(clippy::unnecessary_wraps)] -#[maybe_async] -async fn account_rent_epoch( - state: &mut ExecutorState<'_, B>, - address: &Pubkey, -) -> Result> { - let epoch: U256 = state - .backend - .map_solana_account(address, |info| info.rent_epoch) - .await - .into(); - - let bytes = epoch.to_be_bytes().to_vec(); - - Ok(bytes) -} + Ok(bytes) + } -#[allow(clippy::unnecessary_wraps)] -#[maybe_async] -async fn account_is_executable( - state: &mut ExecutorState<'_, B>, - address: &Pubkey, -) -> Result> { - let executable: U256 = state - .backend - .map_solana_account(address, |info| info.executable) - .await - .into(); - - let bytes = executable.to_be_bytes().to_vec(); - - Ok(bytes) -} + #[allow(clippy::unnecessary_wraps)] + #[maybe_async] + async fn account_is_executable(&mut self, address: &Pubkey) -> Result> { + let executable: U256 = self + .backend + .map_solana_account(address, |info| info.executable) + .await + .into(); -#[allow(clippy::unnecessary_wraps)] -#[maybe_async] -async fn account_data_length( - state: &mut ExecutorState<'_, B>, - address: &Pubkey, -) -> Result> { - let length: U256 = state - .backend - .map_solana_account(address, |info| info.data.borrow().len()) - .await - .try_into()?; - - let bytes = length.to_be_bytes().to_vec(); - - Ok(bytes) -} + let bytes = executable.to_be_bytes().to_vec(); -#[allow(clippy::unnecessary_wraps)] -#[maybe_async] -async fn account_data( - state: &mut ExecutorState<'_, B>, - address: &Pubkey, - offset: usize, - length: usize, -) -> Result> { - if length == 0 { - return Err(Error::Custom( - "Query Account: data() - length == 0".to_string(), - )); + Ok(bytes) } - state - .backend - .map_solana_account(address, |info| { - info.data - .borrow() - .get(offset..offset + length) - .map(<[u8]>::to_vec) - }) - .await - .ok_or_else(|| Error::Custom("Query Account: data() - out of bounds".to_string())) -} + #[allow(clippy::unnecessary_wraps)] + #[maybe_async] + async fn account_data_length(&mut self, address: &Pubkey) -> Result> { + let length: U256 = self + .backend + .map_solana_account(address, |info| info.data.borrow().len()) + .await + .try_into()?; + + let bytes = length.to_be_bytes().to_vec(); -#[allow(clippy::unnecessary_wraps)] -#[maybe_async] -async fn account_info( - state: &mut ExecutorState<'_, B>, - address: &Pubkey, -) -> Result> { - fn to_solidity_account_value(info: &AccountInfo) -> Vec { - let mut buffer = [0_u8; 5 * 32]; - let (key, _, lamports, owner, _, executable, _, rent_epoch) = - arrayref::mut_array_refs![&mut buffer, 32, 24, 8, 32, 31, 1, 24, 8]; - - *key = info.key.to_bytes(); - *lamports = info.lamports().to_be_bytes(); - *owner = info.owner.to_bytes(); - executable[0] = info.executable.into(); - *rent_epoch = info.rent_epoch.to_be_bytes(); - - buffer.to_vec() + Ok(bytes) } - let info = state - .backend - .map_solana_account(address, to_solidity_account_value) - .await; + #[allow(clippy::unnecessary_wraps)] + #[maybe_async] + async fn account_data( + &mut self, + address: &Pubkey, + offset: usize, + length: usize, + ) -> Result> { + if length == 0 { + return Err(Error::Custom( + "Query Account: data() - length == 0".to_string(), + )); + } + + self.backend + .map_solana_account(address, |info| { + info.data + .borrow() + .get(offset..offset + length) + .map(<[u8]>::to_vec) + }) + .await + .ok_or_else(|| Error::Custom("Query Account: data() - out of bounds".to_string())) + } - Ok(info) + #[allow(clippy::unnecessary_wraps)] + #[maybe_async] + async fn account_info(&mut self, address: &Pubkey) -> Result> { + fn to_solidity_account_value(info: &AccountInfo) -> Vec { + let mut buffer = [0_u8; 5 * 32]; + let (key, _, lamports, owner, _, executable, _, rent_epoch) = + arrayref::mut_array_refs![&mut buffer, 32, 24, 8, 32, 31, 1, 24, 8]; + + *key = info.key.to_bytes(); + *lamports = info.lamports().to_be_bytes(); + *owner = info.owner.to_bytes(); + executable[0] = info.executable.into(); + *rent_epoch = info.rent_epoch.to_be_bytes(); + + buffer.to_vec() + } + + let info = self + .backend + .map_solana_account(address, to_solidity_account_value) + .await; + + Ok(info) + } } diff --git a/evm_loader/program/src/executor/precompile_extension/spl_token.rs b/evm_loader/program/src/executor/precompile_extension/spl_token.rs index 86348d42c..39ca0b34e 100644 --- a/evm_loader/program/src/executor/precompile_extension/spl_token.rs +++ b/evm_loader/program/src/executor/precompile_extension/spl_token.rs @@ -33,201 +33,6 @@ use crate::{ // [0x78, 0x42, 0x3b, 0xcf] : "transfer(bytes32,bytes32,uint64)" // [0x7c, 0x0e, 0xb8, 0x10] : "transferWithSeed(bytes32,bytes32,bytes32,uint64)" -#[allow(clippy::too_many_lines)] -#[maybe_async] -pub async fn spl_token( - state: &mut ExecutorState<'_, B>, - address: &Address, - input: &[u8], - context: &crate::evm::Context, - is_static: bool, -) -> Result> { - if context.value != 0 { - return Err(Error::Custom("SplToken: value != 0".to_string())); - } - - if &context.contract != address { - return Err(Error::Custom( - "SplToken: callcode or delegatecall is not allowed".to_string(), - )); - } - - let (selector, input) = input.split_at(4); - let selector: [u8; 4] = selector.try_into()?; - - match selector { - [0xb1, 0x1e, 0xcc, 0x50] => { - // initializeMint(bytes32 seed, uint8 decimals) - if is_static { - return Err(Error::StaticModeViolation(*address)); - } - - let seed = read_salt(input)?; - let decimals = read_u8(&input[32..])?; - - initialize_mint(context, state, seed, decimals, None, None).await - } - [0xc3, 0xf3, 0xf2, 0xf2] => { - // initializeMint(bytes32 seed, uint8 decimals, bytes32 mint_authority, bytes32 freeze_authority) - if is_static { - return Err(Error::StaticModeViolation(*address)); - } - - let seed = read_salt(input)?; - let decimals = read_u8(&input[32..])?; - let mint_authority = read_pubkey(&input[64..])?; - let freeze_authority = read_pubkey(&input[96..])?; - initialize_mint( - context, - state, - seed, - decimals, - Some(mint_authority), - Some(freeze_authority), - ) - .await - } - [0xda, 0xa1, 0x2c, 0x5c] => { - // initializeAccount(bytes32 seed, bytes32 mint) - if is_static { - return Err(Error::StaticModeViolation(*address)); - } - - let seed = read_salt(input)?; - let mint = read_pubkey(&input[32..])?; - - initialize_account(context, state, seed, mint, None).await - } - [0xfc, 0x86, 0xb7, 0x17] => { - // initializeAccount(bytes32 seed, bytes32 mint, bytes32 owner) - if is_static { - return Err(Error::StaticModeViolation(*address)); - } - - let seed = read_salt(input)?; - let mint = read_pubkey(&input[32..])?; - let owner = read_pubkey(&input[64..])?; - initialize_account(context, state, seed, mint, Some(owner)).await - } - [0x57, 0x82, 0xa0, 0x43] => { - // closeAccount(bytes32 account) - if is_static { - return Err(Error::StaticModeViolation(*address)); - } - - let account = read_pubkey(input)?; - close_account(context, state, account) - } - [0xa9, 0xc1, 0x58, 0x06] => { - // approve(bytes32 source, bytes32 target, uint64 amount) - if is_static { - return Err(Error::StaticModeViolation(*address)); - } - - let source = read_pubkey(input)?; - let target = read_pubkey(&input[32..])?; - let amount = read_u64(&input[64..])?; - approve(context, state, source, target, amount) - } - [0xb7, 0x5c, 0x7d, 0xc6] => { - // revoke(bytes32 source) - if is_static { - return Err(Error::StaticModeViolation(*address)); - } - - let source = read_pubkey(input)?; - revoke(context, state, source) - } - [0x78, 0x42, 0x3b, 0xcf] => { - // transfer(bytes32 source, bytes32 target, uint64 amount) - if is_static { - return Err(Error::StaticModeViolation(*address)); - } - - let source = read_pubkey(input)?; - let target = read_pubkey(&input[32..])?; - let amount = read_u64(&input[64..])?; - transfer(context, state, source, target, amount) - } - [0x7c, 0x0e, 0xb8, 0x10] => { - // transferWithSeed(bytes32,bytes32,bytes32,uint64) - if is_static { - return Err(Error::StaticModeViolation(*address)); - } - - let seed = read_salt(input)?; - let source = read_pubkey(&input[32..])?; - let target = read_pubkey(&input[64..])?; - let amount = read_u64(&input[96..])?; - - transfer_with_seed(context, state, seed, source, target, amount) - } - [0xc9, 0xd0, 0xe2, 0xfd] => { - // mintTo(bytes32 mint, bytes32 account, uint64 amount) - if is_static { - return Err(Error::StaticModeViolation(*address)); - } - - let mint = read_pubkey(input)?; - let account = read_pubkey(&input[32..])?; - let amount = read_u64(&input[64..])?; - mint_to(context, state, mint, account, amount) - } - [0xc0, 0x67, 0xee, 0xbb] => { - // burn(bytes32 mint, bytes32 account, uint64 amount) - if is_static { - return Err(Error::StaticModeViolation(*address)); - } - - let mint = read_pubkey(input)?; - let account = read_pubkey(&input[32..])?; - let amount = read_u64(&input[64..])?; - burn(context, state, mint, account, amount) - } - [0x44, 0xef, 0x32, 0x44] => { - // freeze(bytes32 mint, bytes32 account) - if is_static { - return Err(Error::StaticModeViolation(*address)); - } - - let mint = read_pubkey(input)?; - let account = read_pubkey(&input[32..])?; - freeze(context, state, mint, account) - } - [0x3d, 0x71, 0x8c, 0x9a] => { - // thaw(bytes32 mint, bytes32 account) - if is_static { - return Err(Error::StaticModeViolation(*address)); - } - - let mint = read_pubkey(input)?; - let account = read_pubkey(&input[32..])?; - thaw(context, state, mint, account) - } - [0xeb, 0x7d, 0xa7, 0x8c] => { - // findAccount(bytes32 seed) - let seed = read_salt(input)?; - find_account(context, state, seed) - } - [0x6d, 0xa9, 0xde, 0x75] => { - // isSystemAccount(bytes32 account) - let account = read_pubkey(input)?; - is_system_account(context, state, account).await - } - [0xd1, 0xde, 0x50, 0x11] => { - // getAccount(bytes32 account) - let account = read_pubkey(input)?; - get_account(context, state, account).await - } - [0xa2, 0xce, 0x9c, 0x1f] => { - // getMint(bytes32 account) - let account = read_pubkey(input)?; - get_mint(context, state, account).await - } - _ => Err(Error::UnknownPrecompileMethodSelector(*address, selector)), - } -} - #[inline] fn read_u8(input: &[u8]) -> Result { U256::from_be_bytes(*arrayref::array_ref![input, 0, 32]) @@ -258,492 +63,676 @@ fn read_salt(input: &[u8]) -> Result<&[u8; 32]> { Ok(arrayref::array_ref![input, 0, 32]) } -fn create_account( - state: &mut ExecutorState, - account: &OwnedAccountInfo, - space: usize, - seeds: Vec>, -) -> Result<()> { - let rent = Rent::get()?; - let minimum_balance = rent.minimum_balance(space); - - let required_lamports = minimum_balance.saturating_sub(account.lamports); - - if required_lamports > 0 { - let transfer = system_instruction::transfer( - &state.backend.operator(), - &account.key, - required_lamports, - ); - state.queue_external_instruction(transfer, vec![], required_lamports); - } +impl ExecutorState<'_, B> { + #[allow(clippy::too_many_lines)] + #[maybe_async] + pub async fn spl_token( + &mut self, + address: &Address, + input: &[u8], + context: &crate::evm::Context, + is_static: bool, + ) -> Result> { + if context.value != 0 { + return Err(Error::Custom("SplToken: value != 0".to_string())); + } - let allocate = system_instruction::allocate(&account.key, space.try_into().unwrap()); - state.queue_external_instruction(allocate, seeds.clone(), 0); + if &context.contract != address { + return Err(Error::Custom( + "SplToken: callcode or delegatecall is not allowed".to_string(), + )); + } - let assign = system_instruction::assign(&account.key, &spl_token::ID); - state.queue_external_instruction(assign, seeds, 0); + let (selector, input) = input.split_at(4); + let selector: [u8; 4] = selector.try_into()?; - Ok(()) -} + match selector { + [0xb1, 0x1e, 0xcc, 0x50] => { + // initializeMint(bytes32 seed, uint8 decimals) + if is_static { + return Err(Error::StaticModeViolation(*address)); + } -#[maybe_async] -async fn initialize_mint( - context: &crate::evm::Context, - state: &mut ExecutorState<'_, B>, - seed: &[u8], - decimals: u8, - mint_authority: Option, - freeze_authority: Option, -) -> Result> { - let signer = context.caller; - let (signer_pubkey, _) = state.backend.contract_pubkey(signer); - - let (mint_key, bump_seed) = Pubkey::find_program_address( - &[ - &[ACCOUNT_SEED_VERSION], - b"ContractData", - signer.as_bytes(), - seed, - ], - state.backend.program_id(), - ); + let seed = read_salt(input)?; + let decimals = read_u8(&input[32..])?; + + self.initialize_mint(context, seed, decimals, None, None) + .await + } + [0xc3, 0xf3, 0xf2, 0xf2] => { + // initializeMint(bytes32 seed, uint8 decimals, bytes32 mint_authority, bytes32 freeze_authority) + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let seed = read_salt(input)?; + let decimals = read_u8(&input[32..])?; + let mint_authority = read_pubkey(&input[64..])?; + let freeze_authority = read_pubkey(&input[96..])?; + self.initialize_mint( + context, + seed, + decimals, + Some(mint_authority), + Some(freeze_authority), + ) + .await + } + [0xda, 0xa1, 0x2c, 0x5c] => { + // initializeAccount(bytes32 seed, bytes32 mint) + if is_static { + return Err(Error::StaticModeViolation(*address)); + } - let account = state.external_account(mint_key).await?; - if !system_program::check_id(&account.owner) { - return Err(Error::AccountInvalidOwner(mint_key, system_program::ID)); + let seed = read_salt(input)?; + let mint = read_pubkey(&input[32..])?; + + self.initialize_account(context, seed, mint, None).await + } + [0xfc, 0x86, 0xb7, 0x17] => { + // initializeAccount(bytes32 seed, bytes32 mint, bytes32 owner) + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let seed = read_salt(input)?; + let mint = read_pubkey(&input[32..])?; + let owner = read_pubkey(&input[64..])?; + self.initialize_account(context, seed, mint, Some(owner)) + .await + } + [0x57, 0x82, 0xa0, 0x43] => { + // closeAccount(bytes32 account) + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let account = read_pubkey(input)?; + self.close_account(context, account) + } + [0xa9, 0xc1, 0x58, 0x06] => { + // approve(bytes32 source, bytes32 target, uint64 amount) + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let source = read_pubkey(input)?; + let target = read_pubkey(&input[32..])?; + let amount = read_u64(&input[64..])?; + self.approve(context, source, target, amount) + } + [0xb7, 0x5c, 0x7d, 0xc6] => { + // revoke(bytes32 source) + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let source = read_pubkey(input)?; + self.revoke(context, source) + } + [0x78, 0x42, 0x3b, 0xcf] => { + // transfer(bytes32 source, bytes32 target, uint64 amount) + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let source = read_pubkey(input)?; + let target = read_pubkey(&input[32..])?; + let amount = read_u64(&input[64..])?; + self.transfer(context, source, target, amount) + } + [0x7c, 0x0e, 0xb8, 0x10] => { + // transferWithSeed(bytes32,bytes32,bytes32,uint64) + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let seed = read_salt(input)?; + let source = read_pubkey(&input[32..])?; + let target = read_pubkey(&input[64..])?; + let amount = read_u64(&input[96..])?; + + self.transfer_with_seed(context, seed, source, target, amount) + } + [0xc9, 0xd0, 0xe2, 0xfd] => { + // mintTo(bytes32 mint, bytes32 account, uint64 amount) + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let mint = read_pubkey(input)?; + let account = read_pubkey(&input[32..])?; + let amount = read_u64(&input[64..])?; + self.mint_to(context, mint, account, amount) + } + [0xc0, 0x67, 0xee, 0xbb] => { + // burn(bytes32 mint, bytes32 account, uint64 amount) + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let mint = read_pubkey(input)?; + let account = read_pubkey(&input[32..])?; + let amount = read_u64(&input[64..])?; + self.burn_spl_token(context, mint, account, amount) + } + [0x44, 0xef, 0x32, 0x44] => { + // freeze(bytes32 mint, bytes32 account) + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let mint = read_pubkey(input)?; + let account = read_pubkey(&input[32..])?; + self.freeze(context, mint, account) + } + [0x3d, 0x71, 0x8c, 0x9a] => { + // thaw(bytes32 mint, bytes32 account) + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let mint = read_pubkey(input)?; + let account = read_pubkey(&input[32..])?; + self.thaw(context, mint, account) + } + [0xeb, 0x7d, 0xa7, 0x8c] => { + // findAccount(bytes32 seed) + let seed = read_salt(input)?; + self.find_account(context, seed) + } + [0x6d, 0xa9, 0xde, 0x75] => { + // isSystemAccount(bytes32 account) + let account = read_pubkey(input)?; + self.is_system_account(context, account).await + } + [0xd1, 0xde, 0x50, 0x11] => { + // getAccount(bytes32 account) + let account = read_pubkey(input)?; + self.get_account(context, account).await + } + [0xa2, 0xce, 0x9c, 0x1f] => { + // getMint(bytes32 account) + let account = read_pubkey(input)?; + self.get_mint(context, account).await + } + _ => Err(Error::UnknownPrecompileMethodSelector(*address, selector)), + } } - let seeds: Vec> = vec![ - vec![ACCOUNT_SEED_VERSION], - b"ContractData".to_vec(), - signer.as_bytes().to_vec(), - seed.to_vec(), - vec![bump_seed], - ]; - - create_account(state, &account, spl_token::state::Mint::LEN, seeds)?; - - let initialize_mint = spl_token::instruction::initialize_mint( - &spl_token::ID, - &mint_key, - &mint_authority.unwrap_or(signer_pubkey), - Some(&freeze_authority.unwrap_or(signer_pubkey)), - decimals, - )?; - state.queue_external_instruction(initialize_mint, vec![], 0); - - Ok(mint_key.to_bytes().to_vec()) -} + fn create_account( + &mut self, + account: &OwnedAccountInfo, + space: usize, + seeds: Vec>, + ) -> Result<()> { + let rent = Rent::get()?; + let minimum_balance = rent.minimum_balance(space); + + let required_lamports = minimum_balance.saturating_sub(account.lamports); + + if required_lamports > 0 { + let transfer = system_instruction::transfer( + &self.backend.operator(), + &account.key, + required_lamports, + ); + self.queue_external_instruction(transfer, vec![], required_lamports); + } -#[maybe_async] -async fn initialize_account( - context: &crate::evm::Context, - state: &mut ExecutorState<'_, B>, - seed: &[u8], - mint: Pubkey, - owner: Option, -) -> Result> { - let signer = context.caller; - let (signer_pubkey, _) = state.backend.contract_pubkey(signer); - - let (account_key, bump_seed) = Pubkey::find_program_address( - &[ - &[ACCOUNT_SEED_VERSION], - b"ContractData", - signer.as_bytes(), - seed, - ], - state.backend.program_id(), - ); + let allocate = system_instruction::allocate(&account.key, space.try_into().unwrap()); + self.queue_external_instruction(allocate, seeds.clone(), 0); - let account = state.external_account(account_key).await?; - if !system_program::check_id(&account.owner) { - return Err(Error::AccountInvalidOwner(account_key, system_program::ID)); - } + let assign = system_instruction::assign(&account.key, &spl_token::ID); + self.queue_external_instruction(assign, seeds, 0); - let seeds: Vec> = vec![ - vec![ACCOUNT_SEED_VERSION], - b"ContractData".to_vec(), - signer.as_bytes().to_vec(), - seed.to_vec(), - vec![bump_seed], - ]; - - create_account(state, &account, spl_token::state::Account::LEN, seeds)?; - - let initialize_mint = spl_token::instruction::initialize_account2( - &spl_token::ID, - &account_key, - &mint, - &owner.unwrap_or(signer_pubkey), - )?; - state.queue_external_instruction(initialize_mint, vec![], 0); - - Ok(account_key.to_bytes().to_vec()) -} + Ok(()) + } -fn close_account( - context: &crate::evm::Context, - state: &mut ExecutorState, - account: Pubkey, -) -> Result> { - let signer = context.caller; - let (signer_pubkey, bump_seed) = state.backend.contract_pubkey(signer); - - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], - ]; - - let close_account = spl_token::instruction::close_account( - &spl_token::ID, - &account, - &state.backend.operator(), - &signer_pubkey, - &[], - )?; - state.queue_external_instruction(close_account, seeds, 0); - - Ok(vec![]) -} + #[maybe_async] + async fn initialize_mint( + &mut self, + context: &crate::evm::Context, + seed: &[u8], + decimals: u8, + mint_authority: Option, + freeze_authority: Option, + ) -> Result> { + let signer = context.caller; + let (signer_pubkey, _) = self.backend.contract_pubkey(signer); + + let (mint_key, bump_seed) = Pubkey::find_program_address( + &[ + &[ACCOUNT_SEED_VERSION], + b"ContractData", + signer.as_bytes(), + seed, + ], + self.backend.program_id(), + ); -fn approve( - context: &crate::evm::Context, - state: &mut ExecutorState, - source: Pubkey, - target: Pubkey, - amount: u64, -) -> Result> { - let signer = context.caller; - let (signer_pubkey, bump_seed) = state.backend.contract_pubkey(signer); - - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], - ]; - - let approve = spl_token::instruction::approve( - &spl_token::ID, - &source, - &target, - &signer_pubkey, - &[], - amount, - )?; - state.queue_external_instruction(approve, seeds, 0); - - Ok(vec![]) -} + let account = self.external_account(mint_key).await?; + if !system_program::check_id(&account.owner) { + return Err(Error::AccountInvalidOwner(mint_key, system_program::ID)); + } -fn revoke( - context: &crate::evm::Context, - state: &mut ExecutorState, - account: Pubkey, -) -> Result> { - let signer = context.caller; - let (signer_pubkey, bump_seed) = state.backend.contract_pubkey(signer); + let seeds: Vec> = vec![ + vec![ACCOUNT_SEED_VERSION], + b"ContractData".to_vec(), + signer.as_bytes().to_vec(), + seed.to_vec(), + vec![bump_seed], + ]; + + self.create_account(&account, spl_token::state::Mint::LEN, seeds)?; + + let initialize_mint = spl_token::instruction::initialize_mint( + &spl_token::ID, + &mint_key, + &mint_authority.unwrap_or(signer_pubkey), + Some(&freeze_authority.unwrap_or(signer_pubkey)), + decimals, + )?; + self.queue_external_instruction(initialize_mint, vec![], 0); + + Ok(mint_key.to_bytes().to_vec()) + } - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], - ]; + #[maybe_async] + async fn initialize_account( + &mut self, + context: &crate::evm::Context, + seed: &[u8], + mint: Pubkey, + owner: Option, + ) -> Result> { + let signer = context.caller; + let (signer_pubkey, _) = self.backend.contract_pubkey(signer); + + let (account_key, bump_seed) = Pubkey::find_program_address( + &[ + &[ACCOUNT_SEED_VERSION], + b"ContractData", + signer.as_bytes(), + seed, + ], + self.backend.program_id(), + ); - let revoke = spl_token::instruction::revoke(&spl_token::ID, &account, &signer_pubkey, &[])?; - state.queue_external_instruction(revoke, seeds, 0); + let account = self.external_account(account_key).await?; + if !system_program::check_id(&account.owner) { + return Err(Error::AccountInvalidOwner(account_key, system_program::ID)); + } - Ok(vec![]) -} + let seeds: Vec> = vec![ + vec![ACCOUNT_SEED_VERSION], + b"ContractData".to_vec(), + signer.as_bytes().to_vec(), + seed.to_vec(), + vec![bump_seed], + ]; + + self.create_account(&account, spl_token::state::Account::LEN, seeds)?; + + let initialize_mint = spl_token::instruction::initialize_account2( + &spl_token::ID, + &account_key, + &mint, + &owner.unwrap_or(signer_pubkey), + )?; + self.queue_external_instruction(initialize_mint, vec![], 0); + + Ok(account_key.to_bytes().to_vec()) + } -fn transfer( - context: &crate::evm::Context, - state: &mut ExecutorState, - source: Pubkey, - target: Pubkey, - amount: u64, -) -> Result> { - let signer = context.caller; - let (signer_pubkey, bump_seed) = state.backend.contract_pubkey(signer); - - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], - ]; - - let transfer = spl_token::instruction::transfer( - &spl_token::ID, - &source, - &target, - &signer_pubkey, - &[], - amount, - )?; - state.queue_external_instruction(transfer, seeds, 0); - - Ok(vec![]) -} + fn close_account(&mut self, context: &crate::evm::Context, account: Pubkey) -> Result> { + let signer = context.caller; + let (signer_pubkey, bump_seed) = self.backend.contract_pubkey(signer); + + let seeds = vec![ + vec![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vec(), + vec![bump_seed], + ]; + + let close_account = spl_token::instruction::close_account( + &spl_token::ID, + &account, + &self.backend.operator(), + &signer_pubkey, + &[], + )?; + self.queue_external_instruction(close_account, seeds, 0); + + Ok(vec![]) + } -fn transfer_with_seed( - context: &crate::evm::Context, - state: &mut ExecutorState, - seed: &[u8; 32], - source: Pubkey, - target: Pubkey, - amount: u64, -) -> Result> { - let seeds: &[&[u8]] = &[ - &[ACCOUNT_SEED_VERSION], - b"AUTH", - context.caller.as_bytes(), - seed, - ]; - let (signer_pubkey, signer_seed) = - Pubkey::find_program_address(seeds, state.backend.program_id()); - - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - b"AUTH".to_vec(), - context.caller.as_bytes().to_vec(), - seed.to_vec(), - vec![signer_seed], - ]; - - let transfer = spl_token::instruction::transfer( - &spl_token::ID, - &source, - &target, - &signer_pubkey, - &[], - amount, - )?; - state.queue_external_instruction(transfer, seeds, 0); - - Ok(vec![]) -} + fn approve( + &mut self, + context: &crate::evm::Context, + source: Pubkey, + target: Pubkey, + amount: u64, + ) -> Result> { + let signer = context.caller; + let (signer_pubkey, bump_seed) = self.backend.contract_pubkey(signer); + + let seeds = vec![ + vec![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vec(), + vec![bump_seed], + ]; + + let approve = spl_token::instruction::approve( + &spl_token::ID, + &source, + &target, + &signer_pubkey, + &[], + amount, + )?; + self.queue_external_instruction(approve, seeds, 0); + + Ok(vec![]) + } -fn mint_to( - context: &crate::evm::Context, - state: &mut ExecutorState, - mint: Pubkey, - target: Pubkey, - amount: u64, -) -> Result> { - let signer = context.caller; - let (signer_pubkey, bump_seed) = state.backend.contract_pubkey(signer); - - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], - ]; - - let mint_to = spl_token::instruction::mint_to( - &spl_token::ID, - &mint, - &target, - &signer_pubkey, - &[], - amount, - )?; - state.queue_external_instruction(mint_to, seeds, 0); - - Ok(vec![]) -} + fn revoke(&mut self, context: &crate::evm::Context, account: Pubkey) -> Result> { + let signer = context.caller; + let (signer_pubkey, bump_seed) = self.backend.contract_pubkey(signer); -fn burn( - context: &crate::evm::Context, - state: &mut ExecutorState, - mint: Pubkey, - source: Pubkey, - amount: u64, -) -> Result> { - let signer = context.caller; - let (signer_pubkey, bump_seed) = state.backend.contract_pubkey(signer); - - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], - ]; - - #[rustfmt::skip] - let burn = spl_token::instruction::burn( - &spl_token::ID, - &source, - &mint, - &signer_pubkey, - &[], - amount - )?; - state.queue_external_instruction(burn, seeds, 0); - - Ok(vec![]) -} + let seeds = vec![ + vec![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vec(), + vec![bump_seed], + ]; -fn freeze( - context: &crate::evm::Context, - state: &mut ExecutorState, - mint: Pubkey, - target: Pubkey, -) -> Result> { - let signer = context.caller; - let (signer_pubkey, bump_seed) = state.backend.contract_pubkey(signer); - - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], - ]; - - let freeze = spl_token::instruction::freeze_account( - &spl_token::ID, - &target, - &mint, - &signer_pubkey, - &[], - )?; - state.queue_external_instruction(freeze, seeds, 0); - - Ok(vec![]) -} + let revoke = spl_token::instruction::revoke(&spl_token::ID, &account, &signer_pubkey, &[])?; + self.queue_external_instruction(revoke, seeds, 0); -fn thaw( - context: &crate::evm::Context, - state: &mut ExecutorState, - mint: Pubkey, - target: Pubkey, -) -> Result> { - let signer = context.caller; - let (signer_pubkey, bump_seed) = state.backend.contract_pubkey(signer); - - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], - ]; - - #[rustfmt::skip] - let thaw = spl_token::instruction::thaw_account( - &spl_token::ID, - &target, - &mint, - &signer_pubkey, - &[] - )?; - state.queue_external_instruction(thaw, seeds, 0); - - Ok(vec![]) -} + Ok(vec![]) + } -#[allow(clippy::unnecessary_wraps)] -fn find_account( - context: &crate::evm::Context, - state: &mut ExecutorState, - seed: &[u8], -) -> Result> { - let signer = context.caller; + fn transfer( + &mut self, + context: &crate::evm::Context, + source: Pubkey, + target: Pubkey, + amount: u64, + ) -> Result> { + let signer = context.caller; + let (signer_pubkey, bump_seed) = self.backend.contract_pubkey(signer); + + let seeds = vec![ + vec![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vec(), + vec![bump_seed], + ]; + + let transfer = spl_token::instruction::transfer( + &spl_token::ID, + &source, + &target, + &signer_pubkey, + &[], + amount, + )?; + self.queue_external_instruction(transfer, seeds, 0); + + Ok(vec![]) + } - let (account_key, _) = Pubkey::find_program_address( - &[ + fn transfer_with_seed( + &mut self, + context: &crate::evm::Context, + seed: &[u8; 32], + source: Pubkey, + target: Pubkey, + amount: u64, + ) -> Result> { + let seeds: &[&[u8]] = &[ &[ACCOUNT_SEED_VERSION], - b"ContractData", - signer.as_bytes(), + b"AUTH", + context.caller.as_bytes(), seed, - ], - state.backend.program_id(), - ); + ]; + let (signer_pubkey, signer_seed) = + Pubkey::find_program_address(seeds, self.backend.program_id()); + + let seeds = vec![ + vec![ACCOUNT_SEED_VERSION], + b"AUTH".to_vec(), + context.caller.as_bytes().to_vec(), + seed.to_vec(), + vec![signer_seed], + ]; + + let transfer = spl_token::instruction::transfer( + &spl_token::ID, + &source, + &target, + &signer_pubkey, + &[], + amount, + )?; + self.queue_external_instruction(transfer, seeds, 0); + + Ok(vec![]) + } - Ok(account_key.to_bytes().to_vec()) -} + fn mint_to( + &mut self, + context: &crate::evm::Context, + mint: Pubkey, + target: Pubkey, + amount: u64, + ) -> Result> { + let signer = context.caller; + let (signer_pubkey, bump_seed) = self.backend.contract_pubkey(signer); + + let seeds = vec![ + vec![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vec(), + vec![bump_seed], + ]; + + let mint_to = spl_token::instruction::mint_to( + &spl_token::ID, + &mint, + &target, + &signer_pubkey, + &[], + amount, + )?; + self.queue_external_instruction(mint_to, seeds, 0); + + Ok(vec![]) + } -#[maybe_async] -async fn is_system_account( - _context: &crate::evm::Context, - state: &mut ExecutorState<'_, B>, - account: Pubkey, -) -> Result> { - let account = state.external_account(account).await?; - if system_program::check_id(&account.owner) { - let mut result = vec![0_u8; 32]; - result[31] = 1; // return true - - Ok(result) - } else { - Ok(vec![0_u8; 32]) + fn burn_spl_token( + &mut self, + context: &crate::evm::Context, + mint: Pubkey, + source: Pubkey, + amount: u64, + ) -> Result> { + let signer = context.caller; + let (signer_pubkey, bump_seed) = self.backend.contract_pubkey(signer); + + let seeds = vec![ + vec![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vec(), + vec![bump_seed], + ]; + + let burn = spl_token::instruction::burn( + &spl_token::ID, + &source, + &mint, + &signer_pubkey, + &[], + amount, + )?; + self.queue_external_instruction(burn, seeds, 0); + + Ok(vec![]) } -} -#[maybe_async] -async fn get_account( - _context: &crate::evm::Context, - state: &mut ExecutorState<'_, B>, - account: Pubkey, -) -> Result> { - let account = state.external_account(account).await?; - let token = if spl_token::check_id(&account.owner) { - spl_token::state::Account::unpack(&account.data)? - } else if system_program::check_id(&account.owner) { - spl_token::state::Account::default() - } else { - return Err(ProgramError::IllegalOwner.into()); - }; - - debug_print!("spl_token get_account: {:?}", token); - - let mut result = [0_u8; 7 * 32]; - let (mint, owner, _, amount, delegate, _, delegated_amount, close_authority, state) = - arrayref::mut_array_refs![&mut result, 32, 32, 24, 8, 32, 24, 8, 32, 32]; - - *mint = token.mint.to_bytes(); - *owner = token.owner.to_bytes(); - *amount = token.amount.to_be_bytes(); - *delegate = token.delegate.map(Pubkey::to_bytes).unwrap_or_default(); - *delegated_amount = token.delegated_amount.to_be_bytes(); - *close_authority = token - .close_authority - .map(Pubkey::to_bytes) - .unwrap_or_default(); - state[31] = token.state as u8; - - Ok(result.to_vec()) -} + fn freeze( + &mut self, + context: &crate::evm::Context, + mint: Pubkey, + target: Pubkey, + ) -> Result> { + let signer = context.caller; + let (signer_pubkey, bump_seed) = self.backend.contract_pubkey(signer); + + let seeds = vec![ + vec![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vec(), + vec![bump_seed], + ]; + + let freeze = spl_token::instruction::freeze_account( + &spl_token::ID, + &target, + &mint, + &signer_pubkey, + &[], + )?; + self.queue_external_instruction(freeze, seeds, 0); + + Ok(vec![]) + } + + fn thaw( + &mut self, + context: &crate::evm::Context, + mint: Pubkey, + target: Pubkey, + ) -> Result> { + let signer = context.caller; + let (signer_pubkey, bump_seed) = self.backend.contract_pubkey(signer); + + let seeds = vec![ + vec![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vec(), + vec![bump_seed], + ]; + + let thaw = spl_token::instruction::thaw_account( + &spl_token::ID, + &target, + &mint, + &signer_pubkey, + &[], + )?; + self.queue_external_instruction(thaw, seeds, 0); + + Ok(vec![]) + } + + #[allow(clippy::unnecessary_wraps)] + fn find_account(&mut self, context: &crate::evm::Context, seed: &[u8]) -> Result> { + let signer = context.caller; + + let (account_key, _) = Pubkey::find_program_address( + &[ + &[ACCOUNT_SEED_VERSION], + b"ContractData", + signer.as_bytes(), + seed, + ], + self.backend.program_id(), + ); -#[maybe_async] -async fn get_mint( - _context: &crate::evm::Context, - state: &mut ExecutorState<'_, B>, - account: Pubkey, -) -> Result> { - let account = state.external_account(account).await?; - let mint = if spl_token::check_id(&account.owner) { - spl_token::state::Mint::unpack(&account.data)? - } else if system_program::check_id(&account.owner) { - spl_token::state::Mint::default() - } else { - return Err(ProgramError::IllegalOwner.into()); - }; - - debug_print!("spl_token get_mint: {:?}", mint); - - let mut result = [0_u8; 5 * 32]; - let (_, supply, _, decimals, _, is_initialized, freeze_authority, mint_authority) = - arrayref::mut_array_refs![&mut result, 24, 8, 31, 1, 31, 1, 32, 32]; - - *supply = mint.supply.to_be_bytes(); - *decimals = mint.decimals.to_be_bytes(); - *is_initialized = if mint.is_initialized { [1_u8] } else { [0_u8] }; - *freeze_authority = mint - .freeze_authority - .map(Pubkey::to_bytes) - .unwrap_or_default(); - *mint_authority = mint - .mint_authority - .map(Pubkey::to_bytes) - .unwrap_or_default(); - - Ok(result.to_vec()) + Ok(account_key.to_bytes().to_vec()) + } + + #[maybe_async] + async fn is_system_account( + &mut self, + _context: &crate::evm::Context, + account: Pubkey, + ) -> Result> { + let account = self.external_account(account).await?; + if system_program::check_id(&account.owner) { + let mut result = vec![0_u8; 32]; + result[31] = 1; // return true + + Ok(result) + } else { + Ok(vec![0_u8; 32]) + } + } + + #[maybe_async] + async fn get_account( + &mut self, + _context: &crate::evm::Context, + account: Pubkey, + ) -> Result> { + let account = self.external_account(account).await?; + let token = if spl_token::check_id(&account.owner) { + spl_token::state::Account::unpack(&account.data)? + } else if system_program::check_id(&account.owner) { + spl_token::state::Account::default() + } else { + return Err(ProgramError::IllegalOwner.into()); + }; + + debug_print!("spl_token get_account: {:?}", token); + + let mut result = [0_u8; 7 * 32]; + let (mint, owner, _, amount, delegate, _, delegated_amount, close_authority, state) = + arrayref::mut_array_refs![&mut result, 32, 32, 24, 8, 32, 24, 8, 32, 32]; + + *mint = token.mint.to_bytes(); + *owner = token.owner.to_bytes(); + *amount = token.amount.to_be_bytes(); + *delegate = token.delegate.map(Pubkey::to_bytes).unwrap_or_default(); + *delegated_amount = token.delegated_amount.to_be_bytes(); + *close_authority = token + .close_authority + .map(Pubkey::to_bytes) + .unwrap_or_default(); + state[31] = token.state as u8; + + Ok(result.to_vec()) + } + + #[maybe_async] + async fn get_mint( + &mut self, + _context: &crate::evm::Context, + account: Pubkey, + ) -> Result> { + let account = self.external_account(account).await?; + let mint = if spl_token::check_id(&account.owner) { + spl_token::state::Mint::unpack(&account.data)? + } else if system_program::check_id(&account.owner) { + spl_token::state::Mint::default() + } else { + return Err(ProgramError::IllegalOwner.into()); + }; + + debug_print!("spl_token get_mint: {:?}", mint); + + let mut result = [0_u8; 5 * 32]; + let (_, supply, _, decimals, _, is_initialized, freeze_authority, mint_authority) = + arrayref::mut_array_refs![&mut result, 24, 8, 31, 1, 31, 1, 32, 32]; + + *supply = mint.supply.to_be_bytes(); + *decimals = mint.decimals.to_be_bytes(); + *is_initialized = if mint.is_initialized { [1_u8] } else { [0_u8] }; + *freeze_authority = mint + .freeze_authority + .map(Pubkey::to_bytes) + .unwrap_or_default(); + *mint_authority = mint + .mint_authority + .map(Pubkey::to_bytes) + .unwrap_or_default(); + + Ok(result.to_vec()) + } } From 3804736049af44fd2c03b1ffcbd84e72ec604628 Mon Sep 17 00:00:00 2001 From: Kristina Nikolaeva <112946046+kristinaNikolaevaa@users.noreply.github.com> Date: Fri, 15 Dec 2023 13:02:48 +0100 Subject: [PATCH 079/318] run evm tests separately (#248) * fix container command --- .github/workflows/deploy.py | 33 +- .github/workflows/github_api_client.py | 15 +- .github/workflows/pipeline.yml | 28 +- Dockerfile | 18 +- ci/deploy-test.sh | 25 - ci/docker-compose-ci.yml | 14 +- ci/docker-compose-test.yml | 49 +- tests/.gitignore | 3 - tests/README.md | 105 --- tests/__init__.py | 0 tests/conftest.py | 179 ----- tests/contracts/contracts.sol | 123 ---- tests/eth_tx_utils.py | 228 ------- tests/requirements.txt | 12 - tests/solana_utils.py | 604 ----------------- tests/test_cancel_trx.py | 42 -- tests/test_cli.py | 153 ----- tests/test_execute_trx_from_instruction.py | 329 ---------- tests/test_holder_account.py | 164 ----- tests/test_neon_core_api.py | 64 -- tests/test_parallel.py | 166 ----- tests/test_step_instructions_work_the_same.py | 62 -- tests/test_transaction_step_from_account.py | 557 ---------------- ...ransaction_step_from_account_no_chainid.py | 123 ---- .../test_transaction_step_from_instruction.py | 611 ------------------ tests/utils/__init__.py | 0 tests/utils/assert_messages.py | 18 - tests/utils/constants.py | 27 - tests/utils/contract.py | 105 --- tests/utils/ethereum.py | 46 -- tests/utils/instructions.py | 243 ------- tests/utils/layouts.py | 50 -- tests/utils/neon_api_client.py | 41 -- tests/utils/storage.py | 47 -- tests/utils/transaction_checks.py | 28 - tests/utils/types.py | 26 - 36 files changed, 108 insertions(+), 4230 deletions(-) delete mode 100755 ci/deploy-test.sh delete mode 100644 tests/.gitignore delete mode 100644 tests/README.md delete mode 100644 tests/__init__.py delete mode 100644 tests/conftest.py delete mode 100644 tests/contracts/contracts.sol delete mode 100644 tests/eth_tx_utils.py delete mode 100644 tests/requirements.txt delete mode 100644 tests/solana_utils.py delete mode 100644 tests/test_cancel_trx.py delete mode 100644 tests/test_cli.py delete mode 100644 tests/test_execute_trx_from_instruction.py delete mode 100644 tests/test_holder_account.py delete mode 100644 tests/test_neon_core_api.py delete mode 100644 tests/test_parallel.py delete mode 100644 tests/test_step_instructions_work_the_same.py delete mode 100644 tests/test_transaction_step_from_account.py delete mode 100644 tests/test_transaction_step_from_account_no_chainid.py delete mode 100644 tests/test_transaction_step_from_instruction.py delete mode 100644 tests/utils/__init__.py delete mode 100644 tests/utils/assert_messages.py delete mode 100644 tests/utils/constants.py delete mode 100644 tests/utils/contract.py delete mode 100644 tests/utils/ethereum.py delete mode 100644 tests/utils/instructions.py delete mode 100644 tests/utils/layouts.py delete mode 100644 tests/utils/neon_api_client.py delete mode 100644 tests/utils/storage.py delete mode 100644 tests/utils/transaction_checks.py delete mode 100644 tests/utils/types.py diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index b619675be..587bcdac6 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -31,12 +31,16 @@ DOCKER_PASSWORD = os.environ.get("DHUBP") IMAGE_NAME = os.environ.get("IMAGE_NAME") RUN_LINK_REPO = os.environ.get("RUN_LINK_REPO") +DOCKERHUB_ORG_NAME = os.environ.get("DOCKERHUB_ORG_NAME") SOLANA_NODE_VERSION = 'v1.16.23' SOLANA_BPF_VERSION = 'v1.16.23' VERSION_BRANCH_TEMPLATE = r"[vt]{1}\d{1,2}\.\d{1,2}\.x.*" docker_client = docker.APIClient() +NEON_TEST_IMAGE_NAME = f"{DOCKERHUB_ORG_NAME.lower()}/neon_tests" +PROXY_ENDPOINT = os.environ.get("PROXY_ENDPOINT") +NEON_TESTS_ENDPOINT = os.environ.get("NEON_TESTS_ENDPOINT") @click.group() def cli(): @@ -100,17 +104,27 @@ def run_subprocess(command): @cli.command(name="run_tests") @click.option('--github_sha') -def run_tests(github_sha): - image_name = f"{IMAGE_NAME}:{github_sha}" - os.environ["EVM_LOADER_IMAGE"] = image_name +@click.option('--neon_test_branch') +def run_tests(github_sha, neon_test_branch): + os.environ["EVM_LOADER_IMAGE"] = f"{IMAGE_NAME}:{github_sha}" + + if neon_test_branch in GithubClient.get_branches_list(NEON_TESTS_ENDPOINT) \ + and neon_test_branch not in ('master', 'develop'): + neon_test_image_tag = neon_test_branch + else: + neon_test_image_tag = 'latest' + os.environ["NEON_TESTS_IMAGE"] = f"{NEON_TEST_IMAGE_NAME}:{neon_test_image_tag}" + project_name = f"neon-evm-{github_sha}" stop_containers(project_name) + run_subprocess(f"docker-compose -p {project_name} -f ./ci/docker-compose-ci.yml pull") run_subprocess(f"docker-compose -p {project_name} -f ./ci/docker-compose-ci.yml up -d") - container_name = get_solana_container_name(project_name) + test_container_name = get_container_name(project_name, "tests") + click.echo("Start tests") exec_id = docker_client.exec_create( - container=container_name, cmd="/opt/deploy-test.sh") + container=test_container_name, cmd="python3 clickfile.py run evm --numprocesses 6") logs = docker_client.exec_start(exec_id['Id'], stream=True) tests_are_failed = False @@ -122,9 +136,6 @@ def run_tests(github_sha): if 'ERROR ' in current_line or 'FAILED ' in current_line: tests_are_failed = True print("Tests are failed") - if "[100%]" not in all_logs: - tests_are_failed = True - print("Part of tests are skipped") exec_status = docker_client.exec_inspect(exec_id['Id'])["ExitCode"] @@ -136,12 +147,12 @@ def run_tests(github_sha): sys.exit(1) -def get_solana_container_name(project_name): +def get_container_name(project_name, service_name): data = subprocess.run( f"docker-compose -p {project_name} -f ./ci/docker-compose-ci.yml ps", shell=True, capture_output=True, text=True).stdout click.echo(data) - pattern = rf'{project_name}_solana_[1-9]+' + pattern = rf'{project_name}_{service_name}_[1-9]+' match = re.search(pattern, data) return match.group(0) @@ -178,7 +189,7 @@ def trigger_proxy_action(head_ref_branch, base_ref_branch, github_ref, github_sh github = GithubClient(token) - if head_ref_branch in github.get_proxy_branches(): + if head_ref_branch in github.get_branches_list(PROXY_ENDPOINT): proxy_branch = head_ref_branch elif re.match(VERSION_BRANCH_TEMPLATE, base_ref_branch): proxy_branch = base_ref_branch diff --git a/.github/workflows/github_api_client.py b/.github/workflows/github_api_client.py index e29dddd29..198a4892a 100644 --- a/.github/workflows/github_api_client.py +++ b/.github/workflows/github_api_client.py @@ -4,15 +4,15 @@ class GithubClient(): - PROXY_ENDPOINT = os.environ.get("PROXY_ENDPOINT") def __init__(self, token): + self.proxy_endpoint = os.environ.get("PROXY_ENDPOINT") self.headers = {"Authorization": f"Bearer {token}", "Accept": "application/vnd.github+json"} def get_proxy_runs_list(self, proxy_branch): response = requests.get( - f"{self.PROXY_ENDPOINT}/actions/workflows/pipeline.yml/runs?branch={proxy_branch}", headers=self.headers) + f"{self.proxy_endpoint}/actions/workflows/pipeline.yml/runs?branch={proxy_branch}", headers=self.headers) if response.status_code != 200: raise RuntimeError(f"Can't get proxy runs list. Error: {response.json()}") runs = [item['id'] for item in response.json()['workflow_runs']] @@ -20,7 +20,7 @@ def get_proxy_runs_list(self, proxy_branch): def get_proxy_runs_count(self, proxy_branch): response = requests.get( - f"{self.PROXY_ENDPOINT}/actions/workflows/pipeline.yml/runs?branch={proxy_branch}", headers=self.headers) + f"{self.proxy_endpoint}/actions/workflows/pipeline.yml/runs?branch={proxy_branch}", headers=self.headers) return int(response.json()["total_count"]) def run_proxy_dispatches(self, proxy_branch, github_ref, github_sha, test_set, initial_pr): @@ -31,18 +31,19 @@ def run_proxy_dispatches(self, proxy_branch, github_ref, github_sha, test_set, i "initial_pr": initial_pr} } response = requests.post( - f"{self.PROXY_ENDPOINT}/actions/workflows/pipeline.yml/dispatches", json=data, headers=self.headers) + f"{self.proxy_endpoint}/actions/workflows/pipeline.yml/dispatches", json=data, headers=self.headers) click.echo(f"Sent data: {data}") click.echo(f"Status code: {response.status_code}") if response.status_code != 204: raise RuntimeError("proxy-model.py action is not triggered") - def get_proxy_branches(self): + @staticmethod + def get_branches_list(endpoint): proxy_branches_obj = requests.get( - f"{self.PROXY_ENDPOINT}/branches?per_page=100").json() + f"{endpoint}/branches?per_page=100").json() return [item["name"] for item in proxy_branches_obj] def get_proxy_run_info(self, id): response = requests.get( - f"{self.PROXY_ENDPOINT}/actions/runs/{id}", headers=self.headers) + f"{self.proxy_endpoint}/actions/runs/{id}", headers=self.headers) return response.json() diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index c46a959e0..0418a9cf7 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -15,6 +15,8 @@ env: DHUBP: ${{secrets.DHUBP}} IMAGE_NAME: ${{vars.IMAGE_NAME}} PROXY_ENDPOINT: ${{vars.PROXY_ENDPOINT}} + NEON_TESTS_ENDPOINT: ${{vars.NEON_TESTS_ENDPOINT}} + DOCKERHUB_ORG_NAME: ${{vars.DOCKERHUB_ORG_NAME}} RUN_LINK_REPO: ${{vars.RUN_LINK_REPO}} BUILD_URL: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" @@ -46,10 +48,34 @@ jobs: - uses: actions/checkout@v3 with: fetch-depth: 0 + - name: Define base branch if the action is tag creation + id: tag_creation + if: startsWith(github.ref , 'refs/tags/') + run: | + base_branch=`echo ${{ github.ref_name }} | sed 's/\.[0-9]*$/\.x/'` + echo "base_branch=$base_branch" >> $GITHUB_OUTPUT + echo "base_branch=$base_branch" + - name: Define neon test branch + id: neon_test_branch + run: | + if [[ "${{ github.ref }}" =~ "refs/heads/"[vt][0-9]+\.[0-9]+\.x ]]; then # version branch + tag=${GITHUB_REF/refs\/heads\//} + + elif [[ "${{ steps.tag_creation.outputs.base_branch }}" != "" ]]; then # tag creation + tag=${{ steps.tag_creation.outputs.base_branch }} + + elif [[ "${{ github.head_ref }}" != "" ]]; then # pr to feature or version branch + tag=${{ github.head_ref }} + else + tag='develop' + fi + echo "value=${tag}" + echo "value=${tag}" >> $GITHUB_OUTPUT - name: Run tests run: | python3 ./.github/workflows/deploy.py run_tests \ - --github_sha=${GITHUB_SHA} + --github_sha=${GITHUB_SHA} \ + --neon_test_branch=${{ steps.neon_test_branch.outputs.value }} trigger-proxy-tests: runs-on: trigger-runner needs: diff --git a/Dockerfile b/Dockerfile index 333ca365d..04bf9c5c8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,25 +27,12 @@ RUN cargo fmt --check && \ cargo build-bpf --features mainnet,emergency && cp target/deploy/evm_loader.so target/deploy/evm_loader-mainnet-emergency.so && \ cargo build-bpf --features ci --dump -# Build Solidity contracts -FROM ethereum/solc:stable-alpine AS contracts -COPY tests/contracts/*.sol /opt/ -COPY solidity/*.sol /opt/ -WORKDIR /opt/ -RUN /usr/local/bin/solc --optimize --optimize-runs 200 --output-dir . --bin *.sol && \ - for file in $(ls *.bin); do xxd -r -p $file >${file}ary; done && \ - ls -l # Add neon_test_invoke_program to the genesis FROM neonlabsorg/neon_test_invoke_program:develop AS neon_test_invoke_program # Define solana-image that contains utility FROM builder AS base -RUN apt-get update -RUN apt-get -y install curl python3 python3-pip - -COPY tests/requirements.txt /tmp/ -RUN pip3 install -r /tmp/requirements.txt RUN solana program dump metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s /opt/metaplex.so --url mainnet-beta @@ -53,7 +40,6 @@ COPY --from=evm-loader-builder /opt/neon-evm/evm_loader/target/deploy/evm_loader COPY --from=evm-loader-builder /opt/neon-evm/evm_loader/target/deploy/evm_loader-dump.txt /opt/ COPY --from=evm-loader-builder /opt/neon-evm/evm_loader/target/release/neon-cli /opt/ COPY --from=evm-loader-builder /opt/neon-evm/evm_loader/target/release/neon-api /opt/ -COPY --from=contracts /opt/ /opt/solidity/ COPY --from=neon_test_invoke_program /opt/neon_test_invoke_program.so /opt/ COPY --from=neon_test_invoke_program /opt/neon_test_invoke_program-keypair.json /opt/ @@ -61,18 +47,16 @@ COPY ci/wait-for-solana.sh \ ci/wait-for-neon.sh \ ci/solana-run-neon.sh \ ci/deploy-evm.sh \ - ci/deploy-test.sh \ ci/create-test-accounts.sh \ ci/evm_loader-keypair.json \ /opt/ +COPY solidity/ /opt/solidity COPY ci/operator-keypairs/ /opt/operator-keypairs -COPY tests /opt/tests COPY ci/operator-keypairs/id.json /root/.config/solana/id.json COPY ci/operator-keypairs/id2.json /root/.config/solana/id2.json COPY ci/keys/ /opt/keys -#ENV CONTRACTS_DIR=/opt/solidity/ ENV PATH=${PATH}:/opt ENTRYPOINT [ "/opt/solana-run-neon.sh" ] diff --git a/ci/deploy-test.sh b/ci/deploy-test.sh deleted file mode 100755 index 75594e9af..000000000 --- a/ci/deploy-test.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -set -euo pipefail -set +v - -echo "Deploy test..." - -export EVM_LOADER=$(solana address -k evm_loader-keypair.json) -echo EVM_LOADER=${EVM_LOADER} - -echo "Wait for NeonEVM" -wait-for-neon.sh 240 - -ELF_PARAMS=$(neon-cli --evm_loader "$EVM_LOADER" neon-elf-params evm_loader.so) -echo ${ELF_PARAMS} -export $(python3 -c " -import sys, json -for key, value in json.loads(sys.argv[1])['value'].items(): - print(f'{key}={value}') -" "$ELF_PARAMS") - - -py.test -n 6 tests/ - -echo "Deploy test success" -exit 0 diff --git a/ci/docker-compose-ci.yml b/ci/docker-compose-ci.yml index e7ef0b13b..a43a98a1b 100644 --- a/ci/docker-compose-ci.yml +++ b/ci/docker-compose-ci.yml @@ -20,7 +20,7 @@ services: networks: - net - dk-neon-api: + neon-core-api: restart: unless-stopped hostname: neon_api entrypoint: @@ -40,6 +40,18 @@ services: image: ${EVM_LOADER_IMAGE} ports: - "8085" + expose: + - "8085" + networks: + - net + + tests: + image: ${NEON_TESTS_IMAGE} + environment: + - SOLANA_URL=http://solana:8899 + - NEON_CORE_API_URL=http://neon_api:8085/api + hostname: tests + command: sleep infinity networks: - net diff --git a/ci/docker-compose-test.yml b/ci/docker-compose-test.yml index c705b2fef..405eea9d1 100644 --- a/ci/docker-compose-test.yml +++ b/ci/docker-compose-test.yml @@ -19,18 +19,43 @@ services: - "8003/udp" entrypoint: /opt/solana-run-neon.sh + networks: + - net -# proxy: -# container_name: proxy -# image: proxy.py:latest -# hostname: proxy -# environment: -# - SOLANA_URL=http://solana:8899 -# ports: -# - 9090:9090 -# expose: -# - "9090" + neon-core-api: + container_name: neon-core-api + restart: unless-stopped + hostname: neon_api + entrypoint: + /opt/neon-api -H 0.0.0.0:8085 + environment: + RUST_BACKTRACE: 1 + RUST_LOG: debug + NEON_API_LISTENER_ADDR: 0.0.0.0:8085 + SOLANA_URL: http://solana:8899 + EVM_LOADER: 53DfF883gyixYNXnM7s5xhdeyV8mVk9T4i2hGV9vG9io + NEON_TOKEN_MINT: HPsV9Deocecw3GeZv1FkAPNCBRfuVyfw9MMwjwRe1xaU + NEON_CHAIN_ID: 111 + COMMITMENT: confirmed + NEON_DB_CLICKHOUSE_URLS: "http://45.250.253.36:8123;http://45.250.253.38:8123" + KEYPAIR: /opt/operator-keypairs/id.json + FEEPAIR: /opt/operator-keypairs/id.json + image: ${EVM_LOADER_IMAGE} + ports: + - "8085:8085" + expose: + - "8085" + networks: + - net + tests: + image: ${NEON_TESTS_IMAGE} + environment: + - SOLANA_URL=http://solana:8899 + - NEON_CORE_API_URL=http://neon_api:8085/api + hostname: tests + command: sleep infinity + networks: + - net networks: - default: - name: evm_loader-deploy_test-net \ No newline at end of file + net: \ No newline at end of file diff --git a/tests/.gitignore b/tests/.gitignore deleted file mode 100644 index fc4b05c7d..000000000 --- a/tests/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -contracts/*.binary -__pycache__ -.pytest_cache \ No newline at end of file diff --git a/tests/README.md b/tests/README.md deleted file mode 100644 index 7ce13b3d2..000000000 --- a/tests/README.md +++ /dev/null @@ -1,105 +0,0 @@ -Intro -====== - -In this directory are located tests for the evm which sends transactions direct to the evm. -Tests are using python and py.test library for run tests. - - -Installation ------------- - -```bash -pip install -r requirements.txt -py.test ./ -s -v -``` - -Moreover, we can use additional command line keys: - -1. --neon-api-uri - neon_core_api url (by default 'http://neon_api:8085/api') - -Also we can configure some variables from environment variables: - -1. SOLANA_URL - by default http://localhost:8899 -2. EVM_LOADER - set evm loader address -3. NEON_TOKEN_MINT - ethereum token mint address - - -How to write tests -================== - -Structure ---------- - -Test has a several helper directories and files: - -1. contracts - place for all Solidity contracts used in tests -2. utils - place for utilities which divided by logic parts -3. conftest.py - common fixtures for all tests - - -Common fixtures ---------------- - -For more information about fixtures see [pytest-fixture](https://docs.pytest.org/en/latest/fixture.html). -In several words, fixtures are functions which are called before and after each test and has a scope parameter which setup how often this function will be called. -For example: - -```python -import pytest - -@pytest.fixture(scope="function") -def fixture1(): - print("Call fixture1") - return "fixture1" - - -def test_one(fixture1): - pass - - -def test_two(fixture1): - pass -``` - -In this case "fixture1" will be called before each test. - -```python -import pytest - -@pytest.fixture(scope="session") -def fixture1(): - print("Call fixture1") - return "fixture1" - - -def test_one(fixture1): - pass - - -def test_two(fixture1): - pass -``` - -In this case "fixture1" will be called only once before all tests. - -We have a several common fixtures: - -1. evm_loader - fixture for evm loader object -2. operator_keypair - solana Keypair for operator key -3. treasury_pool - created treasury pool -4. user_account - created user account with ethereum account - - -Tips -==== - -Generate eth contract function call data ---------------------------------------- - -```python -from eth_utils import abi -func_name = abi.function_signature_to_4byte_selector('unchange_storage(uint8,uint8)') -data = (func_name + bytes.fromhex("%064x" % 0x01) + bytes.fromhex("%064x" % 0x01)) -``` - -uint8 parameters must be 64 bytes long diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/conftest.py b/tests/conftest.py deleted file mode 100644 index 74baf0b08..000000000 --- a/tests/conftest.py +++ /dev/null @@ -1,179 +0,0 @@ -import os -import json -import pathlib - -import eth_abi -import pytest - -from solana.keypair import Keypair -from eth_keys import keys as eth_keys -from solana.publickey import PublicKey -from solana.rpc.commitment import Confirmed - -from .solana_utils import EvmLoader, create_treasury_pool_address, make_new_user, \ - deposit_neon, solana_client, get_solana_balance, wait_for_account_to_exists -from .utils.constants import NEON_TOKEN_MINT_ID -from .utils.contract import deploy_contract -from .utils.storage import create_holder -from .utils.types import TreasuryPool, Caller, Contract -from .utils.neon_api_client import NeonApiClient - - -def pytest_addoption(parser): - parser.addoption( - "--neon-api-uri", action="store", default="http://neon_api:8085/api", - help="" - ) - - -def pytest_configure(): - if "CI" in os.environ: - pytest.CONTRACTS_PATH = pathlib.Path("/opt/solidity") - else: - pytest.CONTRACTS_PATH = pathlib.Path(__file__).parent / "contracts" - - -@pytest.fixture(scope="session") -def evm_loader(operator_keypair: Keypair) -> EvmLoader: - loader = EvmLoader(operator_keypair) - return loader - - -def prepare_operator(key_file): - with open(key_file, "r") as key: - secret_key = json.load(key)[:32] - account = Keypair.from_secret_key(secret_key) - - solana_client.request_airdrop(account.public_key, 1000 * 10 ** 9, commitment=Confirmed) - wait_for_account_to_exists(solana_client, account.public_key) - - a = solana_client.get_account_info(account.public_key, commitment=Confirmed) - print(f"{a}") - - operator_ether = eth_keys.PrivateKey(account.secret_key[:32]).public_key.to_canonical_address() - - evm_loader = EvmLoader(account) - ether_balance_pubkey = evm_loader.ether2balance(operator_ether) - acc_info = solana_client.get_account_info(ether_balance_pubkey, commitment=Confirmed) - if acc_info.value is None: - evm_loader.create_balance_account(operator_ether) - - return account - -@pytest.fixture(scope="session") -def default_operator_keypair() -> Keypair: - """ - Initialized solana keypair with balance. Get private keys from ci/operator-keypairs/id.json - """ - key_path = pathlib.Path(__file__).parent.parent / "operator-keypairs" - key_file = key_path / "id.json" - return prepare_operator(key_file) - -@pytest.fixture(scope="session") -def operator_keypair(worker_id) -> Keypair: - """ - Initialized solana keypair with balance. Get private keys from ci/operator-keypairs - """ - key_path = pathlib.Path(__file__).parent.parent / "operator-keypairs" - if worker_id in ("master", "gw1"): - key_file = key_path / "id.json" - else: - file_id = int(worker_id[-1]) + 2 - key_file = key_path / f"id{file_id}.json" - return prepare_operator(key_file) - - -@pytest.fixture(scope="session") -def second_operator_keypair(worker_id) -> Keypair: - """ - Initialized solana keypair with balance. Get private key from cli or ./ci/operator-keypairs - """ - key_path = pathlib.Path(__file__).parent.parent / "operator-keypairs" - if worker_id in ("master", "gw1"): - key_file = key_path / "id20.json" - else: - file_id = 20 + int(worker_id[-1]) + 2 - key_file = key_path / f"id{file_id}.json" - - return prepare_operator(key_file) - - -@pytest.fixture(scope="session") -def treasury_pool(evm_loader) -> TreasuryPool: - index = 2 - address = create_treasury_pool_address(index) - index_buf = index.to_bytes(4, 'little') - return TreasuryPool(index, address, index_buf) - - -@pytest.fixture(scope="function") -def user_account(evm_loader) -> Caller: - return make_new_user(evm_loader) - - -@pytest.fixture(scope="session") -def session_user(evm_loader) -> Caller: - return make_new_user(evm_loader) - - -@pytest.fixture(scope="session") -def second_session_user(evm_loader) -> Caller: - return make_new_user(evm_loader) - - -@pytest.fixture(scope="session") -def sender_with_tokens(evm_loader, operator_keypair) -> Caller: - user = make_new_user(evm_loader) - deposit_neon(evm_loader, operator_keypair, user.eth_address, 100000) - return user - - -@pytest.fixture(scope="session") -def holder_acc(operator_keypair) -> PublicKey: - return create_holder(operator_keypair) - - -@pytest.fixture(scope="function") -def new_holder_acc(operator_keypair) -> PublicKey: - return create_holder(operator_keypair) - - -@pytest.fixture(scope="function") -def rw_lock_contract(evm_loader: EvmLoader, operator_keypair: Keypair, session_user: Caller, - treasury_pool) -> Contract: - return deploy_contract(operator_keypair, session_user, "rw_lock.binary", evm_loader, treasury_pool) - - -@pytest.fixture(scope="function") -def rw_lock_caller(evm_loader: EvmLoader, operator_keypair: Keypair, - session_user: Caller, treasury_pool: TreasuryPool, rw_lock_contract: Contract) -> Contract: - constructor_args = eth_abi.encode(['address'], [rw_lock_contract.eth_address.hex()]) - return deploy_contract(operator_keypair, session_user, "rw_lock_caller.binary", evm_loader, - treasury_pool, encoded_args=constructor_args) - - -@pytest.fixture(scope="function") -def string_setter_contract(evm_loader: EvmLoader, operator_keypair: Keypair, session_user: Caller, - treasury_pool) -> Contract: - return deploy_contract(operator_keypair, session_user, "string_setter.binary", evm_loader, treasury_pool) - - -@pytest.fixture(scope="session") -def calculator_contract(evm_loader: EvmLoader, operator_keypair: Keypair, session_user: Caller, - treasury_pool) -> Contract: - return deploy_contract(operator_keypair, session_user, "Calculator.binary", evm_loader, treasury_pool) - - -@pytest.fixture(scope="session") -def calculator_caller_contract(evm_loader: EvmLoader, operator_keypair: Keypair, session_user: Caller, - treasury_pool, calculator_contract) -> Contract: - constructor_args = eth_abi.encode(['address'], [calculator_contract.eth_address.hex()]) - - return deploy_contract(operator_keypair, session_user, "CalculatorCaller.binary", evm_loader, treasury_pool, - encoded_args=constructor_args) - - -@pytest.fixture(scope="session") -def neon_api_client(request): - client = NeonApiClient(url=request.config.getoption("--neon-api-uri")) - return client diff --git a/tests/contracts/contracts.sol b/tests/contracts/contracts.sol deleted file mode 100644 index 988e55d12..000000000 --- a/tests/contracts/contracts.sol +++ /dev/null @@ -1,123 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity >=0.5.12; - -contract rw_lock { - mapping(address => mapping(uint256 => uint256)) public data; - uint len = 0; - string public text; - - function unchange_storage(uint8 x, uint8 y) public pure returns(uint8) { - return x + y; - } - - function update_storage(uint resize) public { - uint n = 0; - - while (n < resize){ - data[msg.sender][len+n] = uint256(len+n); - n = n + 1; - } - len = len + resize; - } - - function update_storage_str(string memory new_text) public { - text = new_text; - } - - function update_storage_map(uint resize) public { - uint n = 0; - while (n < resize){ - data[msg.sender][n] = uint256(n); - n = n + 1; - } - } - - function get_text() public view returns (string memory) { - return text; - } - - function deploy_contract() public returns(address){ - hello_world hello = new hello_world(); - hello.call_hello_world(); - return address(hello); - } - -} - - -contract hello_world { - uint public num = 5; - string public text = "Hello World!"; - - function call_hello_world() public view returns (string memory) { - return text; - } -} - -contract small { - function call_hello() public view returns (string memory) { - return "Hi"; - } -} - - -contract string_setter{ - string public text; - - - function get() public view returns (string memory) { - return text; - } - - function set(string memory new_text) public payable { - text = new_text; - } - - -} - -contract rw_lock_caller { - rw_lock rw; - - constructor(address rw_lock_address) { - rw = rw_lock(rw_lock_address); - } - - function unchange_storage(uint8 x, uint8 y) public view returns(uint8) { - return rw.unchange_storage(x, y); - } - - function update_storage_str(string memory new_text) public { - rw.update_storage_str(new_text); - } - - function update_storage_map(uint resize) public { - rw.update_storage_map(resize); - } - - function get_text() public view returns (string memory) { - return rw.get_text(); - } -} - - -contract Calculator { - uint public x = 20; - uint public y = 20; - - function getSum() public view returns (uint256) { - return x + y; - } -} - -contract CalculatorCaller { - Calculator calculator; - - constructor(address _calc) { - calculator = Calculator(_calc); - } - - function callCalculator() public view returns (uint sum) { - sum = calculator.getSum(); - } -} diff --git a/tests/eth_tx_utils.py b/tests/eth_tx_utils.py deleted file mode 100644 index e5ec11fb7..000000000 --- a/tests/eth_tx_utils.py +++ /dev/null @@ -1,228 +0,0 @@ -from sha3 import keccak_256 -import json -from web3.auto import w3 -from eth_keys import keys -import struct - - -def unpack(data): - ch = data[0] - if ch <= 0x7F: - return ch, data[1:] - elif ch == 0x80: - return None, data[1:] - elif ch <= 0xB7: - l = ch - 0x80 - return data[1:1 + l].tobytes(), data[1 + l:] - elif ch <= 0xBF: - lLen = ch - 0xB7 - l = int.from_bytes(data[1:1 + lLen], byteorder='big') - return data[1 + lLen:1 + lLen + l].tobytes(), data[1 + lLen + l:] - elif ch == 0xC0: - return (), data[1:] - elif ch <= 0xF7: - l = ch - 0xC0 - lst = list() - sub = data[1:1 + l] - while len(sub): - (item, sub) = unpack(sub) - lst.append(item) - return lst, data[1 + l:] - else: - lLen = ch - 0xF7 - l = int.from_bytes(data[1:1 + lLen], byteorder='big') - lst = list() - sub = data[1 + lLen:1 + lLen + l] - while len(sub): - (item, sub) = unpack(sub) - lst.append(item) - return lst, data[1 + lLen + l:] - - -def pack(data): - if data is None: - return (0x80).to_bytes(1, 'big') - if isinstance(data, str): - return pack(data.encode('utf8')) - elif isinstance(data, bytes): - if len(data) <= 55: - return (len(data) + 0x80).to_bytes(1, 'big') + data - else: - l = len(data) - lLen = (l.bit_length() + 7) // 8 - return (0xB7 + lLen).to_bytes(1, 'big') + l.to_bytes(lLen, 'big') + data - elif isinstance(data, int): - if data < 0x80: - return data.to_bytes(1, 'big') - else: - l = (data.bit_length() + 7) // 8 - return (l + 0x80).to_bytes(1, 'big') + data.to_bytes(l, 'big') - pass - elif isinstance(data, list) or isinstance(data, tuple): - if len(data) == 0: - return (0xC0).to_bytes(1, 'big') - else: - res = bytearray() - for d in data: - res += pack(d) - l = len(res) - if l <= 55: - return (l + 0xC0).to_bytes(1, 'big') + res - else: - lLen = (l.bit_length() + 7) // 8 - return (lLen + 0xF7).to_bytes(1, 'big') + l.to_bytes(lLen, 'big') + res - else: - raise Exception("Unknown type {} of data".format(str(type(data)))) - - -def get_int(a): - if isinstance(a, int): - return a - if isinstance(a, bytes): - return int.from_bytes(a, 'big') - if a is None: - return a - raise Exception("Invalid convertion from {} to int".format(a)) - - -class Trx: - def __init__(self): - self.nonce = None - self.gasPrice = None - self.gasLimit = None - self.toAddress = None - self.value = None - self.callData = None - self.v = None - self.r = None - self.s = None - - @classmethod - def from_string(cls, s): - t = Trx() - (unpacked, data) = unpack(memoryview(s)) - (nonce, gasPrice, gasLimit, toAddress, value, callData, v, r, s) = unpacked - t.nonce = get_int(nonce) - t.gasPrice = get_int(gasPrice) - t.gasLimit = get_int(gasLimit) - t.toAddress = toAddress - t.value = get_int(value) - t.callData = callData - t.v = get_int(v) - t.r = get_int(r) - t.s = get_int(s) - return t - - def chain_id(self): - # chainid*2 + 35 xxxxx0 + 100011 xxxx0 + 100010 +1 - # chainid*2 + 36 xxxxx0 + 100100 xxxx0 + 100011 +1 - return (self.v - 1) // 2 - 17 - - def __str__(self): - return pack(( - self.nonce, - self.gasPrice, - self.gasLimit, - self.toAddress, - self.value, - self.callData, - self.v, - self.r.to_bytes(32, 'big') if self.r else None, - self.s.to_bytes(32, 'big') if self.s else None) - ).hex() - - def get_msg(self, chain_id=None): - return pack(( - self.nonce, - self.gasPrice, - self.gasLimit, - self.toAddress, - self.value, - self.callData, - chain_id or self.chain_id(), None, None)) - - def hash(self, chain_id=None): - trx = pack(( - self.nonce, - self.gasPrice, - self.gasLimit, - self.toAddress, - self.value, - self.callData, - chain_id or self.chain_id(), None, None)) - return keccak_256(trx).digest() - - def sender(self): - msg_hash = self.hash() - sig = keys.Signature(vrs=[1 if self.v % 2 == 0 else 0, self.r, self.s]) - pub = sig.recover_public_key_from_msg_hash(msg_hash) - return pub.to_canonical_address().hex() - - -class JsonEncoder(json.JSONEncoder): - def default(self, obj): - if isinstance(obj, bytes): - return obj.hex() - return json.JSONEncoder.default(obj) - - -def make_instruction_data_from_tx(instruction, private_key=None): - if isinstance(instruction, dict): - if instruction['chainId'] is None: - raise Exception("chainId value is needed in input dict") - if private_key is None: - raise Exception("Needed private key for transaction creation from fields") - - signed_tx = w3.eth.account.sign_transaction(instruction, private_key) - # print(signed_tx.rawTransaction.hex()) - _trx = Trx.from_string(signed_tx.rawTransaction) - # print(json.dumps(_trx.__dict__, cls=JsonEncoder, indent=3)) - - raw_msg = _trx.get_msg(instruction['chainId']) - sig = keys.Signature(vrs=[1 if _trx.v % 2 == 0 else 0, _trx.r, _trx.s]) - pub = sig.recover_public_key_from_msg_hash(_trx.hash()) - - # print(pub.to_hex()) - - return pub.to_canonical_address(), sig.to_bytes(), raw_msg - elif isinstance(instruction, str): - if instruction[:2] == "0x": - instruction = instruction[2:] - - _trx = Trx.from_string(bytearray.fromhex(instruction)) - # print(json.dumps(_trx.__dict__, cls=JsonEncoder, indent=3)) - - raw_msg = _trx.get_msg() - sig = keys.Signature(vrs=[1 if _trx.v % 2 == 0 else 0, _trx.r, _trx.s]) - pub = sig.recover_public_key_from_msg_hash(_trx.hash()) - - data = pub.to_canonical_address() - data += sig.to_bytes() - data += raw_msg - - return pub.to_canonical_address(), sig.to_bytes(), raw_msg - else: - raise Exception("function gets ") - - -def make_keccak_instruction_data(check_instruction_index, msg_len, data_start): - if 255 < check_instruction_index < 0: - raise Exception("Invalid index for instruction - {}".format(check_instruction_index)) - - check_count = 1 - eth_address_size = 20 - signature_size = 65 - eth_address_offset = data_start - signature_offset = eth_address_offset + eth_address_size - message_data_offset = signature_offset + signature_size - - data = struct.pack("B", check_count) - data += struct.pack(" PublicKey: - return PublicKey(sha256(bytes(base) + bytes(seed, 'utf8') + bytes(program)).digest()) - - -def create_account_with_seed(funding, base, seed, lamports, space, program=PublicKey(EVM_LOADER)): - created = account_with_seed(base, seed, program) - print(f"Created: {created}") - return sp.create_account_with_seed(sp.CreateAccountWithSeedParams( - from_pubkey=funding, - new_account_pubkey=created, - base_pubkey=base, - seed=seed, - lamports=lamports, - space=space, - program_id=program - )) - - -def create_holder_account(account, operator, seed): - return TransactionInstruction( - keys=[ - AccountMeta(pubkey=account, is_signer=False, is_writable=True), - AccountMeta(pubkey=operator, is_signer=True, is_writable=False), - ], - program_id=PublicKey(EVM_LOADER), - data=bytes.fromhex("24") + - len(seed).to_bytes(8, 'little') + seed - ) - - -class solana_cli: - def __init__(self, acc=None): - self.acc = acc - - def call(self, arguments): - if self.acc is None: - cmd = '{} --url {} {}'.format(path_to_solana, SOLANA_URL, arguments) - else: - cmd = '{} --keypair {} --url {} {}'.format(path_to_solana, self.acc.get_path(), SOLANA_URL, arguments) - try: - return subprocess.check_output(cmd, shell=True, universal_newlines=True) - except subprocess.CalledProcessError as err: - print(f"ERR: solana error {err}") - raise - - -class neon_cli: - def __init__(self, verbose_flags=''): - self.verbose_flags = verbose_flags - - def call(self, arguments): - cmd = 'neon-cli {} --loglevel debug --commitment=processed --url {} {}'.format(self.verbose_flags, SOLANA_URL, arguments) - proc_result = subprocess.run(cmd, shell=True, text=True, stdout=subprocess.PIPE, universal_newlines=True) - result = json.loads(proc_result.stdout) - if result["result"] == "error": - error = result["error"] - raise Exception(f"ERR: neon-cli error {error}") - - proc_result.check_returncode() - return result["value"] - - def emulate(self, loader_id, sender, contract, data): - cmd = ["neon-cli", - "--commitment=confirmed", - "--url", SOLANA_URL, - f"--evm_loader={loader_id}", - "emulate" - ] - print('cmd:', cmd) - print("data:", data) - - body = json.dumps({ - "tx": { - "from": sender, - "to": contract, - "data": data - }, - "accounts": [] - }) - - proc_result = subprocess.run(cmd, input=body, text=True, stdout=subprocess.PIPE, universal_newlines=True) - - result = json.loads(proc_result.stdout) - print("EMULATOR RESULT: ") - print(json.dumps(result)) - - if result["result"] == "error": - error = result["error"] - raise Exception(f"ERR: neon-cli error {error}") - - proc_result.check_returncode() - return result["value"] - - def call_contract_get_function(self, evm_loader, sender, contract, function_signature: str, constructor_args=None): - data = abi.function_signature_to_4byte_selector(function_signature) - if constructor_args is not None: - data += constructor_args - result = self.emulate(evm_loader.loader_id, sender.eth_address.hex(), contract.eth_address.hex(), data.hex()) - return result["result"] - - def get_steps_count(self, evm_loader, from_acc, to, data): - if isinstance(to, (Caller, Contract)): - to = to.eth_address.hex() - - result = neon_cli().emulate( - evm_loader.loader_id, - from_acc.eth_address.hex(), - to, - data - ) - - return result["steps_executed"] - - -class RandomAccount: - def __init__(self, path=None): - if path is None: - self.make_random_path() - print(f"New keypair file: {self.path}") - self.generate_key() - else: - self.path = path - self.retrieve_keys() - print('New Public key:', self.acc.public_key()) - print('Private:', self.acc.secret_key()) - - def make_random_path(self): - self.path = os.urandom(5).hex() + ".json" - - def generate_key(self): - cmd_generate = 'solana-keygen new --no-passphrase --outfile {}'.format(self.path) - try: - return subprocess.check_output(cmd_generate, shell=True, universal_newlines=True) - except subprocess.CalledProcessError as err: - print(f"ERR: solana error {err}") - raise - - def retrieve_keys(self): - with open(self.path) as f: - d = json.load(f) - self.acc = Keypair(d[0:32]) - - def get_path(self): - return self.path - - def get_acc(self): - return self.acc - - -class WalletAccount(RandomAccount): - def __init__(self, path): - self.path = path - self.retrieve_keys() - print('Wallet public key:', self.acc.public_key()) - - -class EvmLoader: - def __init__(self, acc: Keypair, program_id=EVM_LOADER): - if program_id is None: - print(f"EVM Loader program address is empty, deploy it") - result = json.loads(solana_cli(acc).call('deploy {}'.format(EVM_LOADER_SO))) - program_id = result['programId'] - EvmLoader.loader_id = PublicKey(program_id) - print("Done\n") - - self.loader_id = EvmLoader.loader_id - self.acc = acc - print("Evm loader program: {}".format(self.loader_id)) - - def create_balance_account(self, ether: Union[str, bytes]) -> PublicKey: - account_pubkey = self.ether2balance(ether) - contract_pubkey = PublicKey(self.ether2program(ether)[0]) - print('createBalanceAccount: {} => {}'.format(ether, account_pubkey)) - - data = bytes([0x30]) + self.ether2bytes(ether) + CHAIN_ID.to_bytes(8, 'little') - trx = Transaction() - trx.add(TransactionInstruction( - program_id=self.loader_id, - data=data, - keys=[ - AccountMeta(pubkey=self.acc.public_key, is_signer=True, is_writable=True), - AccountMeta(pubkey=PublicKey(SYSTEM_ADDRESS), is_signer=False, is_writable=False), - AccountMeta(pubkey=account_pubkey, is_signer=False, is_writable=True), - AccountMeta(pubkey=contract_pubkey, is_signer=False, is_writable=True), - ])) - - send_transaction(solana_client, trx, self.acc) - return account_pubkey - - @staticmethod - def ether2hex(ether: Union[str, bytes]): - if isinstance(ether, str): - if ether.startswith('0x'): - return ether[2:] - return ether - return ether.hex() - - @staticmethod - def ether2bytes(ether: Union[str, bytes]): - if isinstance(ether, str): - if ether.startswith('0x'): - return bytes.fromhex(ether[2:]) - return bytes.fromhex(ether) - return ether - - def ether2seed(self, ether: Union[str, bytes]): - seed = b58encode(ACCOUNT_SEED_VERSION + self.ether2bytes(ether)).decode('utf8') - acc = account_with_seed(self.acc.public_key, seed, self.loader_id) - print('ether2program: {} {} => {}'.format(self.ether2hex(ether), 255, acc)) - return acc, 255 - - def ether2program(self, ether: Union[str, bytes]) -> Tuple[str, int]: - items = PublicKey.find_program_address([ACCOUNT_SEED_VERSION, self.ether2bytes(ether)], PublicKey(EVM_LOADER)) - return str(items[0]), items[1] - - def ether2balance(self, address: Union[str, bytes]) -> PublicKey: - address_bytes = self.ether2bytes(address) - chain_id_bytes = CHAIN_ID.to_bytes(32, 'big') - return PublicKey.find_program_address( - [ACCOUNT_SEED_VERSION, address_bytes, chain_id_bytes], - PublicKey(EVM_LOADER) - )[0] - - def check_account(self, solana): - info = solana_client.get_account_info(solana) - print("checkAccount({}): {}".format(solana, info)) - - def get_neon_nonce(self, account: Union[str, bytes, Caller]) -> int: - if isinstance(account, Caller): - return self.get_neon_nonce(account.eth_address) - - solana_address = self.ether2balance(account) - - info: bytes = get_solana_account_data(solana_client, solana_address, BALANCE_ACCOUNT_LAYOUT.sizeof()) - layout = BALANCE_ACCOUNT_LAYOUT.parse(info) - - return layout.trx_count - - def get_neon_balance(self, account: Union[str, bytes, Caller]) -> int: - if isinstance(account, Caller): - return self.get_neon_balance(account.eth_address) - - solana_address = self.ether2balance(account) - - info: bytes = get_solana_account_data(solana_client, solana_address, BALANCE_ACCOUNT_LAYOUT.sizeof()) - layout = BALANCE_ACCOUNT_LAYOUT.parse(info) - - return int.from_bytes(layout.balance, byteorder="little") - - -def get_solana_balance(account): - return solana_client.get_balance(account, commitment=Confirmed).value - - -def get_solana_account_data(solana_client: Client, account: Union[str, PublicKey, Keypair], expected_length: int) -> bytes: - if isinstance(account, Keypair): - account = account.public_key - print(f"Get account data for {account}") - info = solana_client.get_account_info(account, commitment=Confirmed) - print(f"Result: {info}") - info = info.value - if info is None: - raise Exception("Can't get information about {}".format(account)) - if len(info.data) < expected_length: - print("len(data)({}) < expected_length({})".format(len(info.data), expected_length)) - raise Exception("Wrong data length for account data {}".format(account)) - return info.data - -def send_transaction(client: Client, trx: Transaction, *signers: Keypair, wait_status=Confirmed): - print("Send trx") - result = client.send_transaction(trx, *signers, opts=TxOpts(skip_confirmation=True, preflight_commitment=wait_status)) - print("Result: {}".format(result)) - client.confirm_transaction(result.value, commitment=Confirmed) - return client.get_transaction(result.value, commitment=Confirmed) - - -def evm_step_cost(): - operator_expences = PAYMENT_TO_TREASURE + LAMPORTS_PER_SIGNATURE - return math.floor(operator_expences / EVM_STEPS) - - -def make_new_user(evm_loader: EvmLoader) -> Caller: - key = Keypair.generate() - if get_solana_balance(key.public_key) == 0: - solana_client.request_airdrop(key.public_key, 1000 * 10 ** 9, commitment=Confirmed) - wait_for_account_to_exists(solana_client, key.public_key) - - caller_ether = eth_keys.PrivateKey(key.secret_key[:32]).public_key.to_canonical_address() - caller_solana = evm_loader.ether2program(caller_ether)[0] - caller_balance = evm_loader.ether2balance(caller_ether) - caller_token = get_associated_token_address(caller_balance, NEON_TOKEN_MINT_ID) - - if get_solana_balance(caller_balance) == 0: - print(f"Create Neon account {caller_ether} for user {caller_balance}") - evm_loader.create_balance_account(caller_ether) - - print('Account solana address:', key.public_key) - print(f'Account ether address: {caller_ether.hex()}', ) - print(f'Account solana address: {caller_balance}') - return Caller(key, PublicKey(caller_solana), caller_balance, caller_ether, caller_token) - - -def deposit_neon(evm_loader: EvmLoader, operator_keypair: Keypair, ether_address: Union[str, bytes], amount: int): - balance_pubkey = evm_loader.ether2balance(ether_address) - contract_pubkey = PublicKey(evm_loader.ether2program(ether_address)[0]) - - evm_token_authority = PublicKey.find_program_address([b"Deposit"], evm_loader.loader_id)[0] - evm_pool_key = get_associated_token_address(evm_token_authority, NEON_TOKEN_MINT_ID) - - token_pubkey = get_associated_token_address(operator_keypair.public_key, NEON_TOKEN_MINT_ID) - - with open("evm_loader-keypair.json", "r") as key: - secret_key = json.load(key)[:32] - mint_authority = Keypair.from_secret_key(secret_key) - - trx = Transaction() - trx.add( - make_CreateAssociatedTokenIdempotent( - operator_keypair.public_key, - operator_keypair.public_key, - NEON_TOKEN_MINT_ID - ), - spl.token.instructions.mint_to( - MintToParams( - spl.token.constants.TOKEN_PROGRAM_ID, - NEON_TOKEN_MINT_ID, - token_pubkey, - mint_authority.public_key, - amount - ) - ), - spl.token.instructions.approve( - ApproveParams( - spl.token.constants.TOKEN_PROGRAM_ID, - token_pubkey, - balance_pubkey, - operator_keypair.public_key, - amount, - ) - ), - make_DepositV03( - evm_loader.ether2bytes(ether_address), - CHAIN_ID, - balance_pubkey, - contract_pubkey, - NEON_TOKEN_MINT_ID, - token_pubkey, - evm_pool_key, - spl.token.constants.TOKEN_PROGRAM_ID, - operator_keypair.public_key, - ) - ) - - receipt = send_transaction(solana_client, trx, operator_keypair, mint_authority) - - return receipt - - -def cancel_transaction( - evm_loader: EvmLoader, - tx_hash: HexBytes, - holder_acc: PublicKey, - operator_keypair: Keypair, - additional_accounts: typing.List[PublicKey], -): - # Cancel deployment transaction: - trx = Transaction() - trx.add( - make_Cancel( - evm_loader, - holder_acc, - operator_keypair, - tx_hash, - additional_accounts, - ) - ) - - cancel_receipt = send_transaction(solana_client, trx, operator_keypair) - - print("Cancel receipt:", cancel_receipt) - assert cancel_receipt.value.transaction.meta.err is None - return cancel_receipt - - -def write_transaction_to_holder_account( - signed_tx: SignedTransaction, - holder_account: PublicKey, - operator: Keypair, -): - # Write transaction to transaction holder account - offset = 0 - receipts = [] - rest = signed_tx.rawTransaction - while len(rest): - (part, rest) = (rest[:920], rest[920:]) - trx = Transaction() - trx.add(make_WriteHolder(operator.public_key, holder_account, signed_tx.hash, offset, part)) - receipts.append( - solana_client.send_transaction( - trx, - operator, - opts=TxOpts(skip_confirmation=True, preflight_commitment=Confirmed), - ) - ) - offset += len(part) - - for rcpt in receipts: - solana_client.confirm_transaction(rcpt.value, commitment=Confirmed) - - -def execute_trx_from_instruction(operator: Keypair, evm_loader: EvmLoader, treasury_address: PublicKey, treasury_buffer: bytes, - instruction: SignedTransaction, - additional_accounts, signer: Keypair, - system_program=sp.SYS_PROGRAM_ID) -> SendTransactionResp: - trx = TransactionWithComputeBudget(operator) - trx.add(make_ExecuteTrxFromInstruction(operator, evm_loader, treasury_address, - treasury_buffer, instruction.rawTransaction, additional_accounts, - system_program)) - - return solana_client.send_transaction(trx, signer, opts=TxOpts(skip_preflight=False, skip_confirmation=False, preflight_commitment=Confirmed)) - - -def send_transaction_step_from_instruction(operator: Keypair, evm_loader: EvmLoader, treasury, storage_account, - instruction: SignedTransaction, - additional_accounts, steps_count, signer: Keypair, - system_program=sp.SYS_PROGRAM_ID, index=0) -> SendTransactionResp: - trx = TransactionWithComputeBudget(operator) - trx.add( - make_PartialCallOrContinueFromRawEthereumTX( - index, steps_count, instruction.rawTransaction, - operator, evm_loader, storage_account, treasury, - additional_accounts, system_program - ) - ) - - return solana_client.send_transaction(trx, signer, opts=TxOpts(skip_preflight=False, skip_confirmation=False, preflight_commitment=Confirmed)) - - -def execute_transaction_steps_from_instruction(operator: Keypair, evm_loader: EvmLoader, treasury, storage_account, - instruction: SignedTransaction, - additional_accounts, steps_count=EVM_STEPS, - signer: Keypair = None) -> SendTransactionResp: - signer = operator if signer is None else signer - - index = 0 - done = False - while not done: - response = send_transaction_step_from_instruction(operator, evm_loader, treasury, storage_account, instruction, additional_accounts, EVM_STEPS, signer, index=index) - index += 1 - - receipt = solana_client.get_transaction(response.value, commitment=Confirmed) - if receipt.value.transaction.meta.err: - raise AssertionError(f"Can't deploy contract: {receipt.value.transaction.meta.err}") - for log in receipt.value.transaction.meta.log_messages: - if "exit_status" in log: - done = True - break - if "ExitError" in log: - raise AssertionError(f"EVM Return error in logs: {receipt}") - - return response - - -def send_transaction_step_from_account(operator: Keypair, evm_loader: EvmLoader, treasury, storage_account, - additional_accounts, steps_count, signer: Keypair, - system_program=sp.SYS_PROGRAM_ID, - tag=0x35, index=0) -> GetTransactionResp: - trx = TransactionWithComputeBudget(operator) - trx.add( - make_ExecuteTrxFromAccountDataIterativeOrContinue( - index, steps_count, - operator, evm_loader, storage_account, treasury, - additional_accounts, system_program, tag - ) - ) - return send_transaction(solana_client, trx, signer) - - -def execute_transaction_steps_from_account(operator: Keypair, evm_loader: EvmLoader, treasury, storage_account, - additional_accounts, steps_count=EVM_STEPS, signer: Keypair = None) -> GetTransactionResp: - signer = operator if signer is None else signer - - index = 0 - done = False - while not done: - receipt = send_transaction_step_from_account(operator, evm_loader, treasury, storage_account, additional_accounts, EVM_STEPS, signer, index=index) - index += 1 - - if receipt.value.transaction.meta.err: - raise AssertionError(f"Can't deploy contract: {receipt.value.transaction.meta.err}") - for log in receipt.value.transaction.meta.log_messages: - if "exit_status" in log: - done = True - break - if "ExitError" in log: - raise AssertionError(f"EVM Return error in logs: {receipt}") - - return receipt - - -def execute_transaction_steps_from_account_no_chain_id(operator: Keypair, evm_loader: EvmLoader, treasury, storage_account, - additional_accounts, steps_count=EVM_STEPS, - signer: Keypair = None) -> GetTransactionResp: - signer = operator if signer is None else signer - - index = 0 - done = False - while not done: - receipt = send_transaction_step_from_account(operator, evm_loader, treasury, storage_account, additional_accounts, EVM_STEPS, signer, tag=0x36, index=index) - index += 1 - - if receipt.value.transaction.meta.err: - raise AssertionError(f"Can't deploy contract: {receipt.value.transaction.meta.err}") - for log in receipt.value.transaction.meta.log_messages: - if "exit_status" in log: - done = True - break - if "ExitError" in log: - raise AssertionError(f"EVM Return error in logs: {receipt}") - - return receipt diff --git a/tests/test_cancel_trx.py b/tests/test_cancel_trx.py deleted file mode 100644 index cbb683a9a..000000000 --- a/tests/test_cancel_trx.py +++ /dev/null @@ -1,42 +0,0 @@ -from solana.transaction import Transaction - -from .solana_utils import send_transaction, solana_client, \ - send_transaction_step_from_instruction -from .utils.constants import TAG_FINALIZED_STATE, TAG_STATE -from .utils.contract import make_contract_call_trx -from .utils.storage import create_holder -from .utils.instructions import make_Cancel -from .utils.layouts import FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, STORAGE_ACCOUNT_INFO_LAYOUT -from .utils.transaction_checks import check_holder_account_tag - - -# We need test here two types of transaction -class TestCancelTrx: - - def test_cancel_trx(self, operator_keypair, rw_lock_contract, user_account, treasury_pool, evm_loader): - """EVM can cancel transaction and finalize storage account""" - signed_tx = make_contract_call_trx(user_account, rw_lock_contract, "unchange_storage(uint8,uint8)", [1, 1]) - - storage_account = create_holder(operator_keypair) - trx = send_transaction_step_from_instruction(operator_keypair, evm_loader, treasury_pool, storage_account, - signed_tx, - [rw_lock_contract.solana_address, - rw_lock_contract.balance_account_address, - user_account.balance_account_address], - 1, operator_keypair) - - receipt = solana_client.get_transaction(trx.value) - assert receipt.value.transaction.meta.err is None - check_holder_account_tag(storage_account, STORAGE_ACCOUNT_INFO_LAYOUT, TAG_STATE) - - user_nonce = evm_loader.get_neon_nonce(user_account.eth_address) - trx = Transaction() - trx.add( - make_Cancel(evm_loader, storage_account, operator_keypair, signed_tx.hash, - [rw_lock_contract.solana_address, - rw_lock_contract.balance_account_address, - user_account.balance_account_address]) - ) - send_transaction(solana_client, trx, operator_keypair) - check_holder_account_tag(storage_account, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) - assert user_nonce < evm_loader.get_neon_nonce(user_account.eth_address) diff --git a/tests/test_cli.py b/tests/test_cli.py deleted file mode 100644 index ed60f63df..000000000 --- a/tests/test_cli.py +++ /dev/null @@ -1,153 +0,0 @@ -import os -import random - -import pytest -from solana.rpc.api import Client -from solana.publickey import PublicKey -from solana.rpc.commitment import Confirmed - -from .solana_utils import neon_cli, create_treasury_pool_address -from .solana_utils import solana_client, get_solana_balance, send_transaction -from .utils.constants import CHAIN_ID, SOLANA_URL -from .utils.contract import deploy_contract -from .utils.ethereum import make_eth_transaction -from eth_utils import abi, to_text - -from .utils.instructions import TransactionWithComputeBudget, make_PartialCallOrContinueFromRawEthereumTX -from .utils.storage import create_holder - - -def gen_hash_of_block(size: int) -> str: - """Generates a block hash of the given size""" - try: - block_hash = hex(int.from_bytes(os.urandom(size), "big")) - if bytes.fromhex(block_hash[2:]) or len(block_hash[2:]) != size * 2: - return block_hash - except ValueError: - return gen_hash_of_block(size) - - -def test_emulate_transfer(user_account, evm_loader, session_user): - result = neon_cli().emulate( - evm_loader.loader_id, - user_account.eth_address.hex(), - session_user.eth_address.hex(), - data=None - ) - assert result['exit_status'] == 'succeed', f"The 'exit_status' field is not succeed. Result: {result}" - assert result['steps_executed'] == 1, f"Steps executed amount is not 1. Result: {result}" - assert result['used_gas'] > 0, f"Used gas is less than 0. Result: {result}" - - -def test_emulate_contract_deploy(user_account, evm_loader): - contract_path = pytest.CONTRACTS_PATH / "hello_world.binary" - - with open(contract_path, 'rb') as f: - contract_code = f.read() - - result = neon_cli().emulate( - evm_loader.loader_id, - user_account.eth_address.hex(), - None, - contract_code.hex() - ) - assert result['exit_status'] == 'succeed', f"The 'exit_status' field is not succeed. Result: {result}" - assert result['steps_executed'] > 0, f"Steps executed amount is not 0. Result: {result}" - assert result['used_gas'] > 0, f"Used gas is less than 0. Result: {result}" - - -def test_emulate_call_contract_function(user_account, evm_loader, operator_keypair, treasury_pool): - contract = deploy_contract(operator_keypair, user_account, "hello_world.binary", evm_loader, treasury_pool) - assert contract.eth_address - assert get_solana_balance(contract.solana_address) > 0 - data = abi.function_signature_to_4byte_selector('call_hello_world()') - result = neon_cli().emulate( - evm_loader.loader_id, - user_account.eth_address.hex(), - contract.eth_address.hex(), - data.hex() - ) - - assert result['exit_status'] == 'succeed', f"The 'exit_status' field is not succeed. Result: {result}" - assert result['steps_executed'] > 0, f"Steps executed amount is 0. Result: {result}" - assert result['used_gas'] > 0, f"Used gas is less than 0. Result: {result}" - assert "Hello World" in to_text(result["result"]) - - -def test_neon_elf_params(evm_loader): - result = neon_cli().call(f"--evm_loader={evm_loader.loader_id} neon-elf-params") - some_fields = ['NEON_CHAIN_ID', 'NEON_TOKEN_MINT', 'NEON_REVISION'] - for field in some_fields: - assert field in result, f"The field {field} is not in result {result}" - assert result[field] != "", f"The value for fiels {field} is empty" - - -def test_collect_treasury(evm_loader): - command_args = f"collect-treasury --evm_loader {evm_loader.loader_id}" - index = random.randint(0, 127) - treasury_pool_address = create_treasury_pool_address(index) - result = neon_cli().call(command_args) - main_pool_address = PublicKey(result["pool_address"]) - balance_before = get_solana_balance(main_pool_address) - - amount = random.randint(1, 1000) - trx = solana_client.request_airdrop(treasury_pool_address, amount) - solana_client.confirm_transaction(trx.value, commitment=Confirmed) - result = neon_cli().call(command_args) - - balance_after = get_solana_balance(PublicKey(main_pool_address)) - assert balance_after >= balance_before + amount - - -def test_init_environment(evm_loader): - result = neon_cli().call(f"init-environment --evm_loader {evm_loader.loader_id}") - assert len(result["transactions"]) == 0 - - -def test_get_ether_account_data(evm_loader, user_account): - result = neon_cli().call(f"get-ether-account-data --evm_loader {evm_loader.loader_id} {user_account.eth_address.hex()} {CHAIN_ID}") - - assert str(user_account.balance_account_address) == result[0]["solana_address"] - - assert solana_client.get_account_info(user_account.solana_account.public_key).value is not None - - -def test_get_storage_at(evm_loader, operator_keypair, user_account, treasury_pool): - contract = deploy_contract(operator_keypair, user_account, "hello_world.binary", evm_loader, treasury_pool) - expected_storage = '0000000000000000000000000000000000000000000000000000000000000005' - result = neon_cli().call( - f"get-storage-at --evm_loader {evm_loader.loader_id} {contract.eth_address.hex()} 0x0") - assert result == expected_storage - - -def test_cancel_trx(evm_loader, user_account, rw_lock_contract, default_operator_keypair, treasury_pool): - func_name = abi.function_signature_to_4byte_selector('unchange_storage(uint8,uint8)') - data = (func_name + bytes.fromhex("%064x" % 0x01) + bytes.fromhex("%064x" % 0x01)) - - eth_transaction = make_eth_transaction( - rw_lock_contract.eth_address, - data, - user_account - ) - storage_account = create_holder(default_operator_keypair) - instruction = eth_transaction.rawTransaction - trx = TransactionWithComputeBudget(default_operator_keypair) - trx.add( - make_PartialCallOrContinueFromRawEthereumTX( - 0, 1, instruction, - default_operator_keypair, evm_loader, storage_account, treasury_pool, - [ - rw_lock_contract.solana_address, - user_account.balance_account_address, - ] - ) - ) - solana_client = Client(SOLANA_URL) - - receipt = send_transaction(solana_client, trx, default_operator_keypair) - assert receipt.value.transaction.meta.err is None - user_nonce = evm_loader.get_neon_nonce(user_account.eth_address) - - result = neon_cli().call(f"cancel-trx --evm_loader={evm_loader.loader_id} {storage_account}") - assert result["transaction"] is not None - assert user_nonce < evm_loader.get_neon_nonce(user_account.eth_address) diff --git a/tests/test_execute_trx_from_instruction.py b/tests/test_execute_trx_from_instruction.py deleted file mode 100644 index 46a4a07bb..000000000 --- a/tests/test_execute_trx_from_instruction.py +++ /dev/null @@ -1,329 +0,0 @@ -import random -import string - -import pytest -import solana -import eth_abi -from eth_account.datastructures import SignedTransaction -from eth_keys import keys as eth_keys -from eth_utils import abi, to_text -from hexbytes import HexBytes -from solana.keypair import Keypair -from solana.publickey import PublicKey -from solana.rpc.commitment import Confirmed -from spl.token.instructions import get_associated_token_address - -from .solana_utils import execute_trx_from_instruction, solana_client, neon_cli -from .utils.assert_messages import InstructionAsserts -from .utils.constants import NEON_TOKEN_MINT_ID -from .utils.contract import deploy_contract, make_contract_call_trx -from .utils.ethereum import make_eth_transaction -from .utils.transaction_checks import check_transaction_logs_have_text -from .utils.types import Caller, Contract - - -class TestExecuteTrxFromInstruction: - - def test_simple_transfer_transaction(self, operator_keypair, treasury_pool, - sender_with_tokens: Caller, session_user: Caller, - evm_loader): - amount = 10 - sender_balance_before = evm_loader.get_neon_balance(sender_with_tokens) - recipient_balance_before = evm_loader.get_neon_balance(session_user) - - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, amount) - resp = execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, - signed_tx, - [sender_with_tokens.balance_account_address, - session_user.balance_account_address, - session_user.solana_account_address], - operator_keypair) - sender_balance_after = evm_loader.get_neon_balance(sender_with_tokens) - recipient_balance_after = evm_loader.get_neon_balance(session_user) - assert sender_balance_before - amount == sender_balance_after - assert recipient_balance_before + amount == recipient_balance_after - check_transaction_logs_have_text(resp.value, "exit_status=0x11") - - def test_transfer_transaction_with_non_existing_recipient(self, operator_keypair, treasury_pool, - sender_with_tokens: Caller, - evm_loader): - # recipient account should be created - recipient = Keypair.generate() - - recipient_ether = eth_keys.PrivateKey(recipient.secret_key[:32]).public_key.to_canonical_address() - recipient_solana_address, _ = evm_loader.ether2program(recipient_ether) - recipient_balance_address = evm_loader.ether2balance(recipient_ether) - amount = 10 - signed_tx = make_eth_transaction(recipient_ether, None, sender_with_tokens, amount) - resp = execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, - signed_tx, - [sender_with_tokens.balance_account_address, - recipient_balance_address, - PublicKey(recipient_solana_address)], - operator_keypair) - - recipient_balance_after = evm_loader.get_neon_balance(recipient_ether) - check_transaction_logs_have_text(resp.value, "exit_status=0x11") - - assert recipient_balance_after == amount - - def test_call_contract_function_without_neon_transfer(self, operator_keypair, treasury_pool, - sender_with_tokens: Caller, string_setter_contract: Contract, - evm_loader): - text = ''.join(random.choice(string.ascii_letters) for _ in range(10)) - signed_tx = make_contract_call_trx(sender_with_tokens, string_setter_contract, "set(string)", [text]) - - resp = execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, - signed_tx, - [sender_with_tokens.balance_account_address, - string_setter_contract.solana_address], - operator_keypair) - - check_transaction_logs_have_text(resp.value, "exit_status=0x11") - assert text in to_text( - neon_cli().call_contract_get_function(evm_loader, sender_with_tokens, string_setter_contract, - "get()")) - - def test_call_contract_function_with_neon_transfer(self, operator_keypair, treasury_pool, - sender_with_tokens: Caller, - evm_loader): - transfer_amount = random.randint(1, 1000) - - contract: Contract = deploy_contract(operator_keypair, sender_with_tokens, "string_setter.binary", evm_loader, - treasury_pool) - - sender_balance_before = evm_loader.get_neon_balance(sender_with_tokens) - contract_balance_before = evm_loader.get_neon_balance(contract.eth_address) - - text = ''.join(random.choice(string.ascii_letters) for i in range(10)) - func_name = abi.function_signature_to_4byte_selector('set(string)') - data = func_name + eth_abi.encode(['string'], [text]) - signed_tx = make_eth_transaction(contract.eth_address, data, sender_with_tokens, transfer_amount) - resp = execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, - signed_tx, - [sender_with_tokens.balance_account_address, - contract.balance_account_address, - contract.solana_address], - operator_keypair) - - check_transaction_logs_have_text(resp.value, "exit_status=0x11") - - assert text in to_text(neon_cli().call_contract_get_function(evm_loader, sender_with_tokens, contract, "get()")) - - sender_balance_after = evm_loader.get_neon_balance(sender_with_tokens) - contract_balance_after = evm_loader.get_neon_balance(contract.eth_address) - assert sender_balance_before - transfer_amount == sender_balance_after - assert contract_balance_before + transfer_amount == contract_balance_after - - def test_incorrect_chain_id(self, operator_keypair, treasury_pool, - sender_with_tokens: Caller, session_user: Caller, - evm_loader): - amount = 1 - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, amount, chain_id=1) - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.INVALID_CHAIN_ID): - execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, - signed_tx, - [sender_with_tokens.balance_account_address, - session_user.balance_account_address, - session_user.solana_account_address], - operator_keypair) - - def test_incorrect_nonce(self, operator_keypair, treasury_pool, - sender_with_tokens: Caller, session_user: Caller, - evm_loader): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) - - execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, - signed_tx, - [sender_with_tokens.balance_account_address, - session_user.balance_account_address, - session_user.solana_account_address], - operator_keypair) - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.INVALID_NONCE): - execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, - signed_tx, - [sender_with_tokens.balance_account_address, - session_user.balance_account_address, - session_user.solana_account_address], - operator_keypair) - - def test_insufficient_funds(self, operator_keypair, treasury_pool, evm_loader, - sender_with_tokens: Caller, session_user: Caller): - user_balance = evm_loader.get_neon_balance(session_user) - - signed_tx = make_eth_transaction(sender_with_tokens.eth_address, None, session_user, user_balance + 1) - - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.INSUFFICIENT_FUNDS): - execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, - signed_tx, - [sender_with_tokens.balance_account_address, - session_user.balance_account_address, - session_user.solana_account_address], - operator_keypair) - - def test_gas_limit_reached(self, operator_keypair, treasury_pool, - session_user: Caller, sender_with_tokens: Caller, - evm_loader): - amount = 10 - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, amount, gas=1) - - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.OUT_OF_GAS): - execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, - signed_tx, - [sender_with_tokens.balance_account_address, - session_user.balance_account_address, - session_user.solana_account_address], - operator_keypair) - - def test_sender_missed_in_remaining_accounts(self, operator_keypair, treasury_pool, - session_user: Caller, sender_with_tokens: Caller, - evm_loader): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.ADDRESS_MUST_BE_PRESENT): - execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, - signed_tx, - [session_user.balance_account_address, - session_user.solana_account_address], - operator_keypair) - - def test_recipient_missed_in_remaining_accounts(self, operator_keypair, treasury_pool, - sender_with_tokens: Caller, session_user: Caller, - evm_loader): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.ADDRESS_MUST_BE_PRESENT): - execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, - signed_tx, - [sender_with_tokens.balance_account_address], - operator_keypair) - - def test_incorrect_treasure_pool(self, operator_keypair, - sender_with_tokens: Caller, session_user: Caller, - evm_loader): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) - - treasury_buffer = b'\x02\x00\x00\x00' - treasury_pool = Keypair().public_key - - error = str.format(InstructionAsserts.INVALID_ACCOUNT, treasury_pool) - with pytest.raises(solana.rpc.core.RPCException, match=error): - execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool, treasury_buffer, - signed_tx, - [], - operator_keypair) - - def test_incorrect_treasure_index(self, operator_keypair, treasury_pool, - sender_with_tokens: Caller, session_user: Caller, - evm_loader): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) - treasury_buffer = b'\x03\x00\x00\x00' - - error = str.format(InstructionAsserts.INVALID_ACCOUNT, treasury_pool.account) - with pytest.raises(solana.rpc.core.RPCException, match=error): - execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_buffer, - signed_tx, - [], - operator_keypair) - - def test_incorrect_operator_account(self, evm_loader, treasury_pool, - session_user: Caller, sender_with_tokens: Caller): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) - fake_operator = Keypair() - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.ACC_NOT_FOUND): - execute_trx_from_instruction(fake_operator, evm_loader, treasury_pool.account, treasury_pool.buffer, - signed_tx, - [sender_with_tokens.balance_account_address, - session_user.balance_account_address, - session_user.solana_account_address], - fake_operator) - - def test_operator_is_not_in_white_list(self, sender_with_tokens, evm_loader, treasury_pool, - session_user): - # now any user can send transactions through "execute transaction from instruction" instruction - - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) - resp = execute_trx_from_instruction(sender_with_tokens.solana_account, evm_loader, - treasury_pool.account, - treasury_pool.buffer, - signed_tx, - [sender_with_tokens.balance_account_address, - session_user.balance_account_address, - session_user.solana_account_address], - sender_with_tokens.solana_account) - check_transaction_logs_have_text(resp.value, "exit_status=0x11") - - def test_incorrect_system_program(self, sender_with_tokens, operator_keypair, evm_loader, treasury_pool, - session_user): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) - fake_sys_program_id = Keypair().public_key - with pytest.raises(solana.rpc.core.RPCException, - match=str.format(InstructionAsserts.NOT_SYSTEM_PROGRAM, fake_sys_program_id)): - execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, - treasury_pool.buffer, - signed_tx, - [], - operator_keypair, system_program=fake_sys_program_id) - - def test_operator_does_not_have_enough_founds(self, evm_loader, treasury_pool, - session_user: Caller, sender_with_tokens: Caller): - key = Keypair.generate() - caller_ether = eth_keys.PrivateKey(key.secret_key[:32]).public_key.to_canonical_address() - caller, caller_nonce = evm_loader.ether2program(caller_ether) - caller_token = get_associated_token_address(PublicKey(caller), NEON_TOKEN_MINT_ID) - evm_loader.create_balance_account(caller_ether) - - operator_without_money = Caller(key, PublicKey(caller), caller_ether, caller_nonce, caller_token) - - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) - with pytest.raises(solana.rpc.core.RPCException, - match="Attempt to debit an account but found no record of a prior credit"): - execute_trx_from_instruction(operator_without_money.solana_account, evm_loader, treasury_pool.account, - treasury_pool.buffer, - signed_tx, - [sender_with_tokens.balance_account_address, - session_user.balance_account_address, - session_user.solana_account_address], - operator_without_money.solana_account) - - def test_transaction_with_access_list(self, operator_keypair, treasury_pool, sender_with_tokens, - evm_loader, calculator_contract, calculator_caller_contract): - access_list = ( - { - "address": '0x' + calculator_contract.eth_address.hex(), - "storageKeys": ( - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000001", - ) - }, - ) - signed_tx = make_contract_call_trx(sender_with_tokens, calculator_caller_contract, "callCalculator()", [], - access_list=access_list) - - resp = execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, - signed_tx, - [sender_with_tokens.balance_account_address, - calculator_caller_contract.solana_address, - calculator_contract.solana_address], - operator_keypair) - - check_transaction_logs_have_text(resp.value, "exit_status=0x12") - - def test_old_trx_type_with_leading_zeros(self, sender_with_tokens, operator_keypair, evm_loader, - calculator_caller_contract, calculator_contract, treasury_pool): - signed_tx = make_contract_call_trx(sender_with_tokens, calculator_caller_contract, "callCalculator()", []) - new_raw_trx = HexBytes(bytes([0]) + signed_tx.rawTransaction) - - signed_tx_new = SignedTransaction( - rawTransaction=new_raw_trx, - hash=signed_tx.hash, - r=signed_tx.r, - s=signed_tx.s, - v=signed_tx.v, - ) - - resp = execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, - signed_tx_new, - [sender_with_tokens.balance_account_address, - calculator_caller_contract.solana_address, - calculator_contract.solana_address], - operator_keypair) - check_transaction_logs_have_text(resp.value, "exit_status=0x12") diff --git a/tests/test_holder_account.py b/tests/test_holder_account.py deleted file mode 100644 index a0ec3198b..000000000 --- a/tests/test_holder_account.py +++ /dev/null @@ -1,164 +0,0 @@ -from hashlib import sha256 -from random import randrange - -import pytest -import solana -from solana.publickey import PublicKey -from solana.rpc.commitment import Confirmed -from solana.rpc.types import TxOpts -from solana.transaction import Transaction - -from . import solana_utils -from .solana_utils import solana_client, write_transaction_to_holder_account, \ - send_transaction_step_from_account, get_solana_balance, execute_transaction_steps_from_account -from .utils.assert_messages import InstructionAsserts -from .utils.constants import EVM_LOADER, TAG_STATE -from .utils.contract import make_deployment_transaction, make_contract_call_trx -from .utils.ethereum import make_eth_transaction -from .utils.instructions import make_WriteHolder -from .utils.layouts import STORAGE_ACCOUNT_INFO_LAYOUT, HOLDER_ACCOUNT_INFO_LAYOUT -from .utils.storage import create_holder, delete_holder - - -def transaction_from_holder(key: PublicKey): - data = solana_client.get_account_info(key, commitment=Confirmed).value.data - header = HOLDER_ACCOUNT_INFO_LAYOUT.parse(data) - - return data[HOLDER_ACCOUNT_INFO_LAYOUT.sizeof():][:header.len] - - -def test_create_holder_account(operator_keypair): - holder_acc = create_holder(operator_keypair) - info = solana_client.get_account_info(holder_acc, commitment=Confirmed) - assert info.value is not None, "Holder account is not created" - assert info.value.lamports == 1000000000, "Account balance is not correct" - - -def test_create_the_same_holder_account_by_another_user(operator_keypair, session_user): - seed = str(randrange(1000000)) - storage = PublicKey( - sha256(bytes(operator_keypair.public_key) + bytes(seed, 'utf8') + bytes(PublicKey(EVM_LOADER))).digest()) - create_holder(operator_keypair, seed=seed, storage=storage) - - trx = Transaction() - trx.add( - solana_utils.create_account_with_seed(session_user.solana_account.public_key, - session_user.solana_account.public_key, seed, 10 ** 9, 128 * 1024), - solana_utils.create_holder_account(storage, session_user.solana_account.public_key, bytes(seed, 'utf8')) - ) - - error = str.format(InstructionAsserts.INVALID_ACCOUNT, storage) - with pytest.raises(solana.rpc.core.RPCException, match=error): - solana_utils.send_transaction(solana_client, trx, session_user.solana_account) - - -def test_write_tx_to_holder(operator_keypair, session_user, second_session_user, evm_loader): - holder_acc = create_holder(operator_keypair) - signed_tx = make_eth_transaction(second_session_user.eth_address, None, session_user, 10) - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - assert signed_tx.rawTransaction == transaction_from_holder(holder_acc), \ - "Account data is not correct" - - -def test_write_tx_to_holder_in_parts(operator_keypair, session_user): - holder_acc = create_holder(operator_keypair) - contract_filename = "ERC20ForSplFactory.binary" - - signed_tx = make_deployment_transaction(session_user, contract_filename) - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - assert signed_tx.rawTransaction == transaction_from_holder(holder_acc), \ - "Account data is not correct" - - -def test_write_tx_to_holder_by_no_owner(operator_keypair, session_user, second_session_user, evm_loader): - holder_acc = create_holder(operator_keypair) - - signed_tx = make_eth_transaction(second_session_user.eth_address, None, session_user, 10) - with pytest.raises(solana.rpc.core.RPCException, match="invalid owner"): - write_transaction_to_holder_account(signed_tx, holder_acc, session_user.solana_account) - - -def test_delete_holder(operator_keypair): - holder_acc = create_holder(operator_keypair) - delete_holder(holder_acc, operator_keypair, operator_keypair) - info = solana_client.get_account_info(holder_acc, commitment=Confirmed) - assert info.value is None, "Holder account isn't deleted" - - -def test_success_refund_after_holder_deliting(operator_keypair): - holder_acc = create_holder(operator_keypair) - - pre_storage = get_solana_balance(holder_acc) - pre_acc = get_solana_balance(operator_keypair.public_key) - - delete_holder(holder_acc, operator_keypair, operator_keypair) - - post_acc = get_solana_balance(operator_keypair.public_key) - - assert pre_storage + pre_acc, post_acc + 5000 - - -def test_delete_holder_by_no_owner(operator_keypair, user_account): - holder_acc = create_holder(operator_keypair) - with pytest.raises(solana.rpc.core.RPCException, match="invalid owner"): - delete_holder(holder_acc, user_account.solana_account, user_account.solana_account) - - -def test_write_to_not_finalized_holder(rw_lock_contract, user_account, evm_loader, operator_keypair, treasury_pool, - new_holder_acc): - signed_tx = make_contract_call_trx(user_account, rw_lock_contract, "unchange_storage(uint8,uint8)", [1, 1]) - write_transaction_to_holder_account(signed_tx, new_holder_acc, operator_keypair) - - send_transaction_step_from_account(operator_keypair, evm_loader, treasury_pool, new_holder_acc, - [user_account.solana_account_address, - user_account.balance_account_address, - rw_lock_contract.solana_address], 1, operator_keypair) - account_data = solana_client.get_account_info(new_holder_acc, commitment=Confirmed).value.data - parsed_data = STORAGE_ACCOUNT_INFO_LAYOUT.parse(account_data) - assert parsed_data.tag == TAG_STATE - - signed_tx2 = make_contract_call_trx(user_account, rw_lock_contract, "unchange_storage(uint8,uint8)", [1, 1]) - - with pytest.raises(solana.rpc.core.RPCException, match="invalid tag"): - write_transaction_to_holder_account(signed_tx2, new_holder_acc, operator_keypair) - - -def test_write_to_finalized_holder(rw_lock_contract, session_user, evm_loader, operator_keypair, treasury_pool, - new_holder_acc): - signed_tx = make_contract_call_trx(session_user, rw_lock_contract, "unchange_storage(uint8,uint8)", [1, 1]) - write_transaction_to_holder_account(signed_tx, new_holder_acc, operator_keypair) - - execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, new_holder_acc, - [session_user.solana_account_address, - session_user.balance_account_address, - rw_lock_contract.solana_address]) - signed_tx2 = make_contract_call_trx(session_user, rw_lock_contract, "unchange_storage(uint8,uint8)", [1, 1]) - - write_transaction_to_holder_account(signed_tx2, new_holder_acc, operator_keypair) - assert signed_tx2.rawTransaction == transaction_from_holder(new_holder_acc), \ - "Account data is not correct" - - -def test_holder_write_integer_overflow(operator_keypair, holder_acc): - overflow_offset = int(0xFFFFFFFFFFFFFFFF) - - trx = Transaction() - trx.add(make_WriteHolder(operator_keypair.public_key, holder_acc, b"\x00" * 32, overflow_offset, b"\x00" * 1)) - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.HOLDER_OVERFLOW): - solana_client.send_transaction( - trx, - operator_keypair, - opts=TxOpts(skip_confirmation=True, preflight_commitment=Confirmed), - ) - -def test_holder_write_account_size_overflow(operator_keypair, holder_acc): - overflow_offset = int(0xFFFFFFFF) - - trx = Transaction() - trx.add(make_WriteHolder(operator_keypair.public_key, holder_acc, b"\x00" * 32, overflow_offset, b"\x00" * 1)) - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.HOLDER_INSUFFICIENT_SIZE): - solana_client.send_transaction( - trx, - operator_keypair, - opts=TxOpts(skip_confirmation=True, preflight_commitment=Confirmed), - ) diff --git a/tests/test_neon_core_api.py b/tests/test_neon_core_api.py deleted file mode 100644 index 740b34d4e..000000000 --- a/tests/test_neon_core_api.py +++ /dev/null @@ -1,64 +0,0 @@ -import pytest -from eth_utils import abi, to_text - -from .utils.contract import deploy_contract -from .solana_utils import solana_client - - -def test_get_storage_at(neon_api_client, operator_keypair, user_account, evm_loader, treasury_pool): - contract = deploy_contract(operator_keypair, user_account, "hello_world.binary", evm_loader, treasury_pool) - storage = neon_api_client.get_storage_at(contract.eth_address.hex())["value"] - zero_array = [0 for _ in range(31)] - assert storage == zero_array + [5] - - storage = neon_api_client.get_storage_at(contract.eth_address.hex(), index='0x2')["value"] - assert storage == zero_array + [0] - - -def test_get_ether_account_data(neon_api_client, user_account): - result = neon_api_client.get_ether_account_data(user_account.eth_address.hex())['value'] - assert str(user_account.balance_account_address) == result[0]["solana_address"] - assert solana_client.get_account_info(user_account.solana_account.public_key).value is not None - - -def test_emulate_transfer(neon_api_client, user_account, session_user): - result = neon_api_client.emulate(user_account.eth_address.hex(), - session_user.eth_address.hex())["value"] - assert result['exit_status'] == 'succeed', f"The 'exit_status' field is not succeed. Result: {result}" - assert result['steps_executed'] == 1, f"Steps executed amount is not 1. Result: {result}" - assert result['used_gas'] > 0, f"Used gas is less than 0. Result: {result}" - - -def test_emulate_contract_deploy(neon_api_client, user_account): - contract_path = pytest.CONTRACTS_PATH / "hello_world.binary" - - with open(contract_path, 'rb') as f: - contract_code = f.read() - result = neon_api_client.emulate(user_account.eth_address.hex(), - contract=None, data=contract_code)["value"] - assert result['exit_status'] == 'succeed', f"The 'exit_status' field is not succeed. Result: {result}" - assert result['steps_executed'] > 100, f"Steps executed amount is wrong. Result: {result}" - assert result['used_gas'] > 0, f"Used gas is less than 0. Result: {result}" - - -def test_emulate_call_contract_function(neon_api_client, operator_keypair, treasury_pool, evm_loader, user_account): - contract = deploy_contract(operator_keypair, user_account, "hello_world.binary", evm_loader, treasury_pool) - assert contract.eth_address - data = abi.function_signature_to_4byte_selector('call_hello_world()') - - result = neon_api_client.emulate(user_account.eth_address.hex(), - contract=contract.eth_address.hex(), data=data)["value"] - - assert result['exit_status'] == 'succeed', f"The 'exit_status' field is not succeed. Result: {result}" - assert result['steps_executed'] > 0, f"Steps executed amount is 0. Result: {result}" - assert result['used_gas'] > 0, f"Used gas is less than 0. Result: {result}" - assert "Hello World" in to_text(result["result"]) - - -def test_emulate_with_small_amount_of_steps(neon_api_client, evm_loader, user_account): - contract_path = pytest.CONTRACTS_PATH / "hello_world.binary" - with open(contract_path, 'rb') as f: - contract_code = f.read() - result = neon_api_client.emulate(user_account.eth_address.hex(), - contract=None, data=contract_code, max_steps_to_execute=10) - assert result['error'] == 'Too many steps' diff --git a/tests/test_parallel.py b/tests/test_parallel.py deleted file mode 100644 index c3dc56f46..000000000 --- a/tests/test_parallel.py +++ /dev/null @@ -1,166 +0,0 @@ -from typing import Any -from unittest import TestCase - -from _pytest.fixtures import fixture -from solana.keypair import Keypair -from solana.publickey import PublicKey -from solana.rpc.core import RPCException - -from .solana_utils import EvmLoader, solana_client, get_solana_account_data, make_new_user, deposit_neon, \ - cancel_transaction, send_transaction_step_from_account, execute_trx_from_instruction -from .utils.contract import write_transaction_to_holder_account, make_deployment_transaction -from .utils.ethereum import create_contract_address, make_eth_transaction -from .utils.layouts import CONTRACT_ACCOUNT_LAYOUT -from .utils.storage import create_holder -from .utils.types import Caller, TreasuryPool - -EVM_STEPS_COUNT = 0xFFFFFFFF -ONE_TOKEN = 10 ** 9 -BIG_CONTRACT_FILENAME = "BigContract.binary" -MAX_PERMITTED_DATA_INCREASE = 10240 - - -class ParallelTransactionsTest(TestCase): - @fixture(autouse=True) - def prepare_fixture( - self, - user_account: Caller, - evm_loader: EvmLoader, - operator_keypair: Keypair, - treasury_pool: TreasuryPool, - ): - self.user_account = user_account - self.evm_loader = evm_loader - self.operator_keypair = operator_keypair - self.treasury_pool = treasury_pool - self.second_account = make_new_user(evm_loader) - - def test_create_same_accounts(self): - cases = [ - [2], - [3], - [4], - ] - - for case in cases: - iterations = case[0] - with self.subTest(iterations=iterations): - self.create_same_accounts_subtest(iterations) - - def create_same_accounts_subtest(self, iterations: int): - deposit_neon(self.evm_loader, self.operator_keypair, self.user_account.eth_address, ONE_TOKEN) - deposit_neon(self.evm_loader, self.operator_keypair, self.second_account.eth_address, ONE_TOKEN) - - contract = create_contract_address(self.user_account, self.evm_loader) - holder_acc = create_holder(self.operator_keypair) - deployment_tx = make_deployment_transaction(self.user_account, BIG_CONTRACT_FILENAME) - write_transaction_to_holder_account(deployment_tx, holder_acc, self.operator_keypair) - - # First N iterations - for i in range(iterations): - deployment_receipt = send_transaction_step_from_account(self.operator_keypair, - self.evm_loader, - self.treasury_pool, - holder_acc, - [contract.balance_account_address, - contract.solana_address, - self.user_account.balance_account_address, - self.user_account.solana_account_address], - EVM_STEPS_COUNT, - self.operator_keypair, - index=i) - - assert not ParallelTransactionsTest.check_iteration_deployed(deployment_receipt) - - # Transferring to the same account in order to break deployment - ParallelTransactionsTest.transfer( - self.second_account, - contract.eth_address, - ONE_TOKEN, - self.evm_loader, - self.operator_keypair, - self.treasury_pool, - ) - - # Trying to finish deployment (expected to fail) - try: - send_transaction_step_from_account(self.operator_keypair, - self.evm_loader, - self.treasury_pool, - holder_acc, - [contract.balance_account_address, - contract.solana_address, - self.user_account.balance_account_address, - self.user_account.solana_account_address], - EVM_STEPS_COUNT, - self.operator_keypair) - - assert False, 'Deployment expected to fail' - except RPCException as e: - ParallelTransactionsTest.check_account_initialized_in_another_trx_exception(e, contract.balance_account_address) - - # Cancel deployment transaction: - cancel_transaction( - self.evm_loader, - deployment_tx.hash, - holder_acc, - self.operator_keypair, - [contract.balance_account_address, - contract.solana_address, - self.user_account.balance_account_address, - self.user_account.solana_account_address], - ) - - @staticmethod - def check_iteration_deployed(receipt: Any) -> bool: - if receipt.value.transaction.meta.err: - raise AssertionError(f"Can't deploy contract: {receipt.value.transaction.meta.err}") - - for log in receipt.value.transaction.meta.log_messages: - if "exit_status" in log: - return True - if "ExitError" in log: - raise AssertionError(f"EVM Return error in logs: {receipt}") - return False - - @staticmethod - def transfer( - src_account: Caller, - dst_addr: bytes, - value: int, - evm_loader: EvmLoader, - operator_keypair: Keypair, - treasury_pool: TreasuryPool, - ): - message = make_eth_transaction( - dst_addr, - bytes(), - src_account, - value, - ) - - dst_solana_account, _ = evm_loader.ether2program(dst_addr) - dst_balance_account = evm_loader.ether2balance(dst_addr) - - trx = execute_trx_from_instruction(operator_keypair, evm_loader, treasury_pool.account, treasury_pool.buffer, - message, - [dst_balance_account, - PublicKey(dst_solana_account), - src_account.balance_account_address], - operator_keypair) - receipt = solana_client.get_transaction(trx.value) - print("Transfer receipt:", receipt) - assert receipt.value.transaction.meta.err is None - - return receipt - - @staticmethod - def check_account_initialized_in_another_trx_exception(exception: RPCException, solana_address: PublicKey): - error = exception.args[0] - print("error:", error) - - for log in error.data.logs: - if f'Account {solana_address} - was empty, created by another transaction' in log: - return - - assert False, "Search string not found in Solana logs" diff --git a/tests/test_step_instructions_work_the_same.py b/tests/test_step_instructions_work_the_same.py deleted file mode 100644 index e7e4cacbb..000000000 --- a/tests/test_step_instructions_work_the_same.py +++ /dev/null @@ -1,62 +0,0 @@ -from .solana_utils import solana_client, execute_transaction_steps_from_account, write_transaction_to_holder_account, \ - execute_transaction_steps_from_instruction -from .utils.contract import make_deployment_transaction -from .utils.ethereum import make_eth_transaction, create_contract_address -from .utils.storage import create_holder - - - -class TestTransactionStepFromAccount: - - def test_simple_transfer_transaction(self, operator_keypair, treasury_pool, evm_loader, - sender_with_tokens, session_user, holder_acc): - amount = 10 - - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, amount) - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - resp_from_acc = execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, - [session_user.solana_account_address, - session_user.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address], 0).value - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, amount) - signature = execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, - signed_tx, [session_user.solana_account_address, - session_user.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address], - 0) - resp_from_inst = solana_client.get_transaction(signature.value).value - assert resp_from_acc.transaction.meta.fee == resp_from_inst.transaction.meta.fee - assert resp_from_acc.transaction.meta.inner_instructions == resp_from_inst.transaction.meta.inner_instructions - for i in range(len(resp_from_acc.transaction.meta.post_balances)): - assert resp_from_acc.transaction.meta.post_balances[i] - resp_from_acc.transaction.meta.pre_balances[i] == \ - resp_from_inst.transaction.meta.post_balances[i] - resp_from_inst.transaction.meta.pre_balances[i] - - def test_deploy_contract(self, operator_keypair, holder_acc, treasury_pool, evm_loader, sender_with_tokens): - contract_filename = "small.binary" - contract = create_contract_address(sender_with_tokens, evm_loader) - - signed_tx = make_deployment_transaction(sender_with_tokens, contract_filename) - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - - resp_from_acc = execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, - [contract.solana_address, - contract.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address]).value - signed_tx = make_deployment_transaction(sender_with_tokens, contract_filename) - holder_acc = create_holder(operator_keypair) - contract = create_contract_address(sender_with_tokens, evm_loader) - - signature = execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, - signed_tx, [contract.solana_address, - contract.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address]) - resp_from_inst = solana_client.get_transaction(signature.value).value - assert resp_from_acc.transaction.meta.fee == resp_from_inst.transaction.meta.fee - assert len(resp_from_acc.transaction.meta.inner_instructions) == len( - resp_from_inst.transaction.meta.inner_instructions) - assert len(resp_from_acc.transaction.transaction.message.account_keys) == len( - resp_from_acc.transaction.transaction.message.account_keys) diff --git a/tests/test_transaction_step_from_account.py b/tests/test_transaction_step_from_account.py deleted file mode 100644 index a3bdf9343..000000000 --- a/tests/test_transaction_step_from_account.py +++ /dev/null @@ -1,557 +0,0 @@ -import random -import string -import time - -import eth_abi -import pytest -import solana -from eth_keys import keys as eth_keys -from eth_utils import abi, to_text, to_int -from solana.keypair import Keypair -from solana.publickey import PublicKey -from solana.rpc.commitment import Processed, Confirmed -from solana.rpc.types import TxOpts - -from .solana_utils import solana_client, neon_cli, execute_transaction_steps_from_account, \ - write_transaction_to_holder_account, create_treasury_pool_address, send_transaction_step_from_account -from .test_cli import gen_hash_of_block -from .utils.assert_messages import InstructionAsserts -from .utils.constants import TAG_FINALIZED_STATE -from .utils.contract import make_deployment_transaction, make_contract_call_trx, deploy_contract -from .utils.ethereum import make_eth_transaction, create_contract_address -from .utils.instructions import TransactionWithComputeBudget, make_ExecuteTrxFromAccountDataIterativeOrContinue -from .utils.layouts import FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT -from .utils.storage import create_holder -from .utils.transaction_checks import check_transaction_logs_have_text, check_holder_account_tag -from .utils.types import TreasuryPool - - -def generate_access_lists(): - addr1 = gen_hash_of_block(20) - addr2 = gen_hash_of_block(20) - key1, key2, key3, key4 = (f"0x000000000000000000000000000000000000000000000000000000000000000{item}" for item in - (0, 1, 2, 3)) - return (({"address": addr1, "storageKeys": []},), - ({"address": addr1, "storageKeys": (key1, key2, key3, key4)},), - ({"address": addr1, "storageKeys": (key1, key2)}, {"address": addr2, "storageKeys": []}), - ({"address": addr1, "storageKeys": (key1, key2)}, {"address": addr2, "storageKeys": (key3,)})) - - -class TestTransactionStepFromAccount: - - def test_simple_transfer_transaction(self, operator_keypair, treasury_pool, evm_loader, - sender_with_tokens, session_user, holder_acc): - amount = 10 - sender_balance_before = evm_loader.get_neon_balance(sender_with_tokens) - recipient_balance_before = evm_loader.get_neon_balance(session_user) - - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, amount) - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - resp = execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, - [session_user.solana_account_address, - session_user.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address], 0) - - sender_balance_after = evm_loader.get_neon_balance(sender_with_tokens) - recipient_balance_after = evm_loader.get_neon_balance(session_user) - - check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) - check_transaction_logs_have_text(resp.value.transaction.transaction.signatures[0], "exit_status=0x11") - assert sender_balance_before - amount == sender_balance_after - assert recipient_balance_before + amount == recipient_balance_after - - def test_deploy_contract(self, operator_keypair, holder_acc, treasury_pool, evm_loader, sender_with_tokens): - contract_filename = "hello_world.binary" - contract = create_contract_address(sender_with_tokens, evm_loader) - - signed_tx = make_deployment_transaction(sender_with_tokens, contract_filename) - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - - contract_path = pytest.CONTRACTS_PATH / contract_filename - with open(contract_path, 'rb') as f: - contract_code = f.read() - - steps_count = neon_cli().get_steps_count(evm_loader, sender_with_tokens, None, contract_code.hex()) - resp = execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, - [contract.solana_address, - contract.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address], - steps_count) - check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) - check_transaction_logs_have_text(resp.value.transaction.transaction.signatures[0], "exit_status=0x12") - - def test_call_contract_function_without_neon_transfer(self, operator_keypair, holder_acc, treasury_pool, - sender_with_tokens, evm_loader, string_setter_contract): - text = ''.join(random.choice(string.ascii_letters) for _ in range(10)) - signed_tx = make_contract_call_trx(sender_with_tokens, string_setter_contract, "set(string)", [text]) - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - - resp = execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, - [string_setter_contract.solana_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address]) - - check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) - check_transaction_logs_have_text(resp.value.transaction.transaction.signatures[0], "exit_status=0x11") - - assert text in to_text( - neon_cli().call_contract_get_function(evm_loader, sender_with_tokens, string_setter_contract, - "get()")) - - def test_call_contract_function_with_neon_transfer(self, operator_keypair, treasury_pool, - sender_with_tokens, string_setter_contract, holder_acc, - evm_loader): - transfer_amount = random.randint(1, 1000) - - sender_balance_before = evm_loader.get_neon_balance(sender_with_tokens) - contract_balance_before = evm_loader.get_neon_balance(string_setter_contract.eth_address) - - text = ''.join(random.choice(string.ascii_letters) for _ in range(10)) - - signed_tx = make_contract_call_trx(sender_with_tokens, string_setter_contract, "set(string)", [text], - value=transfer_amount) - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - - resp = execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, - [string_setter_contract.solana_address, - string_setter_contract.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address]) - - check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) - check_transaction_logs_have_text(resp.value.transaction.transaction.signatures[0], "exit_status=0x11") - - sender_balance_after = evm_loader.get_neon_balance(sender_with_tokens) - contract_balance_after = evm_loader.get_neon_balance(string_setter_contract.eth_address) - assert sender_balance_before - transfer_amount == sender_balance_after - assert contract_balance_before + transfer_amount == contract_balance_after - - assert text in to_text( - neon_cli().call_contract_get_function(evm_loader, sender_with_tokens, string_setter_contract, - "get()")) - - def test_transfer_transaction_with_non_existing_recipient(self, operator_keypair, holder_acc, treasury_pool, - sender_with_tokens, evm_loader): - # recipient account should be created - recipient = Keypair.generate() - recipient_ether = eth_keys.PrivateKey(recipient.secret_key[:32]).public_key.to_canonical_address() - recipient_solana_address, _ = evm_loader.ether2program(recipient_ether) - recipient_balance_address = evm_loader.ether2balance(recipient_ether) - amount = 10 - signed_tx = make_eth_transaction(recipient_ether, None, sender_with_tokens, amount) - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - - resp = execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, - [PublicKey(recipient_solana_address), - recipient_balance_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address], 0) - - recipient_balance_after = evm_loader.get_neon_balance(recipient_ether) - check_transaction_logs_have_text(resp.value.transaction.transaction.signatures[0], "exit_status=0x11") - - assert recipient_balance_after == amount - - def test_incorrect_chain_id(self, operator_keypair, holder_acc, treasury_pool, - sender_with_tokens, session_user, evm_loader): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1, chain_id=1) - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.INVALID_CHAIN_ID): - execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, - [session_user.solana_account_address, - session_user.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address], 0) - - def test_incorrect_nonce(self, operator_keypair, treasury_pool, sender_with_tokens, evm_loader, session_user, - holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - - execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, - [session_user.solana_account_address, - session_user.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address], 0) - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.INVALID_NONCE): - execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, - [session_user.solana_account_address, - session_user.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address], 0) - - def test_run_finalized_transaction(self, operator_keypair, treasury_pool, sender_with_tokens, evm_loader, - session_user, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - - execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, - [session_user.solana_account_address, - session_user.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address], 0) - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.TRX_ALREADY_FINALIZED): - execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, - [session_user.solana_account_address, - session_user.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address], 0) - - def test_insufficient_funds(self, operator_keypair, treasury_pool, evm_loader, session_user, - holder_acc, sender_with_tokens): - user_balance = evm_loader.get_neon_balance(session_user) - - signed_tx = make_eth_transaction(sender_with_tokens.eth_address, None, session_user, user_balance + 1) - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.INSUFFICIENT_FUNDS): - execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, - [session_user.solana_account_address, - session_user.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address], 0) - - def test_gas_limit_reached(self, operator_keypair, treasury_pool, session_user, evm_loader, sender_with_tokens, - holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 10, gas=1) - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.OUT_OF_GAS): - execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, - [session_user.solana_account_address, - session_user.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address], 0) - - def test_sender_missed_in_remaining_accounts(self, operator_keypair, treasury_pool, session_user, - sender_with_tokens, evm_loader, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.ADDRESS_MUST_BE_PRESENT): - execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, - [session_user.solana_account_address, - session_user.balance_account_address], 0) - - def test_recipient_missed_in_remaining_accounts(self, operator_keypair, treasury_pool, session_user, - sender_with_tokens, evm_loader, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.ADDRESS_MUST_BE_PRESENT): - execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, - [sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address], 0) - - def test_incorrect_treasure_pool(self, operator_keypair, sender_with_tokens, evm_loader, session_user, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - index = 2 - treasury = TreasuryPool(index, Keypair().generate().public_key, index.to_bytes(4, 'little')) - - error = str.format(InstructionAsserts.INVALID_ACCOUNT, treasury.account) - with pytest.raises(solana.rpc.core.RPCException, match=error): - execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury, holder_acc, [], 0) - - def test_incorrect_treasure_index(self, operator_keypair, sender_with_tokens, evm_loader, - session_user, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - - index = 2 - treasury = TreasuryPool(index, create_treasury_pool_address(index), (index + 1).to_bytes(4, 'little')) - - error = str.format(InstructionAsserts.INVALID_ACCOUNT, treasury.account) - with pytest.raises(solana.rpc.core.RPCException, match=error): - execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury, holder_acc, [], 0) - - def test_incorrect_operator_account(self, operator_keypair, sender_with_tokens, evm_loader, treasury_pool, - session_user, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - - fake_operator = Keypair() - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.ACC_NOT_FOUND): - execute_transaction_steps_from_account(fake_operator, evm_loader, treasury_pool, holder_acc, - [sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address, - session_user.solana_account_address, - session_user.balance_account_address], 0) - - def test_operator_is_not_in_white_list(self, sender_with_tokens, operator_keypair, evm_loader, treasury_pool, - session_user, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.NOT_AUTHORIZED_OPERATOR): - execute_transaction_steps_from_account(sender_with_tokens.solana_account, evm_loader, treasury_pool, - holder_acc, - [sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address, - session_user.solana_account_address, - session_user.balance_account_address], 0, - signer=sender_with_tokens.solana_account) - - def test_incorrect_system_program(self, sender_with_tokens, operator_keypair, evm_loader, treasury_pool, - session_user, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) - fake_sys_program_id = Keypair().public_key - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - - error = str.format(InstructionAsserts.NOT_SYSTEM_PROGRAM, fake_sys_program_id) - with pytest.raises(solana.rpc.core.RPCException, match=error): - send_transaction_step_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, - [], 1, operator_keypair, system_program=fake_sys_program_id) - - - def test_incorrect_holder_account(self, operator_keypair, evm_loader, treasury_pool): - fake_holder_acc = Keypair.generate().public_key - - error = str.format(InstructionAsserts.NOT_PROGRAM_OWNED, fake_holder_acc) - with pytest.raises(solana.rpc.core.RPCException, match=error): - send_transaction_step_from_account(operator_keypair, evm_loader, treasury_pool, fake_holder_acc, [], 1, operator_keypair) - - def test_transaction_with_access_list(self, operator_keypair, holder_acc, treasury_pool, - sender_with_tokens, evm_loader, calculator_contract, - calculator_caller_contract): - access_list = ( - { - "address": '0x' + calculator_contract.eth_address.hex(), - "storageKeys": ( - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000001", - ) - }, - ) - signed_tx = make_contract_call_trx(sender_with_tokens, calculator_caller_contract, "callCalculator()", [], - access_list=access_list) - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - - resp = execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, - [calculator_caller_contract.solana_address, - calculator_contract.solana_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address]) - - check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) - check_transaction_logs_have_text(resp.value.transaction.transaction.signatures[0], "exit_status=0x12") - - @pytest.mark.parametrize("access_list", generate_access_lists()) - def test_access_list_structure(self, operator_keypair, holder_acc, treasury_pool, evm_loader, - sender_with_tokens, string_setter_contract, access_list): - text = ''.join(random.choice(string.ascii_letters) for _ in range(10)) - - signed_tx = make_contract_call_trx(sender_with_tokens, string_setter_contract, "set(string)", [text], - value=10, access_list=access_list) - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - resp = execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, - [string_setter_contract.solana_address, - string_setter_contract.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address]) - - check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) - check_transaction_logs_have_text(resp.value.transaction.transaction.signatures[0], "exit_status=0x11") - - assert text in to_text( - neon_cli().call_contract_get_function(evm_loader, sender_with_tokens, string_setter_contract, - "get()")) - - -class TestAccountStepContractCallContractInteractions: - def test_contract_call_unchange_storage_function(self, rw_lock_contract, rw_lock_caller, session_user, evm_loader, - operator_keypair, treasury_pool, holder_acc): - signed_tx = make_contract_call_trx(session_user, rw_lock_caller, 'unchange_storage(uint8,uint8)', [1, 1]) - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - resp = execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, - [rw_lock_caller.solana_address, - rw_lock_contract.solana_address, - session_user.solana_account_address, - session_user.balance_account_address]) - - check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) - check_transaction_logs_have_text(resp.value.transaction.transaction.signatures[0], "exit_status=0x12") - - def test_contract_call_set_function(self, rw_lock_contract, session_user, evm_loader, operator_keypair, - treasury_pool, holder_acc, rw_lock_caller): - signed_tx = make_contract_call_trx(session_user, rw_lock_caller, 'update_storage_str(string)', ['hello']) - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - resp = execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, - [rw_lock_caller.solana_address, - rw_lock_contract.solana_address, - session_user.solana_account_address, - session_user.balance_account_address], 1000) - - check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) - check_transaction_logs_have_text(resp.value.transaction.transaction.signatures[0], "exit_status=0x11") - - assert 'hello' in to_text(neon_cli().call_contract_get_function(evm_loader, session_user, rw_lock_contract, - "get_text()")) - - def test_contract_call_get_function(self, rw_lock_contract, session_user, evm_loader, operator_keypair, - treasury_pool, holder_acc, rw_lock_caller): - signed_tx = make_contract_call_trx(session_user, rw_lock_caller, 'get_text()') - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - - resp = execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, - [rw_lock_caller.solana_address, - rw_lock_contract.solana_address, - session_user.solana_account_address, - session_user.balance_account_address], 1000) - - check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) - check_transaction_logs_have_text(resp.value.transaction.transaction.signatures[0], "exit_status=0x12") - - def test_contract_call_update_storage_map_function(self, rw_lock_contract, session_user, evm_loader, - operator_keypair, rw_lock_caller, - treasury_pool, holder_acc): - signed_tx = make_contract_call_trx(session_user, rw_lock_caller, 'update_storage_map(uint256)', [3]) - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - - func_name = abi.function_signature_to_4byte_selector('update_storage_map(uint256)') - data = func_name + eth_abi.encode(['uint256'], [3]) - result = neon_cli().emulate(evm_loader.loader_id, - session_user.eth_address.hex(), - rw_lock_caller.eth_address.hex(), - data.hex()) - additional_accounts = [session_user.solana_account_address, - session_user.balance_account_address, - rw_lock_contract.solana_address, - rw_lock_caller.solana_address] - for acc in result['solana_accounts']: - additional_accounts.append(PublicKey(acc['pubkey'])) - - resp = execute_transaction_steps_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc, - additional_accounts) - - check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) - check_transaction_logs_have_text(resp.value.transaction.transaction.signatures[0], "exit_status=0x11") - - constructor_args = eth_abi.encode(['address', 'uint256'], [rw_lock_caller.eth_address.hex(), 2]) - actual_data = neon_cli().call_contract_get_function(evm_loader, session_user, rw_lock_contract, - "data(address,uint256)", constructor_args) - assert to_int(hexstr=actual_data) == 2, "Contract data is not correct" - - -class TestTransactionStepFromAccountParallelRuns: - - def test_one_user_call_2_contracts(self, rw_lock_contract, string_setter_contract, user_account, evm_loader, - operator_keypair, treasury_pool, new_holder_acc): - signed_tx = make_contract_call_trx(user_account, rw_lock_contract, 'unchange_storage(uint8,uint8)', [1, 1]) - write_transaction_to_holder_account(signed_tx, new_holder_acc, operator_keypair) - - send_transaction_step_from_account(operator_keypair, evm_loader, treasury_pool, new_holder_acc, - [user_account.balance_account_address, - user_account.solana_account_address, - rw_lock_contract.solana_address], 1, operator_keypair) - - signed_tx2 = make_contract_call_trx(user_account, string_setter_contract, 'get()') - - holder_acc2 = create_holder(operator_keypair) - write_transaction_to_holder_account(signed_tx2, holder_acc2, operator_keypair) - - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.LOCKED_ACC): - send_transaction_step_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc2, - [user_account.balance_account_address, - user_account.solana_account_address, - string_setter_contract.solana_address], 1, operator_keypair) - - def test_2_users_call_the_same_contract(self, rw_lock_contract, user_account, - session_user, evm_loader, operator_keypair, - treasury_pool, new_holder_acc): - signed_tx = make_contract_call_trx(user_account, rw_lock_contract, 'unchange_storage(uint8,uint8)', [1, 1]) - write_transaction_to_holder_account(signed_tx, new_holder_acc, operator_keypair) - - send_transaction_step_from_account(operator_keypair, evm_loader, treasury_pool, new_holder_acc, - [user_account.solana_account_address, - user_account.balance_account_address, - rw_lock_contract.solana_address], 1, operator_keypair) - - signed_tx2 = make_contract_call_trx(session_user, rw_lock_contract, 'get_text()') - - holder_acc2 = create_holder(operator_keypair) - write_transaction_to_holder_account(signed_tx2, holder_acc2, operator_keypair) - - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.LOCKED_ACC): - send_transaction_step_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc2, - [session_user.solana_account_address, - session_user.balance_account_address, - rw_lock_contract.solana_address], 1, operator_keypair) - - def test_two_contracts_call_same_contract(self, rw_lock_contract, user_account, - session_user, evm_loader, operator_keypair, - treasury_pool, new_holder_acc): - constructor_args = eth_abi.encode(['address'], [rw_lock_contract.eth_address.hex()]) - - contract1 = deploy_contract(operator_keypair, session_user, "rw_lock_caller.binary", evm_loader, treasury_pool, - encoded_args=constructor_args) - contract2 = deploy_contract(operator_keypair, session_user, "rw_lock_caller.binary", evm_loader, treasury_pool, - encoded_args=constructor_args) - - signed_tx1 = make_contract_call_trx(user_account, contract1, 'unchange_storage(uint8,uint8)', [1, 1]) - signed_tx2 = make_contract_call_trx(session_user, contract2, 'get_text()') - write_transaction_to_holder_account(signed_tx1, new_holder_acc, operator_keypair) - - send_transaction_step_from_account(operator_keypair, evm_loader, treasury_pool, new_holder_acc, - [user_account.solana_account_address, - user_account.balance_account_address, - rw_lock_contract.solana_address, - contract1.solana_address], 1, operator_keypair) - - holder_acc2 = create_holder(operator_keypair) - write_transaction_to_holder_account(signed_tx2, holder_acc2, operator_keypair) - - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.LOCKED_ACC): - send_transaction_step_from_account(operator_keypair, evm_loader, treasury_pool, holder_acc2, - [session_user.solana_account_address, - session_user.balance_account_address, - rw_lock_contract.solana_address, - contract2.solana_address], 1, - operator_keypair) - - -class TestStepFromAccountChangingOperatorsDuringTrxRun: - def test_next_operator_can_continue_trx_after_some_time(self, rw_lock_contract, user_account, evm_loader, - operator_keypair, second_operator_keypair, treasury_pool, - new_holder_acc): - signed_tx = make_contract_call_trx(user_account, rw_lock_contract, 'update_storage_str(string)', ['text']) - write_transaction_to_holder_account(signed_tx, new_holder_acc, operator_keypair) - - trx = TransactionWithComputeBudget(operator_keypair) - trx.add( - make_ExecuteTrxFromAccountDataIterativeOrContinue( - 0, 1, - operator_keypair, evm_loader, new_holder_acc, treasury_pool, - [user_account.solana_account_address, - user_account.balance_account_address, - rw_lock_contract.solana_address] - ) - ) - solana_client.send_transaction(trx, operator_keypair, - opts=TxOpts(skip_confirmation=True, preflight_commitment=Confirmed)) - - # next operator can't continue trx during OPERATOR_PRIORITY_SLOTS*0.4 - error = rf"{InstructionAsserts.INVALID_OPERATOR_KEY}|{InstructionAsserts.INVALID_HOLDER_OWNER}" - with pytest.raises(solana.rpc.core.RPCException, match=error): - send_transaction_step_from_account( - second_operator_keypair, evm_loader, treasury_pool, new_holder_acc, - [user_account.solana_account_address, - user_account.balance_account_address, - rw_lock_contract.solana_address], - 500, second_operator_keypair - ) - - time.sleep(15) - send_transaction_step_from_account(second_operator_keypair, evm_loader, treasury_pool, new_holder_acc, - [user_account.solana_account_address, - user_account.balance_account_address, - rw_lock_contract.solana_address], 500, second_operator_keypair) - resp = send_transaction_step_from_account(second_operator_keypair, evm_loader, treasury_pool, new_holder_acc, - [user_account.solana_account_address, - user_account.balance_account_address, - rw_lock_contract.solana_address], 1, second_operator_keypair) - check_transaction_logs_have_text(resp.value.transaction.transaction.signatures[0], "exit_status=0x11") diff --git a/tests/test_transaction_step_from_account_no_chainid.py b/tests/test_transaction_step_from_account_no_chainid.py deleted file mode 100644 index 160d666be..000000000 --- a/tests/test_transaction_step_from_account_no_chainid.py +++ /dev/null @@ -1,123 +0,0 @@ -import random -import re -import string -import solana - -import pytest -from eth_utils import to_text - -from .solana_utils import write_transaction_to_holder_account, solana_client, \ - execute_transaction_steps_from_account_no_chain_id, neon_cli -from .utils.assert_messages import InstructionAsserts -from .utils.constants import TAG_FINALIZED_STATE -from .utils.contract import make_deployment_transaction, make_contract_call_trx -from .utils.ethereum import make_eth_transaction, create_contract_address -from .utils.layouts import FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT -from .utils.transaction_checks import check_holder_account_tag, check_transaction_logs_have_text - - -class TestTransactionStepFromAccountNoChainId: - - def test_simple_transfer_transaction(self, operator_keypair, treasury_pool, evm_loader, - sender_with_tokens, session_user, holder_acc): - amount = 10 - sender_balance_before = evm_loader.get_neon_balance(sender_with_tokens) - recipient_balance_before = evm_loader.get_neon_balance(session_user) - - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, amount, chain_id=None) - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - resp = execute_transaction_steps_from_account_no_chain_id(operator_keypair, evm_loader, treasury_pool, - holder_acc, - [session_user.solana_account_address, - session_user.balance_account_address, - sender_with_tokens.balance_account_address, - sender_with_tokens.solana_account_address], 0) - - sender_balance_after = evm_loader.get_neon_balance(sender_with_tokens) - recipient_balance_after = evm_loader.get_neon_balance(session_user) - - check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) - check_transaction_logs_have_text(resp.value.transaction.transaction.signatures[0], "exit_status=0x11") - assert sender_balance_before - amount == sender_balance_after - assert recipient_balance_before + amount == recipient_balance_after - - def test_deploy_contract(self, operator_keypair, holder_acc, treasury_pool, evm_loader, sender_with_tokens): - contract_filename = "hello_world.binary" - contract = create_contract_address(sender_with_tokens, evm_loader) - - signed_tx = make_deployment_transaction(sender_with_tokens, contract_filename, chain_id=None) - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - - contract_path = pytest.CONTRACTS_PATH / contract_filename - with open(contract_path, 'rb') as f: - contract_code = f.read() - - steps_count = neon_cli().get_steps_count(evm_loader, sender_with_tokens, None, contract_code.hex()) - resp = execute_transaction_steps_from_account_no_chain_id(operator_keypair, evm_loader, treasury_pool, - holder_acc, - [contract.solana_address, - contract.balance_account_address, - sender_with_tokens.balance_account_address, - sender_with_tokens.solana_account_address], - steps_count) - check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) - check_transaction_logs_have_text(resp.value.transaction.transaction.signatures[0], "exit_status=0x12") - - def test_call_contract_function_with_neon_transfer(self, operator_keypair, treasury_pool, - sender_with_tokens, string_setter_contract, holder_acc, - evm_loader): - transfer_amount = random.randint(1, 1000) - - sender_balance_before = evm_loader.get_neon_balance(sender_with_tokens) - contract_balance_before = evm_loader.get_neon_balance(string_setter_contract.eth_address) - - text = ''.join(random.choice(string.ascii_letters) for _ in range(10)) - - signed_tx = make_contract_call_trx(sender_with_tokens, string_setter_contract, "set(string)", [text], - value=transfer_amount, chain_id=None) - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - - resp = execute_transaction_steps_from_account_no_chain_id(operator_keypair, evm_loader, treasury_pool, - holder_acc, - [string_setter_contract.solana_address, - string_setter_contract.balance_account_address, - sender_with_tokens.balance_account_address, - sender_with_tokens.solana_account_address] - ) - - check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) - check_transaction_logs_have_text(resp.value.transaction.transaction.signatures[0], "exit_status=0x11") - - sender_balance_after = evm_loader.get_neon_balance(sender_with_tokens) - contract_balance_after = evm_loader.get_neon_balance(string_setter_contract.eth_address) - assert sender_balance_before - transfer_amount == sender_balance_after - assert contract_balance_before + transfer_amount == contract_balance_after - - assert text in to_text( - neon_cli().call_contract_get_function(evm_loader, sender_with_tokens, string_setter_contract, "get()") - ) - - def test_transaction_with_access_list(self, operator_keypair, treasury_pool, - sender_with_tokens, calculator_contract, calculator_caller_contract, - holder_acc, evm_loader): - access_list = ( - { - "address": '0x' + calculator_contract.eth_address.hex(), - "storageKeys": ( - "0x0000000000000000000000000000000000000000000000000000000000000000", - ) - }, - ) - signed_tx = make_contract_call_trx(sender_with_tokens, calculator_caller_contract, "callCalculator()", [], - chain_id=None, access_list=access_list) - write_transaction_to_holder_account(signed_tx, holder_acc, operator_keypair) - - error = re.escape("assertion failed: trx.chain_id().is_none()") - with pytest.raises(solana.rpc.core.RPCException, match=error): - execute_transaction_steps_from_account_no_chain_id(operator_keypair, evm_loader, treasury_pool, - holder_acc, - [calculator_contract.solana_address, - calculator_caller_contract.solana_address, - sender_with_tokens.balance_account_address, - sender_with_tokens.solana_account_address] - ) diff --git a/tests/test_transaction_step_from_instruction.py b/tests/test_transaction_step_from_instruction.py deleted file mode 100644 index e9a567c28..000000000 --- a/tests/test_transaction_step_from_instruction.py +++ /dev/null @@ -1,611 +0,0 @@ -import random -import string -import time - -import eth_abi -import pytest -import rlp -import solana -from eth_account.datastructures import SignedTransaction -from eth_keys import keys as eth_keys -from eth_utils import abi, to_text, to_int -from hexbytes import HexBytes -from solana.keypair import Keypair -from solana.publickey import PublicKey -from solana.rpc.commitment import Confirmed -from solana.rpc.core import RPCException - -from .solana_utils import solana_client, execute_transaction_steps_from_instruction, neon_cli, \ - create_treasury_pool_address, send_transaction_step_from_instruction -from .utils.assert_messages import InstructionAsserts -from .utils.constants import TAG_FINALIZED_STATE -from .utils.contract import make_deployment_transaction, make_contract_call_trx, deploy_contract -from .utils.ethereum import make_eth_transaction, create_contract_address -from .utils.layouts import FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT -from .utils.storage import create_holder -from .utils.transaction_checks import check_transaction_logs_have_text, check_holder_account_tag -from .utils.types import TreasuryPool - - -class TestTransactionStepFromInstruction: - - def test_simple_transfer_transaction(self, operator_keypair, treasury_pool, evm_loader, - sender_with_tokens, session_user, holder_acc): - amount = 10 - sender_balance_before = evm_loader.get_neon_balance(sender_with_tokens) - recipient_balance_before = evm_loader.get_neon_balance(session_user) - - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, amount) - - resp = execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, - signed_tx, [session_user.solana_account_address, - session_user.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address], 0) - - sender_balance_after = evm_loader.get_neon_balance(sender_with_tokens) - recipient_balance_after = evm_loader.get_neon_balance(session_user) - - check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) - check_transaction_logs_have_text(resp.value, "exit_status=0x11") - assert sender_balance_before - amount == sender_balance_after - assert recipient_balance_before + amount == recipient_balance_after - - @pytest.mark.parametrize("chain_id", [None, 111]) - def test_deploy_contract(self, operator_keypair, holder_acc, treasury_pool, evm_loader, sender_with_tokens, - chain_id): - contract_filename = "small.binary" - - signed_tx = make_deployment_transaction(sender_with_tokens, contract_filename, chain_id=chain_id) - contract = create_contract_address(sender_with_tokens, evm_loader) - - contract_path = pytest.CONTRACTS_PATH / contract_filename - with open(contract_path, 'rb') as f: - contract_code = f.read() - - steps_count = neon_cli().get_steps_count(evm_loader, sender_with_tokens, None, contract_code.hex()) - resp = execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, - signed_tx, [contract.solana_address, - contract.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address], - steps_count) - - check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) - check_transaction_logs_have_text(resp.value, "exit_status=0x12") - - def test_call_contract_function_without_neon_transfer(self, operator_keypair, treasury_pool, sender_with_tokens, - evm_loader, holder_acc, string_setter_contract): - text = ''.join(random.choice(string.ascii_letters) for _ in range(10)) - signed_tx = make_contract_call_trx(sender_with_tokens, string_setter_contract, "set(string)", [text]) - - resp = execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, - signed_tx, [string_setter_contract.solana_address, - string_setter_contract.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address] - ) - - check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) - check_transaction_logs_have_text(resp.value, "exit_status=0x11") - - assert text in to_text( - neon_cli().call_contract_get_function(evm_loader, sender_with_tokens, string_setter_contract, - "get()")) - - def test_call_contract_function_with_neon_transfer(self, operator_keypair, treasury_pool, sender_with_tokens, - evm_loader, holder_acc, string_setter_contract): - transfer_amount = random.randint(1, 1000) - - sender_balance_before = evm_loader.get_neon_balance(sender_with_tokens) - contract_balance_before = evm_loader.get_neon_balance(string_setter_contract.eth_address) - - text = ''.join(random.choice(string.ascii_letters) for i in range(10)) - signed_tx = make_contract_call_trx(sender_with_tokens, string_setter_contract, "set(string)", [text], - value=transfer_amount) - - resp = execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, - signed_tx, [string_setter_contract.solana_address, - string_setter_contract.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address] - ) - - check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) - check_transaction_logs_have_text(resp.value, "exit_status=0x11") - - sender_balance_after = evm_loader.get_neon_balance(sender_with_tokens) - contract_balance_after = evm_loader.get_neon_balance(string_setter_contract.eth_address) - assert sender_balance_before - transfer_amount == sender_balance_after - assert contract_balance_before + transfer_amount == contract_balance_after - - assert text in to_text( - neon_cli().call_contract_get_function(evm_loader, sender_with_tokens, string_setter_contract, - "get()")) - - def test_transfer_transaction_with_non_existing_recipient(self, operator_keypair, treasury_pool, sender_with_tokens, - evm_loader, holder_acc): - # recipient account should be created - recipient = Keypair.generate() - recipient_ether = eth_keys.PrivateKey(recipient.secret_key[:32]).public_key.to_canonical_address() - recipient_solana_address, _ = evm_loader.ether2program(recipient_ether) - recipient_balance_address = evm_loader.ether2balance(recipient_ether) - amount = 10 - signed_tx = make_eth_transaction(recipient_ether, None, sender_with_tokens, amount) - - resp = execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, - signed_tx, [PublicKey(recipient_solana_address), - recipient_balance_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address], 0) - - recipient_balance_after = evm_loader.get_neon_balance(recipient_ether) - check_transaction_logs_have_text(resp.value, "exit_status=0x11") - - assert recipient_balance_after == amount - - def test_incorrect_chain_id(self, operator_keypair, holder_acc, treasury_pool, - sender_with_tokens, session_user, evm_loader): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1, chain_id=1) - - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.INVALID_CHAIN_ID): - execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, - signed_tx, - [session_user.solana_account_address, - session_user.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address], 0) - - def test_incorrect_nonce(self, operator_keypair, treasury_pool, sender_with_tokens, evm_loader, session_user, - holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) - execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, - signed_tx, - [session_user.solana_account_address, - session_user.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address], 0) - new_holder_acc = create_holder(operator_keypair) - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.INVALID_NONCE): - execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, new_holder_acc, - signed_tx, - [session_user.solana_account_address, - session_user.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address], 0) - - def test_run_finalized_transaction(self, operator_keypair, treasury_pool, sender_with_tokens, evm_loader, - session_user, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) - execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, - signed_tx, - [session_user.solana_account_address, - session_user.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address], 0) - - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.TRX_ALREADY_FINALIZED): - execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, - signed_tx, - [session_user.solana_account_address, - session_user.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address], 0) - - def test_insufficient_funds(self, operator_keypair, treasury_pool, evm_loader, session_user, - holder_acc, sender_with_tokens): - user_balance = evm_loader.get_neon_balance(session_user) - - signed_tx = make_eth_transaction(sender_with_tokens.eth_address, None, session_user, user_balance + 1) - - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.INSUFFICIENT_FUNDS): - execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, - signed_tx, - [session_user.solana_account_address, - session_user.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address], 0) - - def test_gas_limit_reached(self, operator_keypair, treasury_pool, session_user, evm_loader, sender_with_tokens, - holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 10, gas=1) - - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.OUT_OF_GAS): - execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, - signed_tx, - [session_user.solana_account_address, - session_user.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address], 0) - - def test_sender_missed_in_remaining_accounts(self, operator_keypair, treasury_pool, session_user, - sender_with_tokens, evm_loader, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) - - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.ADDRESS_MUST_BE_PRESENT): - execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, - signed_tx, - [session_user.solana_account_address, - session_user.balance_account_address], 0) - - def test_recipient_missed_in_remaining_accounts(self, operator_keypair, treasury_pool, session_user, - sender_with_tokens, evm_loader, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) - - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.ADDRESS_MUST_BE_PRESENT): - execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, - signed_tx, - [session_user.solana_account_address, - session_user.balance_account_address], 0) - - def test_incorrect_treasure_pool(self, operator_keypair, sender_with_tokens, evm_loader, session_user, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) - index = 2 - treasury = TreasuryPool(index, Keypair().generate().public_key, index.to_bytes(4, 'little')) - - error = str.format(InstructionAsserts.INVALID_ACCOUNT, treasury.account) - with pytest.raises(solana.rpc.core.RPCException, match=error): - execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury, holder_acc, - signed_tx, - [session_user.solana_account_address, - session_user.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address], 0) - - def test_incorrect_treasure_index(self, operator_keypair, sender_with_tokens, evm_loader, - session_user, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) - index = 2 - treasury = TreasuryPool(index, create_treasury_pool_address(index), (index + 1).to_bytes(4, 'little')) - - error = str.format(InstructionAsserts.INVALID_ACCOUNT, treasury.account) - with pytest.raises(solana.rpc.core.RPCException, match=error): - execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury, holder_acc, - signed_tx, - [session_user.solana_account_address, - session_user.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address], 0) - - def test_incorrect_operator_account(self, sender_with_tokens, evm_loader, treasury_pool, session_user, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) - fake_operator = Keypair().generate() - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.ACC_NOT_FOUND): - execute_transaction_steps_from_instruction(fake_operator, evm_loader, treasury_pool, holder_acc, - signed_tx, - [session_user.solana_account_address, - session_user.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address], 0) - - def test_operator_is_not_in_white_list(self, sender_with_tokens, evm_loader, treasury_pool, - session_user, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.NOT_AUTHORIZED_OPERATOR): - execute_transaction_steps_from_instruction(sender_with_tokens.solana_account, evm_loader, treasury_pool, - holder_acc, - signed_tx, - [session_user.solana_account_address, - session_user.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address], 0, - signer=sender_with_tokens.solana_account) - - def test_incorrect_system_program(self, sender_with_tokens, operator_keypair, evm_loader, treasury_pool, - session_user, holder_acc): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) - fake_sys_program_id = Keypair().generate().public_key - - with pytest.raises(solana.rpc.core.RPCException, - match=str.format(InstructionAsserts.NOT_SYSTEM_PROGRAM, fake_sys_program_id)): - send_transaction_step_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, - signed_tx, - [sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address, - session_user.solana_account_address, - session_user.balance_account_address], 1, operator_keypair, - system_program=fake_sys_program_id) - - def test_incorrect_holder_account(self, sender_with_tokens, operator_keypair, evm_loader, treasury_pool, - session_user): - signed_tx = make_eth_transaction(session_user.eth_address, None, sender_with_tokens, 1) - fake_holder_acc = Keypair.generate().public_key - with pytest.raises(solana.rpc.core.RPCException, - match=str.format(InstructionAsserts.NOT_PROGRAM_OWNED, fake_holder_acc)): - send_transaction_step_from_instruction(operator_keypair, evm_loader, treasury_pool, fake_holder_acc, - signed_tx, - [sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address, - session_user.solana_account_address, - session_user.balance_account_address], 1, operator_keypair) - - @pytest.mark.parametrize("value", [0, 10]) - def test_transaction_with_access_list(self, operator_keypair, treasury_pool, sender_with_tokens, - evm_loader, holder_acc, - string_setter_contract, value): - access_list = ( - { - "address": '0x' + string_setter_contract.eth_address.hex(), - "storageKeys": ( - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000001", - ) - }, - ) - signed_tx = make_contract_call_trx(sender_with_tokens, string_setter_contract, "set(string)", ["text"], - value=value, access_list=access_list) - resp = execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, - signed_tx, [string_setter_contract.solana_address, - string_setter_contract.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address] - ) - - check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) - check_transaction_logs_have_text(resp.value, "exit_status=0x11") - - def test_deploy_contract_with_access_list(self, operator_keypair, holder_acc, treasury_pool, evm_loader, - sender_with_tokens): - contract_filename = "small.binary" - contract = create_contract_address(sender_with_tokens, evm_loader) - - access_list = ( - { - "address": contract.eth_address.hex(), - "storageKeys": ( - "0x0000000000000000000000000000000000000000000000000000000000000000", - ) - }, - ) - signed_tx = make_deployment_transaction(sender_with_tokens, contract_filename, access_list=access_list) - contract_path = pytest.CONTRACTS_PATH / contract_filename - with open(contract_path, 'rb') as f: - contract_code = f.read() - - steps_count = neon_cli().get_steps_count(evm_loader, sender_with_tokens, None, contract_code.hex()) - resp = execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, - signed_tx, [contract.solana_address, - contract.balance_account_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address], - steps_count) - check_transaction_logs_have_text(resp.value, "exit_status=0x12") - - -class TestInstructionStepContractCallContractInteractions: - def test_contract_call_unchange_storage_function(self, rw_lock_contract, session_user, evm_loader, operator_keypair, - treasury_pool, holder_acc, rw_lock_caller): - signed_tx = make_contract_call_trx(session_user, rw_lock_caller, 'unchange_storage(uint8,uint8)', [1, 1]) - resp = execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, - signed_tx, - [rw_lock_caller.solana_address, - rw_lock_contract.solana_address, - session_user.solana_account_address, - session_user.balance_account_address]) - - check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) - check_transaction_logs_have_text(resp.value, "exit_status=0x12") - - def test_contract_call_set_function(self, rw_lock_contract, session_user, evm_loader, operator_keypair, - treasury_pool, holder_acc, rw_lock_caller): - signed_tx = make_contract_call_trx(session_user, rw_lock_caller, 'update_storage_str(string)', ['hello']) - - resp = execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, - signed_tx, - [rw_lock_caller.solana_address, - rw_lock_contract.solana_address, - session_user.solana_account_address, - session_user.balance_account_address], 1000) - - check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) - check_transaction_logs_have_text(resp.value, "exit_status=0x11") - - assert 'hello' in to_text(neon_cli().call_contract_get_function(evm_loader, session_user, rw_lock_contract, - "get_text()")) - - def test_contract_call_get_function(self, rw_lock_contract, session_user, evm_loader, operator_keypair, - treasury_pool, holder_acc, rw_lock_caller): - signed_tx = make_contract_call_trx(session_user, rw_lock_caller, 'get_text()') - resp = execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, - signed_tx, - [rw_lock_caller.solana_address, - rw_lock_contract.solana_address, - session_user.solana_account_address, - session_user.balance_account_address], 1000) - - check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) - check_transaction_logs_have_text(resp.value, "exit_status=0x12") - - def test_contract_call_update_storage_map_function(self, rw_lock_contract, session_user, evm_loader, - operator_keypair, rw_lock_caller, - treasury_pool, holder_acc): - signed_tx = make_contract_call_trx(session_user, rw_lock_caller, 'update_storage_map(uint256)', [3]) - - func_name = abi.function_signature_to_4byte_selector('update_storage_map(uint256)') - data = func_name + eth_abi.encode(['uint256'], [3]) - result = neon_cli().emulate(evm_loader.loader_id, - session_user.eth_address.hex(), - rw_lock_caller.eth_address.hex(), - data.hex()) - additional_accounts = [session_user.solana_account_address, - session_user.balance_account_address, - rw_lock_contract.solana_address, - rw_lock_caller.solana_address] - for acc in result['solana_accounts']: - additional_accounts.append(PublicKey(acc['pubkey'])) - - resp = execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, - signed_tx, additional_accounts) - - check_holder_account_tag(holder_acc, FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT, TAG_FINALIZED_STATE) - check_transaction_logs_have_text(resp.value, "exit_status=0x11") - - constructor_args = eth_abi.encode(['address', 'uint256'], [rw_lock_caller.eth_address.hex(), 2]) - actual_data = neon_cli().call_contract_get_function(evm_loader, session_user, rw_lock_contract, - "data(address,uint256)", constructor_args) - assert to_int(hexstr=actual_data) == 2, "Contract data is not correct" - - -class TestTransactionStepFromInstructionParallelRuns: - - def test_one_user_call_2_contracts(self, rw_lock_contract, string_setter_contract, user_account, evm_loader, - operator_keypair, treasury_pool, new_holder_acc): - signed_tx = make_contract_call_trx(user_account, rw_lock_contract, 'unchange_storage(uint8,uint8)', [1, 1]) - send_transaction_step_from_instruction(operator_keypair, evm_loader, treasury_pool, new_holder_acc, signed_tx, - [user_account.solana_account_address, - user_account.balance_account_address, - rw_lock_contract.solana_address], 1, operator_keypair) - - signed_tx2 = make_contract_call_trx(user_account, string_setter_contract, 'get()') - holder_acc2 = create_holder(operator_keypair) - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.LOCKED_ACC): - send_transaction_step_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc2, signed_tx2, - [user_account.solana_account_address, - user_account.balance_account_address, - string_setter_contract.solana_address], 1, operator_keypair) - - def test_2_users_call_the_same_contract(self, rw_lock_contract, user_account, - session_user, evm_loader, operator_keypair, - treasury_pool, new_holder_acc): - signed_tx = make_contract_call_trx(user_account, rw_lock_contract, 'unchange_storage(uint8,uint8)', [1, 1]) - - send_transaction_step_from_instruction(operator_keypair, evm_loader, treasury_pool, new_holder_acc, signed_tx, - [user_account.solana_account_address, - user_account.balance_account_address, - rw_lock_contract.solana_address], 1, operator_keypair) - - signed_tx2 = make_contract_call_trx(session_user, rw_lock_contract, 'get_text()') - holder_acc2 = create_holder(operator_keypair) - - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.LOCKED_ACC): - send_transaction_step_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc2, signed_tx2, - [session_user.solana_account_address, - session_user.balance_account_address, - rw_lock_contract.solana_address], 1, operator_keypair) - - def test_two_contracts_call_same_contract(self, rw_lock_contract, user_account, - session_user, evm_loader, operator_keypair, - treasury_pool, new_holder_acc): - constructor_args = eth_abi.encode(['address'], [rw_lock_contract.eth_address.hex()]) - - contract1 = deploy_contract(operator_keypair, session_user, "rw_lock_caller.binary", evm_loader, treasury_pool, - encoded_args=constructor_args) - contract2 = deploy_contract(operator_keypair, session_user, "rw_lock_caller.binary", evm_loader, treasury_pool, - encoded_args=constructor_args) - - signed_tx1 = make_contract_call_trx(user_account, contract1, 'unchange_storage(uint8,uint8)', [1, 1]) - signed_tx2 = make_contract_call_trx(session_user, contract2, 'get_text()') - - send_transaction_step_from_instruction(operator_keypair, evm_loader, treasury_pool, new_holder_acc, signed_tx1, - [user_account.solana_account_address, - user_account.balance_account_address, - rw_lock_contract.solana_address, - contract1.solana_address], 1, operator_keypair) - - holder_acc2 = create_holder(operator_keypair) - with pytest.raises(solana.rpc.core.RPCException, match=InstructionAsserts.LOCKED_ACC): - send_transaction_step_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc2, signed_tx2, - [session_user.solana_account_address, - session_user.balance_account_address, - rw_lock_contract.solana_address, - contract2.solana_address], 1, - operator_keypair) - - -class TestStepFromInstructionChangingOperatorsDuringTrxRun: - def test_next_operator_can_continue_trx_after_some_time(self, rw_lock_contract, user_account, evm_loader, - operator_keypair, second_operator_keypair, treasury_pool, - new_holder_acc): - signed_tx = make_contract_call_trx(user_account, rw_lock_contract, 'update_storage_str(string)', ['text']) - - send_transaction_step_from_instruction(operator_keypair, evm_loader, treasury_pool, new_holder_acc, - signed_tx, - [user_account.solana_account_address, - user_account.balance_account_address, - rw_lock_contract.solana_address], 1, operator_keypair) - # next operator can't continue trx during OPERATOR_PRIORITY_SLOTS*0.4 - with pytest.raises(solana.rpc.core.RPCException, - match=rf"{InstructionAsserts.INVALID_OPERATOR_KEY}|{InstructionAsserts.INVALID_HOLDER_OWNER}"): - send_transaction_step_from_instruction(second_operator_keypair, evm_loader, treasury_pool, new_holder_acc, - signed_tx, - [user_account.solana_account_address, - user_account.balance_account_address, - rw_lock_contract.solana_address], 500, second_operator_keypair) - - time.sleep(15) - send_transaction_step_from_instruction(second_operator_keypair, evm_loader, treasury_pool, new_holder_acc, - signed_tx, - [user_account.solana_account_address, - user_account.balance_account_address, - rw_lock_contract.solana_address], 500, second_operator_keypair) - resp = send_transaction_step_from_instruction(second_operator_keypair, evm_loader, treasury_pool, - new_holder_acc, signed_tx, - [user_account.solana_account_address, - user_account.balance_account_address, - rw_lock_contract.solana_address], 1, second_operator_keypair) - check_transaction_logs_have_text(resp.value, "exit_status=0x11") - - -class TestStepFromInstructionWithChangedRLPTrx: - def test_add_waste_to_trx(self, sender_with_tokens, operator_keypair, treasury_pool, evm_loader, holder_acc, - string_setter_contract): - text = ''.join(random.choice(string.ascii_letters) for _ in range(10)) - signed_tx = make_contract_call_trx(sender_with_tokens, string_setter_contract, "set(string)", [text]) - decoded_tx = rlp.decode(signed_tx.rawTransaction) - decoded_tx.insert(6, HexBytes(b'\x19p\x16l\xc0')) - new_trx = HexBytes(rlp.encode(decoded_tx)) - - signed_tx_new = SignedTransaction( - rawTransaction=new_trx, - hash=signed_tx.hash, - r=signed_tx.r, - s=signed_tx.s, - v=signed_tx.v, - ) - with pytest.raises(RPCException, match="Program log: RLP error: RlpIncorrectListLen"): - execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, - signed_tx_new, - [sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address, - string_setter_contract.solana_address]) - - def test_add_waste_to_trx_without_decoding(self, sender_with_tokens, operator_keypair, treasury_pool, evm_loader, - holder_acc, - string_setter_contract): - text = ''.join(random.choice(string.ascii_letters) for _ in range(10)) - signed_tx = make_contract_call_trx(sender_with_tokens, string_setter_contract, "set(string)", [text]) - signed_tx_new = SignedTransaction( - rawTransaction=signed_tx.rawTransaction + HexBytes(b'\x19p\x16l\xc0'), - hash=signed_tx.hash, - r=signed_tx.r, - s=signed_tx.s, - v=signed_tx.v, - ) - with pytest.raises(RPCException, match="Program log: RLP error: RlpInconsistentLengthAndData"): - execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, - signed_tx_new, - [sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address, - string_setter_contract.solana_address]) - - def test_old_trx_type_with_leading_zeros(self, sender_with_tokens, operator_keypair, evm_loader, - string_setter_contract, treasury_pool, holder_acc): - text = ''.join(random.choice(string.ascii_letters) for _ in range(10)) - - signed_tx = make_contract_call_trx(sender_with_tokens, string_setter_contract, "set(string)", [text]) - new_raw_trx = HexBytes(bytes([0]) + signed_tx.rawTransaction) - - signed_tx_new = SignedTransaction( - rawTransaction=new_raw_trx, - hash=signed_tx.hash, - r=signed_tx.r, - s=signed_tx.s, - v=signed_tx.v, - ) - - resp = execute_transaction_steps_from_instruction(operator_keypair, evm_loader, treasury_pool, holder_acc, - signed_tx_new, [string_setter_contract.solana_address, - sender_with_tokens.solana_account_address, - sender_with_tokens.balance_account_address] - ) - check_transaction_logs_have_text(resp.value, "exit_status=0x11") diff --git a/tests/utils/__init__.py b/tests/utils/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/utils/assert_messages.py b/tests/utils/assert_messages.py deleted file mode 100644 index 43511cd81..000000000 --- a/tests/utils/assert_messages.py +++ /dev/null @@ -1,18 +0,0 @@ -class InstructionAsserts: - LOCKED_ACC = "trying to execute transaction on rw locked account" - INVALID_CHAIN_ID = "Invalid Chain ID" - INVALID_NONCE = "Invalid Nonce" - TRX_ALREADY_FINALIZED = "Transaction already finalized" - INSUFFICIENT_FUNDS = "Insufficient balance" - OUT_OF_GAS = "Out of Gas" - ADDRESS_MUST_BE_PRESENT = r"address .* must be present in the transaction" - INVALID_ACCOUNT = "Account {} - invalid public key" - ACC_NOT_FOUND = "AccountNotFound" - NOT_AUTHORIZED_OPERATOR = "Operator is not authorized" - NOT_SYSTEM_PROGRAM = "Account {} - is not system program" - NOT_NEON_PROGRAM = "Account {} - is not Neon program" - NOT_PROGRAM_OWNED = "Account {} - invalid owner" - INVALID_HOLDER_OWNER = "Holder Account - invalid owner" - INVALID_OPERATOR_KEY = "operator.key != storage.operator" - HOLDER_OVERFLOW = "Checked Integer Math Overflow" - HOLDER_INSUFFICIENT_SIZE = "Holder Account - insufficient size" diff --git a/tests/utils/constants.py b/tests/utils/constants.py deleted file mode 100644 index cdeff51bc..000000000 --- a/tests/utils/constants.py +++ /dev/null @@ -1,27 +0,0 @@ -import os -from solana.publickey import PublicKey -from construct import Bytes, Int8ul, Struct as cStruct - - -SYSTEM_ADDRESS = "11111111111111111111111111111111" -TOKEN_KEG_ADDRESS = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" -SYSVAR_CLOCK_ADDRESS = "SysvarC1ock11111111111111111111111111111111" -SYS_INSTRUCT_ADDRESS = "Sysvar1nstructions1111111111111111111111111" -KECCAKPROG_ADDRESS = "KeccakSecp256k11111111111111111111111111111" -RENT_ID_ADDRESS = "SysvarRent111111111111111111111111111111111" -INCINERATOR_ADDRESS = "1nc1nerator11111111111111111111111111111111" -TREASURY_POOL_SEED = os.environ.get("NEON_TREASURY_POOL_SEED", "treasury_pool") -TREASURY_POOL_COUNT = os.environ.get("NEON_TREASURY_POOL_COUNT", 128) -COMPUTE_BUDGET_ID: PublicKey = PublicKey("ComputeBudget111111111111111111111111111111") - -ACCOUNT_SEED_VERSION = b'\3' - -TAG_EMPTY = 0 -TAG_STATE = 23 -TAG_FINALIZED_STATE = 32 -TAG_HOLDER = 52 - -SOLANA_URL = os.environ.get("SOLANA_URL", "http://localhost:8899") -EVM_LOADER = os.environ.get("EVM_LOADER") -NEON_TOKEN_MINT_ID: PublicKey = PublicKey(os.environ.get("NEON_TOKEN_MINT")) -CHAIN_ID = int(os.environ.get("NEON_CHAIN_ID")) diff --git a/tests/utils/contract.py b/tests/utils/contract.py deleted file mode 100644 index 631bac0fe..000000000 --- a/tests/utils/contract.py +++ /dev/null @@ -1,105 +0,0 @@ -import typing as tp -import pathlib - -import eth_abi -import pytest -from eth_account.datastructures import SignedTransaction -from eth_utils import abi -from solana.keypair import Keypair - -from .types import Caller, Contract, TreasuryPool -from ..solana_utils import solana_client, \ - EvmLoader, write_transaction_to_holder_account, \ - send_transaction_step_from_account -from .storage import create_holder -from .ethereum import create_contract_address, make_eth_transaction - -from web3.auto import w3 - - -def make_deployment_transaction( - user: Caller, - contract_path: tp.Union[pathlib.Path, str], - encoded_args=None, - gas: int = 999999999, chain_id=111, access_list=None -) -> SignedTransaction: - if isinstance(contract_path, str): - contract_path = pathlib.Path(contract_path) - if not contract_path.name.startswith("/") or not contract_path.name.startswith("."): - contract_path = pytest.CONTRACTS_PATH / contract_path - with open(contract_path, 'rb') as f: - data = f.read() - - if encoded_args is not None: - data += encoded_args - - nonce = EvmLoader(user.solana_account).get_neon_nonce(user.eth_address) - tx = { - 'to': None, - 'value': 0, - 'gas': gas, - 'gasPrice': 0, - 'nonce': nonce, - 'data': data - } - if chain_id: - tx['chainId'] = chain_id - if access_list: - tx['accessList'] = access_list - tx['type'] = 1 - - return w3.eth.account.sign_transaction(tx, user.solana_account.secret_key[:32]) - - -def make_contract_call_trx(user, contract, function_signature, params=None, value=0, chain_id=111, access_list=None, - trx_type=None): - data = abi.function_signature_to_4byte_selector(function_signature) - - if params is not None: - for param in params: - if isinstance(param, int): - data += eth_abi.encode(['uint256'], [param]) - elif isinstance(param, str): - data += eth_abi.encode(['string'], [param]) - - signed_tx = make_eth_transaction(contract.eth_address, data, user, value=value, - chain_id=chain_id, access_list=access_list, type=trx_type) - return signed_tx - - -def deploy_contract( - operator: Keypair, - user: Caller, - contract_path: tp.Union[pathlib.Path, str], - evm_loader: EvmLoader, - treasury_pool: TreasuryPool, - step_count: int = 1000, - encoded_args=None -): - print("Deploying contract") - if isinstance(contract_path, str): - contract_path = pathlib.Path(contract_path) - contract: Contract = create_contract_address(user, evm_loader) - holder_acc = create_holder(operator) - signed_tx = make_deployment_transaction(user, contract_path, encoded_args=encoded_args) - write_transaction_to_holder_account(signed_tx, holder_acc, operator) - - index = 0 - contract_deployed = False - while not contract_deployed: - receipt = send_transaction_step_from_account(operator, evm_loader, treasury_pool, holder_acc, - [contract.solana_address, - contract.balance_account_address, - user.balance_account_address], - step_count, operator, index=index) - index += 1 - - if receipt.value.transaction.meta.err: - raise AssertionError(f"Can't deploy contract: {receipt.value.transaction.meta.err}") - for log in receipt.value.transaction.meta.log_messages: - if "exit_status" in log: - contract_deployed = True - break - if "ExitError" in log: - raise AssertionError(f"EVM Return error in logs: {receipt}") - return contract diff --git a/tests/utils/ethereum.py b/tests/utils/ethereum.py deleted file mode 100644 index 28e5fe1ba..000000000 --- a/tests/utils/ethereum.py +++ /dev/null @@ -1,46 +0,0 @@ -from typing import Union - -from sha3 import keccak_256 -from solana.keypair import Keypair -from solana.publickey import PublicKey -from web3.auto import w3 - -from .constants import CHAIN_ID - -from .types import Caller, Contract -from ..eth_tx_utils import pack -from ..solana_utils import EvmLoader - - -def create_contract_address(user: Caller, evm_loader: EvmLoader) -> Contract: - # Create contract address from (caller_address, nonce) - user_nonce = evm_loader.get_neon_nonce(user.eth_address) - contract_eth_address = keccak_256(pack([user.eth_address, user_nonce or None])).digest()[-20:] - contract_solana_address, _ = evm_loader.ether2program(contract_eth_address) - contract_neon_address = evm_loader.ether2balance(contract_eth_address) - - print(f"Contract addresses: " - f" eth {contract_eth_address.hex()}, " - f" solana {contract_solana_address}") - - return Contract(contract_eth_address, PublicKey(contract_solana_address), contract_neon_address) - - -def make_eth_transaction(to_addr: bytes, data: Union[bytes, None], caller: Caller, - value: int = 0, chain_id=CHAIN_ID, gas=9999999999, access_list=None, type=None): - - nonce = EvmLoader(caller.solana_account).get_neon_nonce(caller.eth_address) - tx = {'to': to_addr, 'value': value, 'gas': gas, 'gasPrice': 0, - 'nonce': nonce} - - if chain_id is not None: - tx['chainId'] = chain_id - - if data is not None: - tx['data'] = data - - if access_list is not None: - tx['accessList'] = access_list - if type is not None: - tx['type'] = type - return w3.eth.account.sign_transaction(tx, caller.solana_account.secret_key[:32]) diff --git a/tests/utils/instructions.py b/tests/utils/instructions.py deleted file mode 100644 index d084804b3..000000000 --- a/tests/utils/instructions.py +++ /dev/null @@ -1,243 +0,0 @@ -import typing as tp - -from eth_keys import keys as eth_keys -from solana.keypair import Keypair -from solana.publickey import PublicKey -import solana.system_program as sp -from solana.transaction import AccountMeta, TransactionInstruction, Transaction - -from tests.utils.types import TreasuryPool -from .constants import EVM_LOADER, INCINERATOR_ADDRESS -from solana.system_program import SYS_PROGRAM_ID -from solana.sysvar import SYSVAR_RENT_PUBKEY -from spl.token.constants import ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_PROGRAM_ID -from spl.token.instructions import get_associated_token_address - -DEFAULT_UNITS = 1_400_000 -DEFAULT_HEAP_FRAME = 256 * 1024 -DEFAULT_ADDITIONAL_FEE = 0 -COMPUTE_BUDGET_ID: PublicKey = PublicKey("ComputeBudget111111111111111111111111111111") - - -class ComputeBudget: - @staticmethod - def request_units(operator, units, additional_fee): - return TransactionInstruction( - program_id=COMPUTE_BUDGET_ID, - keys=[AccountMeta(PublicKey(operator.public_key), is_signer=True, is_writable=False)], - data=bytes.fromhex("02") + units.to_bytes(4, "little") # + additional_fee.to_bytes(4, "little") - ) - - @staticmethod - def request_heap_frame(operator, heap_frame): - return TransactionInstruction( - program_id=COMPUTE_BUDGET_ID, - keys=[AccountMeta(PublicKey(operator.public_key), is_signer=True, is_writable=False)], - data=bytes.fromhex("01") + heap_frame.to_bytes(4, "little") - ) - - -class TransactionWithComputeBudget(Transaction): - def __init__(self, - operator: Keypair, - units=DEFAULT_UNITS, - additional_fee=DEFAULT_ADDITIONAL_FEE, - heap_frame=DEFAULT_HEAP_FRAME, - *args, **kwargs): - super().__init__(*args, **kwargs) - if units: - self.add(ComputeBudget.request_units(operator, units, additional_fee)) - if heap_frame: - self.add(ComputeBudget.request_heap_frame(operator, heap_frame)) - - -def write_holder_layout(hash: bytes, offset: int, data: bytes): - assert (len(hash) == 32) - return ( - bytes([0x26]) - + hash - + offset.to_bytes(8, byteorder="little") - + data - ) - - -def make_WriteHolder(operator: PublicKey, holder_account: PublicKey, hash: bytes, offset: int, payload: bytes): - d = write_holder_layout(hash, offset, payload) - - return TransactionInstruction( - program_id=PublicKey(EVM_LOADER), - data=d, - keys=[ - AccountMeta(pubkey=holder_account, is_signer=False, is_writable=True), - AccountMeta(pubkey=operator, is_signer=True, is_writable=False), - ]) - - -def make_ExecuteTrxFromInstruction( - operator: Keypair, - evm_loader: "EvmLoader", - treasury_address: PublicKey, - treasury_buffer: bytes, - message: bytes, - additional_accounts: tp.List[PublicKey], - system_program=sp.SYS_PROGRAM_ID, -): - data = bytes([0x32]) + treasury_buffer + message - operator_ether = eth_keys.PrivateKey(operator.secret_key[:32]).public_key.to_canonical_address() - print("make_ExecuteTrxFromInstruction accounts") - print("Operator: ", operator.public_key) - print("Treasury: ", treasury_address) - print("Operator ether: ", operator_ether.hex()) - print("Operator eth solana: ", evm_loader.ether2balance(operator_ether)) - accounts = [ - AccountMeta(pubkey=operator.public_key, is_signer=True, is_writable=True), - AccountMeta(pubkey=treasury_address, is_signer=False, is_writable=True), - AccountMeta(pubkey=PublicKey(evm_loader.ether2balance(operator_ether)), is_signer=False, is_writable=True), - AccountMeta(system_program, is_signer=False, is_writable=True), - ] - for acc in additional_accounts: - print("Additional acc ", acc) - accounts.append(AccountMeta(acc, is_signer=False, is_writable=True), ) - - return TransactionInstruction( - program_id=PublicKey(EVM_LOADER), - data=data, - keys=accounts - ) - - -def make_ExecuteTrxFromAccountDataIterativeOrContinue( - index: int, - step_count: int, - operator: Keypair, - evm_loader: "EvmLoader", - holder_address: PublicKey, - treasury: TreasuryPool, - additional_accounts: tp.List[PublicKey], - sys_program_id=sp.SYS_PROGRAM_ID, - tag=0x35): - # 0x35 - TransactionStepFromAccount - # 0x36 - TransactionStepFromAccountNoChainId - data = tag.to_bytes(1, "little") + treasury.buffer + step_count.to_bytes(4, "little") + index.to_bytes(4, "little") - operator_ether = eth_keys.PrivateKey(operator.secret_key[:32]).public_key.to_canonical_address() - print("make_ExecuteTrxFromAccountDataIterativeOrContinue accounts") - print("Holder: ", holder_address) - print("Operator: ", operator.public_key) - print("Treasury: ", treasury.account) - print("Operator ether: ", operator_ether.hex()) - print("Operator eth solana: ", evm_loader.ether2balance(operator_ether)) - accounts = [ - AccountMeta(pubkey=holder_address, is_signer=False, is_writable=True), - AccountMeta(pubkey=operator.public_key, is_signer=True, is_writable=True), - AccountMeta(pubkey=treasury.account, is_signer=False, is_writable=True), - AccountMeta(pubkey=PublicKey(evm_loader.ether2balance(operator_ether)), is_signer=False, is_writable=True), - AccountMeta(sys_program_id, is_signer=False, is_writable=True), - ] - - for acc in additional_accounts: - print("Additional acc ", acc) - accounts.append(AccountMeta(acc, is_signer=False, is_writable=True), ) - - return TransactionInstruction( - program_id=PublicKey(EVM_LOADER), - data=data, - keys=accounts - ) - - -def make_PartialCallOrContinueFromRawEthereumTX( - index: int, - step_count: int, - instruction: bytes, - operator: Keypair, - evm_loader: "EvmLoader", - storage_address: PublicKey, - treasury: TreasuryPool, - additional_accounts: tp.List[PublicKey], - system_program=sp.SYS_PROGRAM_ID): - data = bytes([0x34]) + treasury.buffer + step_count.to_bytes(4, "little") + index.to_bytes(4, "little") + instruction - operator_ether = eth_keys.PrivateKey(operator.secret_key[:32]).public_key.to_canonical_address() - - accounts = [ - AccountMeta(pubkey=storage_address, is_signer=False, is_writable=True), - AccountMeta(pubkey=operator.public_key, is_signer=True, is_writable=True), - AccountMeta(pubkey=treasury.account, is_signer=False, is_writable=True), - AccountMeta(pubkey=evm_loader.ether2balance(operator_ether), is_signer=False, is_writable=True), - AccountMeta(system_program, is_signer=False, is_writable=True), - ] - for acc in additional_accounts: - accounts.append(AccountMeta(acc, is_signer=False, is_writable=True), ) - - return TransactionInstruction( - program_id=PublicKey(EVM_LOADER), - data=data, - keys=accounts - ) - - -def make_Cancel(evm_loader: "EvmLoader", storage_address: PublicKey, operator: Keypair, hash: bytes, additional_accounts: tp.List[PublicKey]): - data = bytes([0x37]) + hash - operator_ether = eth_keys.PrivateKey(operator.secret_key[:32]).public_key.to_canonical_address() - - accounts = [ - AccountMeta(pubkey=storage_address, is_signer=False, is_writable=True), - AccountMeta(pubkey=operator.public_key, is_signer=True, is_writable=True), - AccountMeta(pubkey=evm_loader.ether2balance(operator_ether), is_signer=False, is_writable=True), - ] - - for acc in additional_accounts: - accounts.append(AccountMeta(acc, is_signer=False, is_writable=True), ) - - return TransactionInstruction( - program_id=PublicKey(EVM_LOADER), - data=data, - keys=accounts - ) - - -def make_DepositV03( - ether_address: bytes, - chain_id: int, - balance_account: PublicKey, - contract_account: PublicKey, - mint: PublicKey, - source: PublicKey, - pool: PublicKey, - token_program: PublicKey, - operator_pubkey: PublicKey, -) -> TransactionInstruction: - data = bytes([0x31]) + ether_address + chain_id.to_bytes(8, 'little') - - accounts = [ - AccountMeta(pubkey=mint, is_signer=False, is_writable=True), - AccountMeta(pubkey=source, is_signer=False, is_writable=True), - AccountMeta(pubkey=pool, is_signer=False, is_writable=True), - AccountMeta(pubkey=balance_account, is_signer=False, is_writable=True), - AccountMeta(pubkey=contract_account, is_signer=False, is_writable=True), - AccountMeta(pubkey=token_program, is_signer=False, is_writable=False), - AccountMeta(pubkey=operator_pubkey, is_signer=True, is_writable=True), - AccountMeta(pubkey=sp.SYS_PROGRAM_ID, is_signer=False, is_writable=False), - ] - - return TransactionInstruction(program_id=PublicKey(EVM_LOADER), data=data, keys=accounts) - -def make_CreateAssociatedTokenIdempotent(payer: PublicKey, owner: PublicKey, mint: PublicKey) -> TransactionInstruction: - """Creates a transaction instruction to create an associated token account. - - Returns: - The instruction to create the associated token account. - """ - associated_token_address = get_associated_token_address(owner, mint) - return TransactionInstruction( - data=bytes([1]), - keys=[ - AccountMeta(pubkey=payer, is_signer=True, is_writable=True), - AccountMeta(pubkey=associated_token_address, is_signer=False, is_writable=True), - AccountMeta(pubkey=owner, is_signer=False, is_writable=False), - AccountMeta(pubkey=mint, is_signer=False, is_writable=False), - AccountMeta(pubkey=SYS_PROGRAM_ID, is_signer=False, is_writable=False), - AccountMeta(pubkey=TOKEN_PROGRAM_ID, is_signer=False, is_writable=False), - AccountMeta(pubkey=SYSVAR_RENT_PUBKEY, is_signer=False, is_writable=False), - ], - program_id=ASSOCIATED_TOKEN_PROGRAM_ID, - ) \ No newline at end of file diff --git a/tests/utils/layouts.py b/tests/utils/layouts.py deleted file mode 100644 index 461358bd0..000000000 --- a/tests/utils/layouts.py +++ /dev/null @@ -1,50 +0,0 @@ -from construct import Bytes, Int8ul, Struct, Int64ul, Int32ul - -STORAGE_ACCOUNT_INFO_LAYOUT = Struct( - "tag" / Int8ul, - "blocked" / Int8ul, - "owner" / Bytes(32), - "hash" / Bytes(32), - "caller" / Bytes(20), - "chain_id" / Int64ul, - "gas_limit" / Bytes(32), - "gas_price" / Bytes(32), - "gas_used" / Bytes(32), - "operator" / Bytes(32), - "slot" / Int64ul, - "account_list_len" / Int64ul, -) - -HOLDER_ACCOUNT_INFO_LAYOUT = Struct( - "tag" / Int8ul, - "blocked" / Int8ul, - "owner" / Bytes(32), - "hash" / Bytes(32), - "len" / Int64ul -) - - -FINALIZED_STORAGE_ACCOUNT_INFO_LAYOUT = Struct( - "tag" / Int8ul, - "blocked" / Int8ul, - "owner" / Bytes(32), - "hash" / Bytes(32), -) - - -CONTRACT_ACCOUNT_LAYOUT = Struct( - "type" / Int8ul, - "blocked" / Int8ul, - "address" / Bytes(20), - "chain_id" / Int64ul, - "generation" / Int32ul, -) - -BALANCE_ACCOUNT_LAYOUT = Struct( - "type" / Int8ul, - "blocked" / Int8ul, - "address" / Bytes(20), - "chain_id" / Int64ul, - "trx_count" / Int64ul, - "balance" / Bytes(32), -) \ No newline at end of file diff --git a/tests/utils/neon_api_client.py b/tests/utils/neon_api_client.py deleted file mode 100644 index 977085c9a..000000000 --- a/tests/utils/neon_api_client.py +++ /dev/null @@ -1,41 +0,0 @@ -import requests - -from .constants import CHAIN_ID, NEON_TOKEN_MINT_ID - - -class NeonApiClient: - def __init__(self, url): - self.url = url - self.headers = {"Content-Type": "application/json"} - - def emulate(self, sender, contract, data=bytes(), chain_id=CHAIN_ID, value='0x0', max_steps_to_execute=500000): - body = { - "step_limit": max_steps_to_execute, - "tx": { - "from": sender, - "to": contract, - "data": data.hex(), - "chain_id": chain_id, - "value": value - }, - "accounts": [] - } - - resp = requests.post(url=f"{self.url}/emulate", json=body, headers=self.headers) - print(resp.text) - return resp.json() - - def get_storage_at(self, contract_id, index="0x0"): - body = { - "contract": contract_id, - "index": index - } - return requests.post(url=f"{self.url}/storage", json=body, headers=self.headers).json() - - def get_ether_account_data(self, ether, chain_id = CHAIN_ID): - body = { - "account": [ - { "address": ether, "chain_id": chain_id } - ] - } - return requests.post(url=f"{self.url}/balance", json=body, headers=self.headers).json() \ No newline at end of file diff --git a/tests/utils/storage.py b/tests/utils/storage.py deleted file mode 100644 index 4876d459b..000000000 --- a/tests/utils/storage.py +++ /dev/null @@ -1,47 +0,0 @@ -from hashlib import sha256 -from random import randrange - -from solana.publickey import PublicKey -from solana.keypair import Keypair -from ..solana_utils import create_holder_account, get_solana_balance, create_account_with_seed, \ - send_transaction, solana_client -from solana.transaction import Transaction, TransactionInstruction, AccountMeta -from .constants import EVM_LOADER - - -def create_holder(signer: Keypair, seed: str = None, size: int = None, fund: int = None, - storage: PublicKey = None) -> PublicKey: - if size is None: - size = 128 * 1024 - if fund is None: - fund = 10 ** 9 - if seed is None: - seed = str(randrange(1000000)) - if storage is None: - storage = PublicKey( - sha256(bytes(signer.public_key) + bytes(seed, 'utf8') + bytes(PublicKey(EVM_LOADER))).digest()) - - print(f"Create holder account with seed: {seed}") - - if get_solana_balance(storage) == 0: - trx = Transaction() - trx.add( - create_account_with_seed(signer.public_key, signer.public_key, seed, fund, size), - create_holder_account(storage, signer.public_key, bytes(seed, 'utf8')) - ) - send_transaction(solana_client, trx, signer) - print(f"Created holder account: {storage}") - return storage - - -def delete_holder(del_key: PublicKey, acc: Keypair, signer: Keypair): - trx = Transaction() - - trx.add(TransactionInstruction( - program_id=PublicKey(EVM_LOADER), - data=bytes.fromhex("25"), - keys=[ - AccountMeta(pubkey=del_key, is_signer=False, is_writable=True), - AccountMeta(pubkey=acc.public_key, is_signer=(signer == acc), is_writable=True), - ])) - return send_transaction(solana_client, trx, signer) diff --git a/tests/utils/transaction_checks.py b/tests/utils/transaction_checks.py deleted file mode 100644 index 60e2b8f9c..000000000 --- a/tests/utils/transaction_checks.py +++ /dev/null @@ -1,28 +0,0 @@ -import base64 - -from solana.rpc.commitment import Confirmed - -from ..solana_utils import solana_client - - -def check_transaction_logs_have_text(trx_hash, text): - - receipt = solana_client.get_transaction(trx_hash) - logs = "" - for log in receipt.value.transaction.meta.log_messages: - if "Program data:" in log: - logs += "Program data: " - encoded_part = log.replace("Program data: ", "") - for item in encoded_part.split(" "): - logs += " " + str(base64.b64decode(item)) - else: - logs += log - logs += " " - assert text in logs, f"Transaction logs don't contain '{text}'. Logs: {logs}" - - -def check_holder_account_tag(storage_account, layout, expected_tag): - account_data = solana_client.get_account_info(storage_account, commitment=Confirmed).value.data - parsed_data = layout.parse(account_data) - assert parsed_data.tag == expected_tag, f"Account tag {account_data[0]} != expected {expected_tag}" - diff --git a/tests/utils/types.py b/tests/utils/types.py deleted file mode 100644 index e1001f6e5..000000000 --- a/tests/utils/types.py +++ /dev/null @@ -1,26 +0,0 @@ -from dataclasses import dataclass -from solana.publickey import PublicKey -from solana.keypair import Keypair - - -@dataclass -class TreasuryPool: - index: int - account: PublicKey - buffer: bytes - - -@dataclass -class Caller: - solana_account: Keypair - solana_account_address: PublicKey - balance_account_address: PublicKey - eth_address: bytes - token_address: PublicKey - - -@dataclass -class Contract: - eth_address: bytes - solana_address: PublicKey - balance_account_address: PublicKey From 8aa89175143afd93b13454e8aafcbf8a0e1f8f63 Mon Sep 17 00:00:00 2001 From: Kristina Nikolaeva <112946046+kristinaNikolaevaa@users.noreply.github.com> Date: Thu, 4 Jan 2024 10:10:24 +0100 Subject: [PATCH 080/318] fix container name (#250) --- .github/workflows/deploy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index 587bcdac6..1c5eecfb6 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -139,7 +139,7 @@ def run_tests(github_sha, neon_test_branch): exec_status = docker_client.exec_inspect(exec_id['Id'])["ExitCode"] - run_subprocess(f"docker-compose -p {project_name} -f ./ci/docker-compose-ci.yml logs dk-neon-api") + run_subprocess(f"docker-compose -p {project_name} -f ./ci/docker-compose-ci.yml logs neon-core-api") stop_containers(project_name) From def4fdb9dc2debefff0d6b547b8409516b8a38ca Mon Sep 17 00:00:00 2001 From: Mick van Gelderen Date: Fri, 12 Jan 2024 14:27:41 +0100 Subject: [PATCH 081/318] Eliminate `evm::buffer::Inner::Empty` (#259) * Eliminate `evm::buffer::Inner::Empty` The `Empty` variant was added when we had different memory allocators. Currently we can also represent the emptyness of the buffer trough the `Inner::Owned` variant since that holds a `Vec` which can be empty. --- evm_loader/program/src/evm/buffer.rs | 133 ++++++++++++++++++++++----- 1 file changed, 110 insertions(+), 23 deletions(-) diff --git a/evm_loader/program/src/evm/buffer.rs b/evm_loader/program/src/evm/buffer.rs index 119f24328..7d2b05d34 100644 --- a/evm_loader/program/src/evm/buffer.rs +++ b/evm_loader/program/src/evm/buffer.rs @@ -1,15 +1,9 @@ -use std::{ - ops::{Deref, Range}, - ptr::NonNull, -}; +use std::ops::{Deref, Range}; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; enum Inner { - Empty, - Owned { - data: Vec, - }, + Owned(Vec), Account { key: Pubkey, range: Range, @@ -22,6 +16,8 @@ enum Inner { } pub struct Buffer { + // We maintain a ptr and len to be able to construct a slice without having to discriminate + // inner. This means we should not allow mutation of inner after the construction of a buffer. ptr: *const u8, len: usize, inner: Inner, @@ -30,8 +26,7 @@ pub struct Buffer { impl Buffer { fn new(inner: Inner) -> Self { let (ptr, len) = match &inner { - Inner::Empty => (NonNull::dangling().as_ptr() as *const _, 0), - Inner::Owned { data } => (data.as_ptr(), data.len()), + Inner::Owned(data) => (data.as_ptr(), data.len()), Inner::Account { data, range, .. } => { let ptr = unsafe { data.add(range.start) }; (ptr, range.len()) @@ -65,12 +60,7 @@ impl Buffer { #[must_use] pub fn from_vec(v: Vec) -> Self { - if v.is_empty() { - return Self::empty(); - } - - let inner = Inner::Owned { data: v }; - Self::new(inner) + Self::new(Inner::Owned(v)) } #[must_use] @@ -80,7 +70,7 @@ impl Buffer { #[must_use] pub fn empty() -> Self { - Buffer::new(Inner::Empty) + Buffer::new(Inner::Owned(Vec::default())) } #[must_use] @@ -125,7 +115,6 @@ impl Clone for Buffer { #[inline] fn clone(&self) -> Self { match &self.inner { - Inner::Empty => Self::empty(), Inner::Owned { .. } => Self::from_slice(self), Inner::Account { key, data, range } => Self::new(Inner::Account { key: *key, @@ -154,8 +143,7 @@ impl serde::Serialize for Buffer { use serde::ser::SerializeStructVariant; match &self.inner { - Inner::Empty => serializer.serialize_unit_variant("evm_buffer", 0, "empty"), - Inner::Owned { data } => { + Inner::Owned(data) => { let bytes = serde_bytes::Bytes::new(data); serializer.serialize_newtype_variant("evm_buffer", 1, "owned", bytes) } @@ -221,17 +209,116 @@ impl<'de> serde::Deserialize<'de> for Buffer { let (index, variant) = data.variant::()?; match index { - 0 => variant.unit_variant().map(|_| Buffer::empty()), 1 => variant.newtype_variant().map(Buffer::from_slice), 2 => variant.struct_variant(&["key", "range"], self), _ => Err(serde::de::Error::unknown_variant( "_", - &["empty", "owned", "account"], + &["owned", "account"], )), } } } - deserializer.deserialize_enum("evm_buffer", &["empty", "owned", "account"], BufferVisitor) + deserializer.deserialize_enum("evm_buffer", &["owned", "account"], BufferVisitor) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::cell::RefCell; + use std::rc::Rc; + + macro_rules! assert_slice_ptr_eq { + ($actual:expr, $expected:expr) => {{ + let actual: &[_] = $actual; + let (expected_ptr, expected_len): (*const _, usize) = $expected; + assert_eq!(actual.as_ptr(), expected_ptr); + assert_eq!(actual.len(), expected_len); + }}; + } + + #[test] + fn test_deref_owned_empty() { + let data = Vec::default(); + let expected = (data.as_ptr(), data.len()); + assert_slice_ptr_eq!(&*Buffer::default(), expected); + } + + #[test] + fn test_deref_owned_non_empty() { + let data = vec![1]; + let expected = (data.as_ptr(), data.len()); + assert_slice_ptr_eq!(&*Buffer::from_vec(data), expected); + } + + struct OwnedAccountInfo { + key: Pubkey, + lamports: u64, + data: Vec, + owner: Pubkey, + rent_epoch: u64, + is_signer: bool, + is_writable: bool, + executable: bool, + } + + impl OwnedAccountInfo { + fn with_data(data: Vec) -> Self { + OwnedAccountInfo { + key: Pubkey::default(), + lamports: 0, + data, + owner: Pubkey::default(), + rent_epoch: 0, + is_signer: false, + is_writable: false, + executable: false, + } + } + + fn as_mut(&mut self) -> AccountInfo<'_> { + AccountInfo { + key: &self.key, + lamports: Rc::new(RefCell::new(&mut self.lamports)), + data: Rc::new(RefCell::new(&mut self.data)), + owner: &self.owner, + rent_epoch: self.rent_epoch, + is_signer: self.is_signer, + is_writable: self.is_writable, + executable: self.executable, + } + } + } + + #[test] + fn test_deref_account_empty() { + let data = Vec::default(); + let expected = (data.as_ptr(), data.len()); + let mut account_info = OwnedAccountInfo::with_data(data); + assert_slice_ptr_eq!( + &*unsafe { Buffer::from_account(&account_info.as_mut(), 0..expected.1) }, + expected + ); + } + + #[test] + fn test_deref_account_non_empty() { + let data = vec![1]; + let expected = (data.as_ptr(), data.len()); + let mut account_info = OwnedAccountInfo::with_data(data); + assert_slice_ptr_eq!( + &*unsafe { Buffer::from_account(&account_info.as_mut(), 0..expected.1) }, + expected + ); + } + + #[test] + #[should_panic(expected = "assertion failed: !self.ptr.is_null()")] + fn test_deref_account_uninit() { + let _: &[u8] = &Buffer::new(Inner::AccountUninit { + key: Pubkey::default(), + range: 0..0, + }); } } From a5e934764cae4586f8e40fc5237090905b2cb42a Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Fri, 12 Jan 2024 13:19:55 +0300 Subject: [PATCH 082/318] Remove operator's priority --- evm_loader/program/config/common.toml | 1 - evm_loader/program/src/account/state.rs | 19 ++++--------------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/evm_loader/program/config/common.toml b/evm_loader/program/config/common.toml index 717b0bf35..3c431349a 100644 --- a/evm_loader/program/config/common.toml +++ b/evm_loader/program/config/common.toml @@ -1,6 +1,5 @@ account_seed_version = [3, "u8"] payment_to_treasure = 5000 -operator_priority_slots = 16 holder_msg_size = 950 evm_steps_min = 500 evm_steps_last_iteration_max = 1 diff --git a/evm_loader/program/src/account/state.rs b/evm_loader/program/src/account/state.rs index e7b235e1c..53d22e382 100644 --- a/evm_loader/program/src/account/state.rs +++ b/evm_loader/program/src/account/state.rs @@ -1,7 +1,7 @@ use std::cell::{Ref, RefMut}; use std::mem::size_of; -use crate::config::{GAS_LIMIT_MULTIPLIER_NO_CHAINID, OPERATOR_PRIORITY_SLOTS}; +use crate::config::GAS_LIMIT_MULTIPLIER_NO_CHAINID; use crate::error::{Error, Result}; use crate::types::{Address, Transaction}; use ethnum::U256; @@ -144,7 +144,7 @@ impl<'a> StateAccount<'a> { } } - state.update_priority_operator(&accounts.operator)?; + state.update_current_operator(&accounts.operator); Ok(state) } @@ -270,20 +270,9 @@ impl<'a> StateAccount<'a> { Ok(()) } - fn update_priority_operator(&mut self, operator: &Operator) -> Result<()> { + fn update_current_operator(&mut self, operator: &Operator) { let mut header = self.header_mut(); - - if operator.key != &header.operator { - let clock = Clock::get()?; - if (clock.slot - header.slot) <= OPERATOR_PRIORITY_SLOTS { - return Err(Error::HolderInvalidOwner(header.owner, *operator.key)); - } - - header.operator = *operator.key; - header.slot = clock.slot; - } - - Ok(()) + header.operator = *operator.key; } #[must_use] From b4afacd808031ee0dc4c3e9d8d489803a201770c Mon Sep 17 00:00:00 2001 From: Mick van Gelderen Date: Fri, 12 Jan 2024 16:09:33 +0100 Subject: [PATCH 083/318] Deduplicate `OwnedAccountInfo` (#260) Removes the duplicate definition from the buffer tests. --- evm_loader/program/src/evm/buffer.rs | 32 ++++------------------------ 1 file changed, 4 insertions(+), 28 deletions(-) diff --git a/evm_loader/program/src/evm/buffer.rs b/evm_loader/program/src/evm/buffer.rs index 7d2b05d34..e71a87649 100644 --- a/evm_loader/program/src/evm/buffer.rs +++ b/evm_loader/program/src/evm/buffer.rs @@ -226,8 +226,8 @@ impl<'de> serde::Deserialize<'de> for Buffer { #[cfg(test)] mod tests { use super::*; - use std::cell::RefCell; - use std::rc::Rc; + use crate::executor::OwnedAccountInfo; + use solana_program::account_info::IntoAccountInfo; macro_rules! assert_slice_ptr_eq { ($actual:expr, $expected:expr) => {{ @@ -252,17 +252,6 @@ mod tests { assert_slice_ptr_eq!(&*Buffer::from_vec(data), expected); } - struct OwnedAccountInfo { - key: Pubkey, - lamports: u64, - data: Vec, - owner: Pubkey, - rent_epoch: u64, - is_signer: bool, - is_writable: bool, - executable: bool, - } - impl OwnedAccountInfo { fn with_data(data: Vec) -> Self { OwnedAccountInfo { @@ -276,19 +265,6 @@ mod tests { executable: false, } } - - fn as_mut(&mut self) -> AccountInfo<'_> { - AccountInfo { - key: &self.key, - lamports: Rc::new(RefCell::new(&mut self.lamports)), - data: Rc::new(RefCell::new(&mut self.data)), - owner: &self.owner, - rent_epoch: self.rent_epoch, - is_signer: self.is_signer, - is_writable: self.is_writable, - executable: self.executable, - } - } } #[test] @@ -297,7 +273,7 @@ mod tests { let expected = (data.as_ptr(), data.len()); let mut account_info = OwnedAccountInfo::with_data(data); assert_slice_ptr_eq!( - &*unsafe { Buffer::from_account(&account_info.as_mut(), 0..expected.1) }, + &*unsafe { Buffer::from_account(&account_info.into_account_info(), 0..expected.1) }, expected ); } @@ -308,7 +284,7 @@ mod tests { let expected = (data.as_ptr(), data.len()); let mut account_info = OwnedAccountInfo::with_data(data); assert_slice_ptr_eq!( - &*unsafe { Buffer::from_account(&account_info.as_mut(), 0..expected.1) }, + &*unsafe { Buffer::from_account(&account_info.into_account_info(), 0..expected.1) }, expected ); } From ea0d657cfcc1e19f5ec6762d2462d2b554079753 Mon Sep 17 00:00:00 2001 From: Mick van Gelderen Date: Mon, 15 Jan 2024 14:49:48 +0100 Subject: [PATCH 084/318] Add Buffer serialization and deserialization tests (#263) Also considering serialized data from previous versions. --- evm_loader/program/src/evm/buffer.rs | 101 +++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/evm_loader/program/src/evm/buffer.rs b/evm_loader/program/src/evm/buffer.rs index e71a87649..23f5a2e7a 100644 --- a/evm_loader/program/src/evm/buffer.rs +++ b/evm_loader/program/src/evm/buffer.rs @@ -2,6 +2,7 @@ use std::ops::{Deref, Range}; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; +#[cfg_attr(test, derive(Debug, PartialEq))] enum Inner { Owned(Vec), Account { @@ -15,6 +16,7 @@ enum Inner { }, } +#[cfg_attr(test, derive(Debug))] pub struct Buffer { // We maintain a ptr and len to be able to construct a slice without having to discriminate // inner. This means we should not allow mutation of inner after the construction of a buffer. @@ -23,6 +25,13 @@ pub struct Buffer { inner: Inner, } +#[cfg(test)] +impl core::cmp::PartialEq for Buffer { + fn eq(&self, other: &Self) -> bool { + self.inner == other.inner + } +} + impl Buffer { fn new(inner: Inner) -> Self { let (ptr, len) = match &inner { @@ -209,6 +218,7 @@ impl<'de> serde::Deserialize<'de> for Buffer { let (index, variant) = data.variant::()?; match index { + 0 => variant.unit_variant().map(|()| Buffer::empty()), 1 => variant.newtype_variant().map(Buffer::from_slice), 2 => variant.struct_variant(&["key", "range"], self), _ => Err(serde::de::Error::unknown_variant( @@ -297,4 +307,95 @@ mod tests { range: 0..0, }); } + + #[test] + fn historic_empty_deserialization_works() { + let serialized = [ + 0, 0, 0, 0, // Variant + ]; + let deserialized = Buffer::empty(); + assert_eq!( + bincode::deserialize::(&serialized).unwrap(), + deserialized + ); + } + + #[test] + fn non_empty_owned_serialization_works() { + let deserialized = Buffer::from_vec(vec![0xcc; 3]); + let serialized = [ + 1, 0, 0, 0, // Variant + 3, 0, 0, 0, 0, 0, 0, 0, // Byte count + 0xcc, 0xcc, 0xcc, // Bytes + ]; + assert_eq!(bincode::serialize(&deserialized).unwrap(), serialized); + } + + #[test] + fn non_empty_owned_deserialization_works() { + let serialized = [ + 1, 0, 0, 0, // Variant + 3, 0, 0, 0, 0, 0, 0, 0, // Byte count + 0xcc, 0xcc, 0xcc, // Bytes + ]; + let deserialized = Buffer::from_vec(vec![0xcc; 3]); + assert_eq!( + bincode::deserialize::(&serialized).unwrap(), + deserialized + ); + } + + #[test] + fn non_empty_account_serialization_works() { + let mut account = OwnedAccountInfo { + key: Pubkey::from([0xaa; 32]), + is_signer: false, + is_writable: false, + lamports: 0, + data: vec![0xcc; 10], + owner: Pubkey::from([0xbb; 32]), + executable: false, + rent_epoch: 0, + }; + let deserialized = unsafe { Buffer::from_account(&account.into_account_info(), 6..8) }; + let serialized = [ + 2, 0, 0, 0, // Variant + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, // Pubkey + 6, 0, 0, 0, 0, 0, 0, 0, // Range start + 8, 0, 0, 0, 0, 0, 0, 0, // Range end + ]; + assert_eq!(bincode::serialize(&deserialized).unwrap(), serialized); + } + + #[test] + fn non_empty_account_deserialization_works() { + let serialized = [ + 2, 0, 0, 0, // Variant + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, // Pubkey + 6, 0, 0, 0, 0, 0, 0, 0, // Range start + 8, 0, 0, 0, 0, 0, 0, 0, // Range end + ]; + let deserialized = Buffer::new(Inner::AccountUninit { + key: Pubkey::from([0xaa; 32]), + range: 6..8, + }); + assert_eq!( + bincode::deserialize::(&serialized).unwrap(), + deserialized + ); + } + + #[test] + #[should_panic(expected = "unreachable")] + fn account_uninit_serialization_fails() { + let _: Vec = bincode::serialize(&Buffer::new(Inner::AccountUninit { + key: Pubkey::default(), + range: 0..0, + })) + .unwrap(); + } } From 7e70f95cb18afb6148db0fc17ee19c4c2f42cbb9 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Tue, 16 Jan 2024 11:09:49 +0200 Subject: [PATCH 085/318] NDEV-2514: Refactor get_config module (#255) * NDEV-2514: Refactor get_config module * Remove unused code * Address code review --- evm_loader/lib/src/commands/get_config.rs | 313 +++++++++++++-------- evm_loader/lib/src/rpc/mod.rs | 1 - evm_loader/lib/src/rpc/validator_client.rs | 59 +--- evm_loader/lib/src/syscall_stubs.rs | 4 - evm_loader/program/src/account/program.rs | 23 -- 5 files changed, 205 insertions(+), 195 deletions(-) diff --git a/evm_loader/lib/src/commands/get_config.rs b/evm_loader/lib/src/commands/get_config.rs index e697de497..84f2b8b17 100644 --- a/evm_loader/lib/src/commands/get_config.rs +++ b/evm_loader/lib/src/commands/get_config.rs @@ -2,7 +2,7 @@ use async_trait::async_trait; use base64::Engine; use enum_dispatch::enum_dispatch; use std::collections::BTreeMap; -use tokio::sync::{Mutex, MutexGuard, OnceCell}; +use std::str::FromStr; use serde::{Deserialize, Serialize}; use solana_program_test::{ProgramTest, ProgramTestContext}; @@ -20,9 +20,11 @@ use solana_sdk::{ use crate::{rpc::Rpc, NeonError, NeonResult}; -use crate::rpc::{CallDbClient, CloneRpcClient, SolanaRpc}; +use crate::rpc::{CallDbClient, CloneRpcClient}; use serde_with::{serde_as, DisplayFromStr}; -use solana_client::nonblocking::rpc_client::RpcClient; +use solana_client::client_error::Result as ClientResult; +use solana_client::rpc_config::{RpcLargestAccountsConfig, RpcSimulateTransactionConfig}; +use tokio::sync::{Mutex, MutexGuard, OnceCell}; #[derive(Debug, Serialize)] pub enum Status { @@ -51,58 +53,58 @@ pub struct GetConfigResponse { pub config: BTreeMap, } -static PROGRAM_TEST: OnceCell> = OnceCell::const_new(); - -async fn read_program_data_from_account( - rpc: &CallDbClient, - program_id: Pubkey, -) -> NeonResult> { - let Some(account) = rpc.get_account(&program_id).await?.value else { - return Err(NeonError::AccountNotFound(program_id)); - }; +impl CallDbClient { + async fn read_program_data_from_account(&self, program_id: Pubkey) -> NeonResult> { + let Some(account) = self.get_account(&program_id).await?.value else { + return Err(NeonError::AccountNotFound(program_id)); + }; - if account.owner == bpf_loader::id() || account.owner == bpf_loader_deprecated::id() { - return Ok(account.data); - } + if account.owner == bpf_loader::id() || account.owner == bpf_loader_deprecated::id() { + return Ok(account.data); + } - if account.owner != bpf_loader_upgradeable::id() { - return Err(NeonError::AccountIsNotBpf(program_id)); - } + if account.owner != bpf_loader_upgradeable::id() { + return Err(NeonError::AccountIsNotBpf(program_id)); + } - if let Ok(UpgradeableLoaderState::Program { - programdata_address, - }) = account.state() - { - let Some(programdata_account) = rpc.get_account(&programdata_address).await?.value else { - return Err(NeonError::AssociatedPdaNotFound(programdata_address, program_id)); - }; + if let Ok(UpgradeableLoaderState::Program { + programdata_address, + }) = account.state() + { + let Some(programdata_account) = self.get_account(&programdata_address).await?.value else { + return Err(NeonError::AssociatedPdaNotFound(programdata_address, program_id)); + }; - let offset = UpgradeableLoaderState::size_of_programdata_metadata(); - let program_data = &programdata_account.data[offset..]; + let offset = UpgradeableLoaderState::size_of_programdata_metadata(); + let program_data = &programdata_account.data[offset..]; - Ok(program_data.to_vec()) - } else { - Err(NeonError::AccountIsNotUpgradeable(program_id)) + Ok(program_data.to_vec()) + } else { + Err(NeonError::AccountIsNotUpgradeable(program_id)) + } } } -async fn lock_program_test( - program_id: Pubkey, - program_data: Vec, -) -> MutexGuard<'static, ProgramTestContext> { - async fn init_program_test() -> Mutex { - let program_test = ProgramTest::default(); - let context = program_test.start_with_context().await; - Mutex::new(context) +async fn program_test_context() -> MutexGuard<'static, ProgramTestContext> { + static PROGRAM_TEST_CONTEXT: OnceCell> = OnceCell::const_new(); + + async fn init_program_test_context() -> Mutex { + Mutex::new(ProgramTest::default().start_with_context().await) } - let mut context = PROGRAM_TEST - .get_or_init(init_program_test) + PROGRAM_TEST_CONTEXT + .get_or_init(init_program_test_context) .await .lock() - .await; + .await +} - context.set_account( +fn set_program_account( + program_test_context: &mut ProgramTestContext, + program_id: Pubkey, + program_data: Vec, +) { + program_test_context.set_account( &program_id, &AccountSharedData::from(Account { lamports: Rent::default().minimum_balance(program_data.len()).max(1), @@ -112,13 +114,11 @@ async fn lock_program_test( rent_epoch: 0, }), ); - - context } pub enum ConfigSimulator<'r> { - Rpc(Pubkey, &'r RpcClient), - ProgramTest(MutexGuard<'static, ProgramTestContext>), + CloneRpcClient(Pubkey, &'r CloneRpcClient), + ProgramTestContext(Pubkey, MutexGuard<'static, ProgramTestContext>), } #[async_trait(?Send)] @@ -129,71 +129,116 @@ pub trait BuildConfigSimulator { #[async_trait(?Send)] impl BuildConfigSimulator for CloneRpcClient { - async fn build_config_simulator(&self, _program_id: Pubkey) -> NeonResult { - Ok(ConfigSimulator::Rpc( - self.get_account_with_sol().await?, - self, - )) + async fn build_config_simulator(&self, program_id: Pubkey) -> NeonResult { + Ok(ConfigSimulator::CloneRpcClient(program_id, self)) } } #[async_trait(?Send)] impl BuildConfigSimulator for CallDbClient { async fn build_config_simulator(&self, program_id: Pubkey) -> NeonResult { - let program_data = read_program_data_from_account(self, program_id).await?; - let mut program_test = lock_program_test(program_id, program_data).await; - program_test.get_new_latest_blockhash().await?; + let program_data = self.read_program_data_from_account(program_id).await?; + + let mut program_test_context = program_test_context().await; + + set_program_account(&mut program_test_context, program_id, program_data); + program_test_context.get_new_latest_blockhash().await?; + + Ok(ConfigSimulator::ProgramTestContext( + program_id, + program_test_context, + )) + } +} + +impl CloneRpcClient { + async fn simulate_solana_instruction( + &self, + instruction: Instruction, + ) -> NeonResult> { + let tx = + Transaction::new_with_payer(&[instruction], Some(&self.get_account_with_sol().await?)); + + let result = self + .simulate_transaction_with_config( + &tx, + RpcSimulateTransactionConfig { + sig_verify: false, + replace_recent_blockhash: true, + ..RpcSimulateTransactionConfig::default() + }, + ) + .await? + .value; + + if let Some(e) = result.err { + return Err(e.into()); + } + Ok(result.logs.unwrap()) + } +} + +#[async_trait(?Send)] +trait SolanaInstructionSimulator { + async fn simulate_solana_instruction( + &mut self, + instruction: Instruction, + ) -> NeonResult>; +} - Ok(ConfigSimulator::ProgramTest(program_test)) +#[async_trait(?Send)] +impl SolanaInstructionSimulator for ProgramTestContext { + async fn simulate_solana_instruction( + &mut self, + instruction: Instruction, + ) -> NeonResult> { + let tx = Transaction::new_signed_with_payer( + &[instruction], + Some(&self.payer.pubkey()), + &[&self.payer], + self.last_blockhash, + ); + + // TODO: Fix failure to simulate transaction + // it can come from old NeonEVM program without chain_id support for old tx, when it should return default chain_id info + let result = self + .banks_client + .simulate_transaction(tx) + .await + .map_err(|e| NeonError::from(Box::new(e)))?; + + result.result.unwrap()?; + + Ok(result.simulation_details.unwrap().logs) } } impl ConfigSimulator<'_> { - async fn simulate_config( + fn program_id(&self) -> Pubkey { + match self { + ConfigSimulator::CloneRpcClient(program_id, _) => *program_id, + ConfigSimulator::ProgramTestContext(program_id, _) => *program_id, + } + } + + async fn simulate_evm_instruction( &mut self, - program_id: Pubkey, - instruction: u8, + evm_instruction: u8, data: &[u8], ) -> NeonResult> { fn base64_decode(s: &str) -> Vec { base64::engine::general_purpose::STANDARD.decode(s).unwrap() } - let input = [&[instruction], data].concat(); - - let logs = match self { - ConfigSimulator::Rpc(signer, rpc) => { - let result = rpc - .simulate_transaction_with_instructions( - Some(*signer), - &[Instruction::new_with_bytes(program_id, &input, vec![])], - ) - .await? - .value; - - if let Some(e) = result.err { - return Err(e.into()); - } - result.logs.unwrap() - } - ConfigSimulator::ProgramTest(context) => { - let payer_pubkey = context.payer.pubkey(); - let tx = Transaction::new_signed_with_payer( - &[Instruction::new_with_bytes(program_id, &input, vec![])], - Some(&payer_pubkey), - &[&context.payer], - context.last_blockhash, - ); - let result = context - .banks_client - .simulate_transaction(tx) - .await - .map_err(|e| NeonError::from(Box::new(e)))?; + let program_id = self.program_id(); - result.result.unwrap()?; - result.simulation_details.unwrap().logs - } - }; + let logs = self + .simulate_solana_instruction(Instruction::new_with_bytes( + program_id, + &[&[evm_instruction], data].concat(), + vec![], + )) + .await?; // Program return: 53DfF883gyixYNXnM7s5xhdeyV8mVk9T4i2hGV9vG9io AQAAAAAAAAA= let return_data = logs @@ -207,15 +252,33 @@ impl ConfigSimulator<'_> { Ok(return_data) } - async fn get_version(&mut self, program_id: Pubkey) -> NeonResult<(String, String)> { - let return_data = self.simulate_config(program_id, 0xA7, &[]).await?; + async fn simulate_solana_instruction( + &mut self, + instruction: Instruction, + ) -> NeonResult> { + match self { + ConfigSimulator::CloneRpcClient(_, clone_rpc_client) => { + clone_rpc_client + .simulate_solana_instruction(instruction) + .await + } + ConfigSimulator::ProgramTestContext(_, program_test_context) => { + program_test_context + .simulate_solana_instruction(instruction) + .await + } + } + } + + async fn get_version(&mut self) -> NeonResult<(String, String)> { + let return_data = self.simulate_evm_instruction(0xA7, &[]).await?; let (version, revision) = bincode::deserialize(&return_data)?; Ok((version, revision)) } - async fn get_status(&mut self, program_id: Pubkey) -> NeonResult { - let return_data = self.simulate_config(program_id, 0xA6, &[]).await?; + async fn get_status(&mut self) -> NeonResult { + let return_data = self.simulate_evm_instruction(0xA6, &[]).await?; match return_data[0] { 0 => Ok(Status::Emergency), 1 => Ok(Status::Ok), @@ -223,23 +286,23 @@ impl ConfigSimulator<'_> { } } - async fn get_environment(&mut self, program_id: Pubkey) -> NeonResult { - let return_data = self.simulate_config(program_id, 0xA2, &[]).await?; + async fn get_environment(&mut self) -> NeonResult { + let return_data = self.simulate_evm_instruction(0xA2, &[]).await?; let environment = String::from_utf8(return_data)?; Ok(environment) } - async fn get_chains(&mut self, program_id: Pubkey) -> NeonResult> { + async fn get_chains(&mut self) -> NeonResult> { let mut result = Vec::new(); - let return_data = self.simulate_config(program_id, 0xA0, &[]).await?; + let return_data = self.simulate_evm_instruction(0xA0, &[]).await?; let chain_count = return_data.as_slice().try_into()?; let chain_count = usize::from_le_bytes(chain_count); for i in 0..chain_count { let index = i.to_le_bytes(); - let return_data = self.simulate_config(program_id, 0xA1, &index).await?; + let return_data = self.simulate_evm_instruction(0xA1, &index).await?; let (id, name, token) = bincode::deserialize(&return_data)?; result.push(ChainInfo { id, name, token }); @@ -248,16 +311,16 @@ impl ConfigSimulator<'_> { Ok(result) } - async fn get_properties(&mut self, program_id: Pubkey) -> NeonResult> { + async fn get_properties(&mut self) -> NeonResult> { let mut result = BTreeMap::new(); - let return_data = self.simulate_config(program_id, 0xA3, &[]).await?; + let return_data = self.simulate_evm_instruction(0xA3, &[]).await?; let count = return_data.as_slice().try_into()?; let count = usize::from_le_bytes(count); for i in 0..count { let index = i.to_le_bytes(); - let return_data = self.simulate_config(program_id, 0xA4, &index).await?; + let return_data = self.simulate_evm_instruction(0xA4, &index).await?; let (name, value) = bincode::deserialize(&return_data)?; result.insert(name, value); @@ -273,15 +336,15 @@ pub async fn execute( ) -> NeonResult { let mut simulator = rpc.build_config_simulator(program_id).await?; - let (version, revision) = simulator.get_version(program_id).await?; + let (version, revision) = simulator.get_version().await?; Ok(GetConfigResponse { version, revision, - status: simulator.get_status(program_id).await?, - environment: simulator.get_environment(program_id).await?, - chains: simulator.get_chains(program_id).await?, - config: simulator.get_properties(program_id).await?, + status: simulator.get_status().await?, + environment: simulator.get_environment().await?, + chains: simulator.get_chains().await?, + config: simulator.get_properties().await?, }) } @@ -291,5 +354,35 @@ pub async fn read_chains( ) -> NeonResult> { let mut simulator = rpc.build_config_simulator(program_id).await?; - simulator.get_chains(program_id).await + simulator.get_chains().await +} + +impl CloneRpcClient { + async fn get_account_with_sol(&self) -> ClientResult { + let r = self + .get_largest_accounts_with_config(RpcLargestAccountsConfig { + commitment: Some(self.commitment()), + filter: None, + }) + .await?; // TODO https://neonlabs.atlassian.net/browse/NDEV-2462 replace with more efficient RPC call + + Ok(Pubkey::from_str(&r.value[0].address).unwrap()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_bpf_loader_pubkey() { + let pubkey = Pubkey::from([ + 2, 168, 246, 145, 78, 136, 161, 110, 57, 90, 225, 40, 148, 143, 250, 105, 86, 147, 55, + 104, 24, 221, 71, 67, 82, 33, 243, 198, 0, 0, 0, 0, + ]); + assert_eq!( + format!("{}", pubkey), + "BPFLoader2111111111111111111111111111111111" + ); + } } diff --git a/evm_loader/lib/src/rpc/mod.rs b/evm_loader/lib/src/rpc/mod.rs index 0a641e027..995b0203f 100644 --- a/evm_loader/lib/src/rpc/mod.rs +++ b/evm_loader/lib/src/rpc/mod.rs @@ -3,7 +3,6 @@ mod validator_client; pub use db_call_client::CallDbClient; pub use validator_client::CloneRpcClient; -pub use validator_client::SolanaRpc; use crate::commands::get_config::{BuildConfigSimulator, ConfigSimulator}; use crate::{NeonError, NeonResult}; diff --git a/evm_loader/lib/src/rpc/validator_client.rs b/evm_loader/lib/src/rpc/validator_client.rs index 9e75de53c..a940230ed 100644 --- a/evm_loader/lib/src/rpc/validator_client.rs +++ b/evm_loader/lib/src/rpc/validator_client.rs @@ -1,21 +1,16 @@ use super::Rpc; use async_trait::async_trait; use solana_client::{ - client_error::Result as ClientResult, - nonblocking::rpc_client::RpcClient, - rpc_config::{RpcLargestAccountsConfig, RpcSimulateTransactionConfig}, - rpc_response::{RpcResult, RpcSimulateTransactionResult}, + client_error::Result as ClientResult, nonblocking::rpc_client::RpcClient, + rpc_response::RpcResult, }; use solana_sdk::{ account::Account, clock::{Slot, UnixTimestamp}, commitment_config::CommitmentConfig, - instruction::Instruction, pubkey::Pubkey, - transaction::Transaction, }; use std::ops::Deref; -use std::str::FromStr; use std::sync::Arc; #[derive(Clone)] @@ -72,53 +67,3 @@ impl Rpc for CloneRpcClient { self.0.get_slot().await } } - -#[async_trait(?Send)] -pub trait SolanaRpc { - async fn simulate_transaction_with_instructions( - &self, - signer: Option, - instructions: &[Instruction], - ) -> RpcResult; - - async fn get_account_with_sol(&self) -> ClientResult; -} - -#[async_trait(?Send)] -impl SolanaRpc for RpcClient { - async fn simulate_transaction_with_instructions( - &self, - signer: Option, - instructions: &[Instruction], - ) -> RpcResult { - let payer_pubkey = if let Some(signer) = signer { - signer - } else { - self.get_account_with_sol().await? - }; - - let tx = Transaction::new_with_payer(instructions, Some(&payer_pubkey)); - - self.simulate_transaction_with_config( - &tx, - RpcSimulateTransactionConfig { - sig_verify: false, - replace_recent_blockhash: true, - ..RpcSimulateTransactionConfig::default() - }, - ) - .await - } - - async fn get_account_with_sol(&self) -> ClientResult { - let r = self - .get_largest_accounts_with_config(RpcLargestAccountsConfig { - commitment: Some(self.commitment()), - filter: None, - }) - .await?; - - let pubkey = Pubkey::from_str(&r.value[0].address).unwrap(); - Ok(pubkey) - } -} diff --git a/evm_loader/lib/src/syscall_stubs.rs b/evm_loader/lib/src/syscall_stubs.rs index 4f996e4c1..0def2705b 100644 --- a/evm_loader/lib/src/syscall_stubs.rs +++ b/evm_loader/lib/src/syscall_stubs.rs @@ -3,10 +3,6 @@ use solana_sdk::{program_error::ProgramError, program_stubs::SyscallStubs, sysva use crate::{errors::NeonError, rpc::Rpc}; -pub struct DefaultStubs; - -impl SyscallStubs for DefaultStubs {} - pub struct EmulatorStubs { rent: Rent, } diff --git a/evm_loader/program/src/account/program.rs b/evm_loader/program/src/account/program.rs index 2edb49a9d..756d01220 100644 --- a/evm_loader/program/src/account/program.rs +++ b/evm_loader/program/src/account/program.rs @@ -7,29 +7,6 @@ use solana_program::{rent::Rent, system_instruction, sysvar::Sysvar}; use std::convert::From; use std::ops::Deref; -pub struct Neon<'a>(&'a AccountInfo<'a>); - -impl<'a> Neon<'a> { - pub fn from_account( - program_id: &Pubkey, - info: &'a AccountInfo<'a>, - ) -> Result { - if program_id != info.key { - return Err!(ProgramError::InvalidArgument; "Account {} - is not Neon program", info.key); - } - - Ok(Self(info)) - } -} - -impl<'a> Deref for Neon<'a> { - type Target = AccountInfo<'a>; - - fn deref(&self) -> &Self::Target { - self.0 - } -} - pub struct System<'a>(&'a AccountInfo<'a>); impl<'a> From<&System<'a>> for &'a AccountInfo<'a> { From 9b55e5eeda5339f99a6f5fb26750ba5484af566f Mon Sep 17 00:00:00 2001 From: Mick van Gelderen Date: Wed, 17 Jan 2024 11:37:04 +0100 Subject: [PATCH 086/318] NDEV-2505 Fix EXTHASHCODE (#253) * Fix EXTHASHCODE * NDEV-2505: Code review suggestions (#254) * Remove unused AccountStorage::code_hash method * Replace Buffer::buffer_is_empty with [T]::is_empty * Rename from_address to address (consistent with trait) * Rename buffer to code * Inline data_account_exists method * Remove TODOs * Reformat * Add test_keccak_hash_empty_slice * Add Buffer::is_empty tests * Use early return to simplify code flow * Move `Database` convenience functions to extension trait Added `DatabaseExt` which implements functions that can be implemented in terms of `Database`. * Update comments and naming * Add tests * Address comment * Refactor unit tests * Replace maybe_async::test with tokio::test The maybe_async::test predicate does not work with `cargo test-sbf` right now anyway. * Fix typo --------- Co-authored-by: Andrei Silviu Dragnea --- evm_loader/Cargo.lock | 1 + evm_loader/lib/src/account_storage.rs | 21 -- evm_loader/program/Cargo.toml | 3 + .../program/src/account_storage/backend.rs | 23 -- evm_loader/program/src/account_storage/mod.rs | 2 - evm_loader/program/src/evm/database.rs | 256 +++++++++++++++++- evm_loader/program/src/evm/opcode.rs | 5 +- evm_loader/program/src/executor/state.rs | 14 - 8 files changed, 262 insertions(+), 63 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index d0f3102cd..d9d6e2ae2 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -1890,6 +1890,7 @@ dependencies = [ "spl-token 3.5.0", "static_assertions", "thiserror", + "tokio", ] [[package]] diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index 0e2d3bfd8..e7172e3b4 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -623,27 +623,6 @@ impl AccountStorage for EmulatorAccountStorage<'_, T> { address.find_solana_address(self.program_id()) } - async fn code_hash(&self, address: Address, chain_id: u64) -> [u8; 32] { - use solana_sdk::keccak::hash; - - info!("code_hash {address} {chain_id}"); - - let code = self.code(address).await.to_vec(); - if !code.is_empty() { - return hash(&code).to_bytes(); - } - - // https://eips.ethereum.org/EIPS/eip-1052 - // https://eips.ethereum.org/EIPS/eip-161 - if (self.balance(address, chain_id).await == 0) - && (self.nonce(address, chain_id).await == 0) - { - return <[u8; 32]>::default(); - } - - hash(&[]).to_bytes() - } - async fn code_size(&self, address: Address) -> usize { info!("code_size {address}"); diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index b19e38ed4..52fa5da58 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -62,6 +62,9 @@ async-trait = { version = "0.1.73", optional = true } version = "0.2.7" features = ["is_sync"] +[dev-dependencies] +tokio = { version = "1.0", features = ["full"] } + [lib] crate-type = ["cdylib", "lib"] diff --git a/evm_loader/program/src/account_storage/backend.rs b/evm_loader/program/src/account_storage/backend.rs index c38deb846..7cbd6406a 100644 --- a/evm_loader/program/src/account_storage/backend.rs +++ b/evm_loader/program/src/account_storage/backend.rs @@ -73,29 +73,6 @@ impl<'a> AccountStorage for ProgramAccountStorage<'a> { .contract_with_bump_seed(self.program_id(), address) } - fn code_hash(&self, address: Address, chain_id: u64) -> [u8; 32] { - use solana_program::keccak; - - if let Ok(contract) = self.contract_account(address) { - keccak::hash(&contract.code()).to_bytes() - } else { - // https://eips.ethereum.org/EIPS/eip-1052 - // https://eips.ethereum.org/EIPS/eip-161 - if let Ok(account) = self.balance_account(address, chain_id) { - if account.nonce() > 0 || account.balance() > 0 { - // account without code - keccak::hash(&[]).to_bytes() - } else { - // non-existent account - <[u8; 32]>::default() - } - } else { - // non-existent account - <[u8; 32]>::default() - } - } - } - fn code_size(&self, address: Address) -> usize { self.contract_account(address).map_or(0, |a| a.code_len()) } diff --git a/evm_loader/program/src/account_storage/mod.rs b/evm_loader/program/src/account_storage/mod.rs index 5ad84fbdb..43489fe03 100644 --- a/evm_loader/program/src/account_storage/mod.rs +++ b/evm_loader/program/src/account_storage/mod.rs @@ -58,8 +58,6 @@ pub trait AccountStorage { /// Get contract solana address fn contract_pubkey(&self, address: Address) -> (Pubkey, u8); - /// Get code hash - async fn code_hash(&self, address: Address, chain_id: u64) -> [u8; 32]; /// Get code size async fn code_size(&self, address: Address) -> usize; /// Get code data diff --git a/evm_loader/program/src/evm/database.rs b/evm_loader/program/src/evm/database.rs index 803d0cff6..73ea18cde 100644 --- a/evm_loader/program/src/evm/database.rs +++ b/evm_loader/program/src/evm/database.rs @@ -21,8 +21,6 @@ pub trait Database { chain_id: u64, value: U256, ) -> Result<()>; - - async fn code_hash(&self, address: Address, chain_id: u64) -> Result<[u8; 32]>; async fn code_size(&self, address: Address) -> Result; async fn code(&self, address: Address) -> Result; fn set_code(&mut self, address: Address, chain_id: u64, code: Vec) -> Result<()>; @@ -51,3 +49,257 @@ pub trait Database { is_static: bool, ) -> Option>>; } + +/// Provides convenience methods that can be implemented in terms of `Database`. +#[maybe_async(?Send)] +pub trait DatabaseExt { + /// Returns whether an account exists and is non-empty as specified in + /// https://eips.ethereum.org/EIPS/eip-161. + async fn account_exists(&self, address: Address, chain_id: u64) -> Result; + + /// Returns the code hash for an address as specified in + /// https://eips.ethereum.org/EIPS/eip-1052. + async fn code_hash(&self, address: Address, chain_id: u64) -> Result<[u8; 32]>; +} + +#[maybe_async(?Send)] +impl DatabaseExt for T { + async fn account_exists(&self, address: Address, chain_id: u64) -> Result { + Ok(self.nonce(address, chain_id).await? > 0 || self.balance(address, chain_id).await? > 0) + } + + async fn code_hash(&self, address: Address, chain_id: u64) -> Result<[u8; 32]> { + // The function `Database::code` returns a zero-length buffer if the account exists with + // zero-length code, but also when the account does not exist. This makes it necessary to + // also check if the account exists when the returned buffer is empty. + // + // We could simplify the implementation by checking if the account exists first, but that + // would lead to more computation in what we think is the common case where the account + // exists and contains code. + let code = self.code(address).await?; + let bytes_to_hash: Option<&[u8]> = if !code.is_empty() { + Some(&*code) + } else if self.account_exists(address, chain_id).await? { + Some(&[]) + } else { + None + }; + + Ok(bytes_to_hash.map_or([0; 32], |bytes| { + solana_program::keccak::hash(bytes).to_bytes() + })) + } +} + +#[cfg(test)] +mod tests { + use std::collections::HashMap; + + use super::*; + + struct TestDatabaseEntry { + balance: U256, + nonce: u64, + code: Vec, + } + + impl TestDatabaseEntry { + fn empty() -> Self { + Self { + balance: U256::from(0u8), + nonce: 0, + code: Vec::default(), + } + } + + fn without_code() -> Self { + Self { + balance: U256::from(1u8), + nonce: 1, + code: Vec::default(), + } + } + + fn with_code(code: Vec) -> Self { + assert!(!code.is_empty()); + Self { + balance: U256::from_words(0, 1), + nonce: 1, + code, + } + } + } + + #[derive(Default)] + struct TestDatabase(HashMap); + + impl FromIterator<(Address, TestDatabaseEntry)> for TestDatabase { + fn from_iter>(iter: T) -> Self { + Self(iter.into_iter().collect()) + } + } + + #[maybe_async(?Send)] + #[allow(unused_variables)] + impl Database for TestDatabase { + fn default_chain_id(&self) -> u64 { + unimplemented!(); + } + + fn is_valid_chain_id(&self, chain_id: u64) -> bool { + unimplemented!(); + } + + async fn contract_chain_id(&self, address: Address) -> Result { + unimplemented!(); + } + + async fn nonce(&self, address: Address, chain_id: u64) -> Result { + Ok(self + .0 + .get(&address) + .map(|entry| entry.nonce) + .unwrap_or_default()) + } + + fn increment_nonce(&mut self, address: Address, chain_id: u64) -> Result<()> { + unimplemented!(); + } + + async fn balance(&self, address: Address, chain_id: u64) -> Result { + Ok(self + .0 + .get(&address) + .map(|entry| entry.balance) + .unwrap_or_default()) + } + + async fn transfer( + &mut self, + source: Address, + target: Address, + chain_id: u64, + value: U256, + ) -> Result<()> { + unimplemented!(); + } + + async fn code_size(&self, address: Address) -> Result { + unimplemented!(); + } + + async fn code(&self, address: Address) -> Result { + Ok(self + .0 + .get(&address) + .map(|entry| Buffer::from_slice(&entry.code)) + .unwrap_or_default()) + } + + fn set_code(&mut self, address: Address, chain_id: u64, code: Vec) -> Result<()> { + unimplemented!(); + } + + fn selfdestruct(&mut self, address: Address) -> Result<()> { + unimplemented!(); + } + + async fn storage(&self, address: Address, index: U256) -> Result<[u8; 32]> { + unimplemented!(); + } + + fn set_storage(&mut self, address: Address, index: U256, value: [u8; 32]) -> Result<()> { + unimplemented!(); + } + + async fn block_hash(&self, number: U256) -> Result<[u8; 32]> { + unimplemented!(); + } + + fn block_number(&self) -> Result { + unimplemented!(); + } + + fn block_timestamp(&self) -> Result { + unimplemented!(); + } + + async fn map_solana_account(&self, address: &Pubkey, action: F) -> R + where + F: FnOnce(&AccountInfo) -> R, + { + unimplemented!(); + } + + fn snapshot(&mut self) { + unimplemented!(); + } + + fn revert_snapshot(&mut self) { + unimplemented!(); + } + + fn commit_snapshot(&mut self) { + unimplemented!(); + } + + async fn precompile_extension( + &mut self, + context: &Context, + address: &Address, + data: &[u8], + is_static: bool, + ) -> Option>> { + unimplemented!(); + } + } + + #[maybe_async] + async fn code_hash(database_entry: Option) -> [u8; 32] { + let address = Address::default(); + let database: TestDatabase = database_entry + .map(|entry| (address, entry)) + .into_iter() + .collect(); + database + .code_hash(address, crate::config::DEFAULT_CHAIN_ID) + .await + .unwrap() + } + + #[tokio::test] + async fn code_hash_of_non_existing_account() { + let actual = code_hash(None).await; + assert_eq!(actual, [0; 32]); + } + + #[tokio::test] + async fn code_hash_of_empty_account() { + let actual = code_hash(Some(TestDatabaseEntry::empty())).await; + assert_eq!(actual, [0; 32]); + } + + #[tokio::test] + async fn code_hash_of_existing_account_without_code() { + let actual = code_hash(Some(TestDatabaseEntry::without_code())).await; + assert_eq!( + actual, + [ + 197, 210, 70, 1, 134, 247, 35, 60, 146, 126, 125, 178, 220, 199, 3, 192, 229, 0, + 182, 83, 202, 130, 39, 59, 123, 250, 216, 4, 93, 133, 164, 112, + ] + ); + } + + #[tokio::test] + async fn code_hash_of_existing_account_with_code() { + let actual = code_hash(Some(TestDatabaseEntry::with_code(vec![0; 10]))).await; + assert_eq!( + actual, + [ + 107, 210, 221, 107, 212, 8, 203, 238, 51, 66, 147, 88, 191, 36, 253, 198, 70, 18, + 251, 248, 177, 180, 219, 96, 69, 24, 244, 15, 253, 52, 182, 7 + ] + ); + } +} diff --git a/evm_loader/program/src/evm/opcode.rs b/evm_loader/program/src/evm/opcode.rs index acc9ed5dc..165111245 100644 --- a/evm_loader/program/src/evm/opcode.rs +++ b/evm_loader/program/src/evm/opcode.rs @@ -3,7 +3,10 @@ use ethnum::{I256, U256}; use maybe_async::maybe_async; use solana_program::log::sol_log_data; -use super::{database::Database, tracing_event, Context, Machine, Reason}; +use super::{ + database::{Database, DatabaseExt}, + tracing_event, Context, Machine, Reason, +}; use crate::{ error::{Error, Result}, evm::{trace_end_step, Buffer}, diff --git a/evm_loader/program/src/executor/state.rs b/evm_loader/program/src/executor/state.rs index bf30b232d..5a79b16a8 100644 --- a/evm_loader/program/src/executor/state.rs +++ b/evm_loader/program/src/executor/state.rs @@ -284,20 +284,6 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { Ok(self.backend.code_size(from_address).await) } - async fn code_hash(&self, from_address: Address, chain_id: u64) -> Result<[u8; 32]> { - use solana_program::keccak::hash; - - for action in &self.actions { - if let Action::EvmSetCode { address, code, .. } = action { - if &from_address == address { - return Ok(hash(code).to_bytes()); - } - } - } - - Ok(self.backend.code_hash(from_address, chain_id).await) - } - async fn code(&self, from_address: Address) -> Result { for action in &self.actions { if let Action::EvmSetCode { address, code, .. } = action { From 4236c916031f9e6385b831769a8539d552299df0 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 18 Jan 2024 00:10:01 +0700 Subject: [PATCH 087/318] update version to 1.9.0-dev --- evm_loader/Cargo.lock | 4 ++-- evm_loader/cli/Cargo.toml | 2 +- evm_loader/program/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index d9d6e2ae2..617fa3580 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -1866,7 +1866,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "evm-loader" -version = "1.7.0-dev" +version = "1.9.0-dev" dependencies = [ "arrayref", "async-trait", @@ -3127,7 +3127,7 @@ dependencies = [ [[package]] name = "neon-cli" -version = "1.7.0-dev" +version = "1.9.0-dev" dependencies = [ "build-info", "build-info-build", diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index d638202e8..593c1b94d 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "neon-cli" -version = "1.7.0-dev" +version = "1.9.0-dev" authors = ["NeonLabs Maintainers "] edition = "2021" diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 52fa5da58..a4996d6bf 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "evm-loader" -version = "1.7.0-dev" +version = "1.9.0-dev" description = "Neon EVM loader" authors = ["NeonLabs Maintainers "] edition = "2021" From ad4512f0fda1e6dd37d592b3c9fea3d606e86b63 Mon Sep 17 00:00:00 2001 From: Miroslav Nedelchev <45385208+mnedelchev-vn@users.noreply.github.com> Date: Wed, 24 Jan 2024 14:35:57 +0700 Subject: [PATCH 088/318] =?UTF-8?q?whitelist=20DeBank/=20Rabby=20partner?= =?UTF-8?q?=20to=20use=20local=20neon=20evm=20proxy=20with=20quic=E2=80=A6?= =?UTF-8?q?=20(#266)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add keys for Miro, DeBank/ Rabby and Alfie for devnet WL --- evm_loader/program/config/testnet.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/evm_loader/program/config/testnet.toml b/evm_loader/program/config/testnet.toml index 8ea5d890e..8e22e1371 100644 --- a/evm_loader/program/config/testnet.toml +++ b/evm_loader/program/config/testnet.toml @@ -229,6 +229,9 @@ operators_whitelist = [ "AuikYUkrP9bRCxPq99YpEkFCgWLS9KM2oe3sCPkTCEwr", "AyEE2tf4AezMxtBYXoWgoK1PwMDMsPfDahQRtZvU8BLc", "B5Gefd2yR3nBi4eFDtp3grmVsRq6sw4UYmGVZG6vrda3", + "7P1VpfLJNo1rMJbHmz2P6U34ygkRM5UNogknFUXP2b1k", + "8HzCjhBNP3rs7SydUrZAiQGEoqXHNtpNPE475zzHmzba", + "CRJ7MFYvMjXysVDkifFmiS8jmpDMS5qZRwyu3EN3Rfav", ] [chain.neon] From b730019f9489381f4d9f4de3dceab515af957ccf Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Fri, 16 Feb 2024 13:36:53 +0200 Subject: [PATCH 089/318] NDEV-2620: Add executor_state: &impl Database parameter to EventListener::event method (#273) * NDEV-2620: Add executor_state: &impl Database parameter to EventListener::event method * NDEV-2620: Extract Tracer trait from EventListener trait * NDEV-2620: Move Tracer trait to neon-lib crate --- .../api/src/api_server/handlers/emulate.rs | 13 ++- evm_loader/cli/src/main.rs | 5 +- evm_loader/lib/Cargo.toml | 2 +- evm_loader/lib/src/commands/emulate.rs | 57 +++++------ evm_loader/lib/src/commands/trace.rs | 11 +-- evm_loader/lib/src/tracing/tracers/mod.rs | 52 +++++++--- .../lib/src/tracing/tracers/struct_logger.rs | 8 +- evm_loader/program/Cargo.toml | 2 +- evm_loader/program/src/evm/mod.rs | 97 +++++++++---------- evm_loader/program/src/evm/opcode.rs | 32 ++++-- evm_loader/program/src/evm/opcode_table.rs | 11 ++- evm_loader/program/src/evm/precompile/mod.rs | 3 +- evm_loader/program/src/evm/tracing.rs | 19 ++-- .../src/instruction/transaction_execute.rs | 5 +- .../src/instruction/transaction_step.rs | 9 +- 15 files changed, 186 insertions(+), 140 deletions(-) diff --git a/evm_loader/api/src/api_server/handlers/emulate.rs b/evm_loader/api/src/api_server/handlers/emulate.rs index 6d5015e15..cbb03472a 100644 --- a/evm_loader/api/src/api_server/handlers/emulate.rs +++ b/evm_loader/api/src/api_server/handlers/emulate.rs @@ -1,5 +1,6 @@ use actix_request_identifier::RequestId; use actix_web::{http::StatusCode, post, web::Json, Responder}; +use neon_lib::tracing::tracers::TracerTypeEnum; use std::convert::Into; use tracing::info; @@ -26,8 +27,14 @@ pub async fn emulate( }; process_result( - &EmulateCommand::execute(&rpc, state.config.evm_loader, emulate_request.body, None) - .await - .map_err(Into::into), + &EmulateCommand::execute( + &rpc, + state.config.evm_loader, + emulate_request.body, + None::, + ) + .await + .map(|(response, _)| response) + .map_err(Into::into), ) } diff --git a/evm_loader/cli/src/main.rs b/evm_loader/cli/src/main.rs index edcab4691..36d6b16d7 100644 --- a/evm_loader/cli/src/main.rs +++ b/evm_loader/cli/src/main.rs @@ -29,6 +29,7 @@ use crate::build_info::get_build_info; use evm_loader::types::Address; use neon_lib::errors::NeonError; use neon_lib::rpc::{CallDbClient, RpcEnum}; +use neon_lib::tracing::tracers::TracerTypeEnum; use neon_lib::types::TracerDb; use solana_clap_utils::keypair::signer_from_path; use solana_sdk::signature::Signer; @@ -44,9 +45,9 @@ async fn run(options: &ArgMatches<'_>) -> NeonCliResult { let rpc = build_rpc(options, config).await?; let request = read_tx_from_stdin()?; - emulate::execute(&rpc, config.evm_loader, request, None) + emulate::execute(&rpc, config.evm_loader, request, None::) .await - .map(|result| json!(result)) + .map(|(result, _)| json!(result)) } ("trace", Some(_)) => { let rpc = build_rpc(options, config).await?; diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 7ecba68df..df35d7614 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" thiserror = "1.0" anyhow = "1.0" bincode = "1.3.1" -evm-loader = { path = "../program", default-features = false, features = ["log", "async-trait", "serde_json"] } +evm-loader = { path = "../program", default-features = false, features = ["log", "async-trait"] } solana-sdk = "=1.16.23" solana-client = "=1.16.23" solana-clap-utils = "=1.16.23" diff --git a/evm_loader/lib/src/commands/emulate.rs b/evm_loader/lib/src/commands/emulate.rs index 0271b6248..05de4cd0c 100644 --- a/evm_loader/lib/src/commands/emulate.rs +++ b/evm_loader/lib/src/commands/emulate.rs @@ -2,19 +2,20 @@ use evm_loader::account::ContractAccount; use evm_loader::error::build_revert_message; use log::{debug, info}; use serde::{Deserialize, Serialize}; +use serde_json::Value; use solana_sdk::entrypoint::MAX_PERMITTED_DATA_INCREASE; use solana_sdk::pubkey::Pubkey; use crate::commands::get_config::BuildConfigSimulator; use crate::rpc::Rpc; use crate::syscall_stubs::setup_emulator_syscall_stubs; +use crate::tracing::tracers::Tracer; use crate::types::{EmulateRequest, TxParams}; use crate::{ account_storage::{EmulatorAccountStorage, SolanaAccount}, errors::NeonError, NeonResult, }; -use evm_loader::evm::tracing::TracerType; use evm_loader::{ config::{EVM_STEPS_MIN, PAYMENT_TO_TREASURE}, evm::{ExitStatus, Machine}, @@ -50,12 +51,12 @@ impl EmulateResponse { } } -pub async fn execute( +pub async fn execute( rpc: &(impl Rpc + BuildConfigSimulator), program_id: Pubkey, emulate_request: EmulateRequest, - tracer: Option, -) -> NeonResult { + tracer: Option, +) -> NeonResult<(EmulateResponse, Option)> { let block_overrides = emulate_request .trace_config .as_ref() @@ -81,12 +82,12 @@ pub async fn execute( emulate_trx(emulate_request.tx, &mut storage, step_limit, tracer).await } -async fn emulate_trx( +async fn emulate_trx( tx_params: TxParams, storage: &mut EmulatorAccountStorage<'_, impl Rpc>, step_limit: u64, - tracer: Option, -) -> NeonResult { + tracer: Option, +) -> NeonResult<(EmulateResponse, Option)> { info!("tx_params: {:?}", tx_params); let (origin, tx) = tx_params.into_transaction(storage).await; @@ -94,21 +95,18 @@ async fn emulate_trx( info!("origin: {:?}", origin); info!("tx: {:?}", tx); - let (exit_status, actions, steps_executed) = { - let mut backend = ExecutorState::new(storage); - let mut evm = match Machine::new(tx, origin, &mut backend, tracer).await { - Ok(evm) => evm, - Err(e) => return Ok(EmulateResponse::revert(e)), - }; + let mut backend = ExecutorState::new(storage); + let mut evm = match Machine::new(tx, origin, &mut backend, tracer).await { + Ok(evm) => evm, + Err(e) => return Ok((EmulateResponse::revert(e), None)), + }; - let (result, steps_executed) = evm.execute(step_limit, &mut backend).await?; - if result == ExitStatus::StepLimit { - return Err(NeonError::TooManySteps); - } + let (exit_status, steps_executed, tracer) = evm.execute(step_limit, &mut backend).await?; + if exit_status == ExitStatus::StepLimit { + return Err(NeonError::TooManySteps); + } - let actions = backend.into_actions(); - (result, actions, steps_executed) - }; + let actions = backend.into_actions(); storage.apply_actions(actions.clone()).await?; storage.mark_legacy_accounts().await?; @@ -128,14 +126,17 @@ async fn emulate_trx( let solana_accounts = storage.accounts.borrow().values().cloned().collect(); - Ok(EmulateResponse { - exit_status: exit_status.to_string(), - steps_executed, - used_gas, - solana_accounts, - result: exit_status.into_result().unwrap_or_default(), - iterations, - }) + Ok(( + EmulateResponse { + exit_status: exit_status.to_string(), + steps_executed, + used_gas, + solana_accounts, + result: exit_status.into_result().unwrap_or_default(), + iterations, + }, + tracer.map(|tracer| tracer.into_traces()), + )) } fn realloc_iterations(actions: &[Action]) -> u64 { diff --git a/evm_loader/lib/src/commands/trace.rs b/evm_loader/lib/src/commands/trace.rs index b6f8251fb..96fdc5c97 100644 --- a/evm_loader/lib/src/commands/trace.rs +++ b/evm_loader/lib/src/commands/trace.rs @@ -1,5 +1,3 @@ -use std::rc::Rc; - use serde_json::Value; use solana_sdk::pubkey::Pubkey; @@ -22,13 +20,10 @@ pub async fn trace_transaction( let tracer = new_tracer(&trace_config)?; - let emulation_tracer = Some(Rc::clone(&tracer)); - let r = super::emulate::execute(rpc, program_id, emulate_request, emulation_tracer).await?; + let (r, traces) = + super::emulate::execute(rpc, program_id, emulate_request, Some(tracer)).await?; - let mut traces = Rc::try_unwrap(tracer) - .expect("There is must be only one reference") - .into_inner() - .into_traces(); + let mut traces = traces.expect("traces should not be None"); traces["gas"] = r.used_gas.into(); Ok(traces) diff --git a/evm_loader/lib/src/tracing/tracers/mod.rs b/evm_loader/lib/src/tracing/tracers/mod.rs index e0dd86756..0f54f6391 100644 --- a/evm_loader/lib/src/tracing/tracers/mod.rs +++ b/evm_loader/lib/src/tracing/tracers/mod.rs @@ -1,21 +1,45 @@ use crate::tracing::tracers::struct_logger::StructLogger; use crate::tracing::TraceConfig; -use evm_loader::evm::tracing::TracerType; -use std::cell::RefCell; -use std::rc::Rc; +use evm_loader::evm::database::Database; +use evm_loader::evm::tracing::{Event, EventListener}; +use serde_json::Value; pub mod struct_logger; -pub fn new_tracer(trace_config: &TraceConfig) -> evm_loader::error::Result { - Ok(Rc::new(RefCell::new( - match trace_config.tracer.as_deref() { - None | Some("") => Box::new(StructLogger::new(trace_config)), - _ => { - return Err(evm_loader::error::Error::Custom(format!( - "Unsupported tracer: {:?}", - trace_config.tracer - ))) +pub enum TracerTypeEnum { + StructLogger(StructLogger), +} + +impl EventListener for TracerTypeEnum { + fn event(&mut self, executor_state: &impl Database, event: Event) { + match self { + TracerTypeEnum::StructLogger(struct_logger) => { + struct_logger.event(executor_state, event) } - }, - ))) + } + } +} + +pub trait Tracer: EventListener { + fn into_traces(self) -> Value; +} + +impl Tracer for TracerTypeEnum { + fn into_traces(self) -> Value { + match self { + TracerTypeEnum::StructLogger(struct_logger) => struct_logger.into_traces(), + } + } +} + +pub fn new_tracer(trace_config: &TraceConfig) -> evm_loader::error::Result { + match trace_config.tracer.as_deref() { + None | Some("") => Ok(TracerTypeEnum::StructLogger(StructLogger::new( + trace_config, + ))), + _ => Err(evm_loader::error::Error::Custom(format!( + "Unsupported tracer: {:?}", + trace_config.tracer + ))), + } } diff --git a/evm_loader/lib/src/tracing/tracers/struct_logger.rs b/evm_loader/lib/src/tracing/tracers/struct_logger.rs index a842557f6..e8d23c922 100644 --- a/evm_loader/lib/src/tracing/tracers/struct_logger.rs +++ b/evm_loader/lib/src/tracing/tracers/struct_logger.rs @@ -1,11 +1,13 @@ use std::collections::BTreeMap; use ethnum::U256; +use evm_loader::evm::database::Database; use evm_loader::evm::ExitStatus; use serde::Serialize; use serde_json::Value; use web3::types::Bytes; +use crate::tracing::tracers::Tracer; use crate::tracing::TraceConfig; use evm_loader::evm::opcode_table::OPNAMES; use evm_loader::evm::tracing::{Event, EventListener}; @@ -138,7 +140,7 @@ impl StructLogger { } impl EventListener for StructLogger { - fn event(&mut self, event: Event) { + fn event(&mut self, _executor_state: &impl Database, event: Event) { match event { Event::BeginVM { .. } => { self.depth += 1; @@ -203,8 +205,10 @@ impl EventListener for StructLogger { } }; } +} - fn into_traces(self: Box) -> Value { +impl Tracer for StructLogger { + fn into_traces(self) -> Value { let exit_status = self.exit_status.expect("Emulation is not completed"); let result = StructLoggerResult { gas: 0, diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index a4996d6bf..2cb4e8486 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -51,7 +51,6 @@ borsh = "0.9" bincode = "1" serde_bytes = "0.11.12" serde = { version = "1.0.186", default-features = false, features = ["derive", "rc"] } -serde_json = { version = "1.0.107", features = ["preserve_order"], optional = true } ethnum = { version = "1.4", default-features = false, features = ["serde"] } cfg-if = { version = "1.0" } log = { version = "0.4", default-features = false, optional = true } @@ -64,6 +63,7 @@ features = ["is_sync"] [dev-dependencies] tokio = { version = "1.0", features = ["full"] } +serde_json = { version = "1.0.107", features = ["preserve_order"] } [lib] crate-type = ["cdylib", "lib"] diff --git a/evm_loader/program/src/evm/mod.rs b/evm_loader/program/src/evm/mod.rs index f84010139..8ac20e696 100644 --- a/evm_loader/program/src/evm/mod.rs +++ b/evm_loader/program/src/evm/mod.rs @@ -11,8 +11,9 @@ use solana_program::log::sol_log_data; pub use buffer::Buffer; -#[cfg(not(target_os = "solana"))] -use crate::evm::tracing::TracerTypeOpt; +use crate::evm::tracing::EventListener; +#[cfg(target_os = "solana")] +use crate::evm::tracing::NoopEventListener; use crate::{ error::{build_revert_message, Error, Result}, evm::{opcode::Action, precompile::is_precompile_address}, @@ -28,43 +29,43 @@ mod opcode; pub mod opcode_table; mod precompile; mod stack; -#[cfg(not(target_os = "solana"))] pub mod tracing; mod utils; macro_rules! tracing_event { - ($self:ident, $x:expr) => { + ($self:ident, $backend:ident, $x:expr) => { #[cfg(not(target_os = "solana"))] - if let Some(tracer) = &$self.tracer { - tracer.borrow_mut().event($x); + if let Some(tracer) = &mut $self.tracer { + tracer.event($backend, $x); } }; - ($self:ident, $condition:expr, $x:expr) => { + ($self:ident, $backend:ident, $condition:expr, $x:expr) => { #[cfg(not(target_os = "solana"))] - if let Some(tracer) = &$self.tracer { + if let Some(tracer) = &mut $self.tracer { if $condition { - tracer.borrow_mut().event($x); + tracer.event($backend, $x); } } }; } macro_rules! trace_end_step { - ($self:ident, $return_data:expr) => { + ($self:ident, $backend:ident, $return_data:expr) => { #[cfg(not(target_os = "solana"))] - if let Some(tracer) = &$self.tracer { - tracer - .borrow_mut() - .event(crate::evm::tracing::Event::EndStep { + if let Some(tracer) = &mut $self.tracer { + tracer.event( + $backend, + crate::evm::tracing::Event::EndStep { gas_used: 0_u64, return_data: $return_data, - }) + }, + ) } }; - ($self:ident, $condition:expr; $return_data_getter:expr) => { + ($self:ident, $backend:ident, $condition:expr; $return_data_getter:expr) => { #[cfg(not(target_os = "solana"))] if $condition { - trace_end_step!($self, $return_data_getter) + trace_end_step!($self, $backend, $return_data_getter) } }; } @@ -134,7 +135,7 @@ pub struct Context { #[derive(Serialize, Deserialize)] #[serde(bound = "B: Database")] -pub struct Machine { +pub struct Machine { origin: Address, chain_id: u64, context: Context, @@ -161,12 +162,12 @@ pub struct Machine { #[serde(skip)] phantom: PhantomData<*const B>, - #[cfg(not(target_os = "solana"))] #[serde(skip)] - tracer: TracerTypeOpt, + tracer: Option, } -impl Machine { +#[cfg(target_os = "solana")] +impl Machine { pub fn serialize_into(&self, buffer: &mut [u8]) -> Result { let mut cursor = std::io::Cursor::new(buffer); @@ -175,7 +176,6 @@ impl Machine { cursor.position().try_into().map_err(Error::from) } - #[cfg(target_os = "solana")] pub fn deserialize_from(buffer: &[u8], backend: &B) -> Result { fn reinit_buffer(buffer: &mut Buffer, backend: &B) { if let Some((key, range)) = buffer.uninit_data() { @@ -184,7 +184,10 @@ impl Machine { } } - fn reinit_machine(mut machine: &mut Machine, backend: &B) { + fn reinit_machine( + mut machine: &mut Machine, + backend: &B, + ) { loop { reinit_buffer(&mut machine.call_data, backend); reinit_buffer(&mut machine.execution_code, backend); @@ -202,13 +205,15 @@ impl Machine { Ok(evm) } +} +impl Machine { #[maybe_async] pub async fn new( trx: Transaction, origin: Address, backend: &mut B, - #[cfg(not(target_os = "solana"))] tracer: TracerTypeOpt, + tracer: Option, ) -> Result { let trx_chain_id = trx.chain_id().unwrap_or_else(|| backend.default_chain_id()); @@ -241,25 +246,9 @@ impl Machine { // } if trx.target().is_some() { - Self::new_call( - trx_chain_id, - trx, - origin, - backend, - #[cfg(not(target_os = "solana"))] - tracer, - ) - .await + Self::new_call(trx_chain_id, trx, origin, backend, tracer).await } else { - Self::new_create( - trx_chain_id, - trx, - origin, - backend, - #[cfg(not(target_os = "solana"))] - tracer, - ) - .await + Self::new_create(trx_chain_id, trx, origin, backend, tracer).await } } @@ -269,7 +258,7 @@ impl Machine { trx: Transaction, origin: Address, backend: &mut B, - #[cfg(not(target_os = "solana"))] tracer: TracerTypeOpt, + tracer: Option, ) -> Result { assert!(trx.target().is_some()); @@ -308,7 +297,6 @@ impl Machine { reason: Reason::Call, parent: None, phantom: PhantomData, - #[cfg(not(target_os = "solana"))] tracer, }) } @@ -319,7 +307,7 @@ impl Machine { trx: Transaction, origin: Address, backend: &mut B, - #[cfg(not(target_os = "solana"))] tracer: TracerTypeOpt, + tracer: Option, ) -> Result { assert!(trx.target().is_none()); @@ -362,13 +350,16 @@ impl Machine { call_data: Buffer::empty(), parent: None, phantom: PhantomData, - #[cfg(not(target_os = "solana"))] tracer, }) } #[maybe_async] - pub async fn execute(&mut self, step_limit: u64, backend: &mut B) -> Result<(ExitStatus, u64)> { + pub async fn execute( + &mut self, + step_limit: u64, + backend: &mut B, + ) -> Result<(ExitStatus, u64, Option)> { assert!(self.execution_code.is_initialized()); assert!(self.call_data.is_initialized()); assert!(self.return_data.is_initialized()); @@ -377,6 +368,7 @@ impl Machine { tracing_event!( self, + backend, tracing::Event::BeginVM { context: self.context, code: self.execution_code.to_vec() @@ -399,6 +391,7 @@ impl Machine { tracing_event!( self, + backend, tracing::Event::BeginStep { opcode, pc: self.pc, @@ -415,7 +408,7 @@ impl Machine { } }; - trace_end_step!(self, opcode_result != Action::Noop; match &opcode_result { + trace_end_step!(self, backend, opcode_result != Action::Noop; match &opcode_result { Action::Return(value) | Action::Revert(value) => Some(value.clone()), _ => None, }); @@ -434,12 +427,13 @@ impl Machine { tracing_event!( self, + backend, tracing::Event::EndVM { status: status.clone() } ); - Ok((status, step)) + Ok((status, step, self.tracer.take())) } fn fork( @@ -468,8 +462,7 @@ impl Machine { reason, parent: None, phantom: PhantomData, - #[cfg(not(target_os = "solana"))] - tracer: self.tracer.clone(), + tracer: self.tracer.take(), }; core::mem::swap(self, &mut other); @@ -482,6 +475,8 @@ impl Machine { let mut other = *self.parent.take().unwrap(); core::mem::swap(self, &mut other); + self.tracer = other.tracer.take(); + other } } diff --git a/evm_loader/program/src/evm/opcode.rs b/evm_loader/program/src/evm/opcode.rs index 165111245..d1d42d2df 100644 --- a/evm_loader/program/src/evm/opcode.rs +++ b/evm_loader/program/src/evm/opcode.rs @@ -7,6 +7,7 @@ use super::{ database::{Database, DatabaseExt}, tracing_event, Context, Machine, Reason, }; +use crate::evm::tracing::EventListener; use crate::{ error::{Error, Result}, evm::{trace_end_step, Buffer}, @@ -25,7 +26,7 @@ pub enum Action { } #[allow(clippy::unused_async)] -impl Machine { +impl Machine { /// Unknown instruction #[maybe_async] pub async fn opcode_unknown(&mut self, _backend: &mut B) -> Result { @@ -799,7 +800,11 @@ impl Machine { let index = self.stack.pop_u256()?; let value = backend.storage(self.context.contract, index).await?; - tracing_event!(self, super::tracing::Event::StorageAccess { index, value }); + tracing_event!( + self, + backend, + super::tracing::Event::StorageAccess { index, value } + ); self.stack.push_array(&value)?; @@ -816,7 +821,11 @@ impl Machine { let index = self.stack.pop_u256()?; let value = *self.stack.pop_array()?; - tracing_event!(self, super::tracing::Event::StorageAccess { index, value }); + tracing_event!( + self, + backend, + super::tracing::Event::StorageAccess { index, value } + ); backend.set_storage(self.context.contract, index, value)?; @@ -1073,6 +1082,7 @@ impl Machine { tracing_event!( self, + backend, super::tracing::Event::BeginVM { context, code: init_code.to_vec() @@ -1133,6 +1143,7 @@ impl Machine { tracing_event!( self, + backend, super::tracing::Event::BeginVM { context, code: code.to_vec() @@ -1188,6 +1199,7 @@ impl Machine { tracing_event!( self, + backend, super::tracing::Event::BeginVM { context, code: code.to_vec() @@ -1241,6 +1253,7 @@ impl Machine { tracing_event!( self, + backend, super::tracing::Event::BeginVM { context, code: code.to_vec() @@ -1290,6 +1303,7 @@ impl Machine { tracing_event!( self, + backend, super::tracing::Event::BeginVM { context, code: code.to_vec() @@ -1367,9 +1381,10 @@ impl Machine { return Ok(Action::Return(return_data)); } - trace_end_step!(self, Some(return_data.clone())); + trace_end_step!(self, backend, Some(return_data.clone())); tracing_event!( self, + backend, super::tracing::Event::EndVM { status: super::ExitStatus::Return(return_data.clone()) } @@ -1416,9 +1431,10 @@ impl Machine { return Ok(Action::Revert(return_data)); } - trace_end_step!(self, Some(return_data.clone())); + trace_end_step!(self, backend, Some(return_data.clone())); tracing_event!( self, + backend, super::tracing::Event::EndVM { status: super::ExitStatus::Revert(return_data.clone()) } @@ -1472,9 +1488,10 @@ impl Machine { return Ok(Action::Suicide); } - trace_end_step!(self, None); + trace_end_step!(self, backend, None); tracing_event!( self, + backend, super::tracing::Event::EndVM { status: super::ExitStatus::Suicide } @@ -1504,9 +1521,10 @@ impl Machine { return Ok(Action::Stop); } - trace_end_step!(self, None); + trace_end_step!(self, backend, None); tracing_event!( self, + backend, super::tracing::Event::EndVM { status: super::ExitStatus::Stop } diff --git a/evm_loader/program/src/evm/opcode_table.rs b/evm_loader/program/src/evm/opcode_table.rs index cc169efc2..2f954da47 100644 --- a/evm_loader/program/src/evm/opcode_table.rs +++ b/evm_loader/program/src/evm/opcode_table.rs @@ -1,16 +1,17 @@ use crate::error::Result; +use crate::evm::tracing::EventListener; use super::{database::Database, opcode::Action, Machine}; macro_rules! opcode_table { ($( $opcode:literal, $opname:literal, $op:path;)*) => { #[cfg(target_os = "solana")] - type OpCode = fn(&mut Machine, &mut B) -> Result; + type OpCode = fn(&mut Machine, &mut B) -> Result; #[cfg(target_os = "solana")] - impl Machine { - const OPCODES: [OpCode; 256] = { - let mut opcodes: [OpCode; 256] = [Self::opcode_unknown; 256]; + impl Machine { + const OPCODES: [OpCode; 256] = { + let mut opcodes: [OpCode; 256] = [Self::opcode_unknown; 256]; $(opcodes[$opcode as usize] = $op;)* @@ -25,7 +26,7 @@ macro_rules! opcode_table { } #[cfg(not(target_os = "solana"))] - impl Machine { + impl Machine { pub async fn execute_opcode(&mut self, backend: &mut B, opcode: u8) -> Result { match opcode { $($opcode => $op(self, backend).await,)* diff --git a/evm_loader/program/src/evm/precompile/mod.rs b/evm_loader/program/src/evm/precompile/mod.rs index 16bb5666c..c22b65a8b 100644 --- a/evm_loader/program/src/evm/precompile/mod.rs +++ b/evm_loader/program/src/evm/precompile/mod.rs @@ -1,3 +1,4 @@ +use crate::evm::tracing::EventListener; use crate::evm::{database::Database, Machine}; use crate::types::Address; @@ -56,7 +57,7 @@ pub fn is_precompile_address(address: &Address) -> bool { || *address == SYSTEM_ACCOUNT_BLAKE2F } -impl Machine { +impl Machine { #[must_use] pub fn precompile(address: &Address, data: &[u8]) -> Option> { match *address { diff --git a/evm_loader/program/src/evm/tracing.rs b/evm_loader/program/src/evm/tracing.rs index d9386f6ee..8f7776206 100644 --- a/evm_loader/program/src/evm/tracing.rs +++ b/evm_loader/program/src/evm/tracing.rs @@ -1,19 +1,16 @@ -use std::cell::RefCell; -use std::fmt::Debug; -use std::rc::Rc; - +use super::{Context, ExitStatus}; +use crate::evm::database::Database; use ethnum::U256; -use serde_json::Value; -use super::{Context, ExitStatus}; +pub struct NoopEventListener; -pub trait EventListener: Debug { - fn event(&mut self, event: Event); - fn into_traces(self: Box) -> Value; +pub trait EventListener { + fn event(&mut self, executor_state: &impl Database, event: Event); } -pub type TracerType = Rc>>; -pub type TracerTypeOpt = Option; +impl EventListener for NoopEventListener { + fn event(&mut self, _executor_state: &impl Database, _event: Event) {} +} /// Trace event pub enum Event { diff --git a/evm_loader/program/src/instruction/transaction_execute.rs b/evm_loader/program/src/instruction/transaction_execute.rs index 9c27de786..a55800d5b 100644 --- a/evm_loader/program/src/instruction/transaction_execute.rs +++ b/evm_loader/program/src/instruction/transaction_execute.rs @@ -3,6 +3,7 @@ use solana_program::pubkey::Pubkey; use crate::account::{AccountsDB, AllocateResult}; use crate::account_storage::ProgramAccountStorage; use crate::error::{Error, Result}; +use crate::evm::tracing::NoopEventListener; use crate::evm::Machine; use crate::executor::ExecutorState; use crate::gasometer::Gasometer; @@ -38,8 +39,8 @@ pub fn execute( let (exit_reason, apply_state) = { let mut backend = ExecutorState::new(&account_storage); - let mut evm = Machine::new(trx, origin, &mut backend)?; - let (result, _) = evm.execute(u64::MAX, &mut backend)?; + let mut evm = Machine::new(trx, origin, &mut backend, None::)?; + let (result, _, _) = evm.execute(u64::MAX, &mut backend)?; let actions = backend.into_actions(); diff --git a/evm_loader/program/src/instruction/transaction_step.rs b/evm_loader/program/src/instruction/transaction_step.rs index c8b20a3af..f6ba7d642 100644 --- a/evm_loader/program/src/instruction/transaction_step.rs +++ b/evm_loader/program/src/instruction/transaction_step.rs @@ -2,13 +2,14 @@ use crate::account::{AccountsDB, AllocateResult, StateAccount}; use crate::account_storage::{AccountStorage, ProgramAccountStorage}; use crate::config::{EVM_STEPS_LAST_ITERATION_MAX, EVM_STEPS_MIN}; use crate::error::{Error, Result}; +use crate::evm::tracing::NoopEventListener; use crate::evm::{ExitStatus, Machine}; use crate::executor::{Action, ExecutorState}; use crate::gasometer::Gasometer; use crate::types::{Address, Transaction}; type EvmBackend<'a, 'r> = ExecutorState<'r, ProgramAccountStorage<'a>>; -type Evm<'a, 'r> = Machine>; +type Evm<'a, 'r> = Machine, NoopEventListener>; pub fn do_begin<'a>( accounts: AccountsDB<'a>, @@ -22,7 +23,7 @@ pub fn do_begin<'a>( let accounts = ProgramAccountStorage::new(accounts)?; let mut backend = ExecutorState::new(&accounts); - let evm = Machine::new(trx, origin, &mut backend)?; + let evm = Machine::new(trx, origin, &mut backend, None::)?; // Burn `gas_limit` tokens from the origin account // Later we will mint them to the operator @@ -50,9 +51,9 @@ pub fn do_continue<'a>( let account_storage = ProgramAccountStorage::new(accounts)?; let (mut backend, mut evm) = deserialize_evm_state(&storage, &account_storage)?; - let (result, steps_executed) = { + let (result, steps_executed, _) = { match backend.exit_status() { - Some(status) => (status.clone(), 0_u64), + Some(status) => (status.clone(), 0_u64, None), None => evm.execute(step_count, &mut backend)?, } }; From ce759a5e67c2c69c7b0842748869b2836a1c834e Mon Sep 17 00:00:00 2001 From: s-medvedev <40623263+s-medvedev@users.noreply.github.com> Date: Tue, 20 Feb 2024 19:50:18 +0700 Subject: [PATCH 090/318] NDEV-2651 Remove syscall_stabs (#279) * NDEV-2651 Remove syscall_stabs --------- Co-authored-by: Semen Medvedev --- evm_loader/lib/src/account_storage.rs | 42 +++++++++---- evm_loader/lib/src/commands/emulate.rs | 2 - evm_loader/lib/src/lib.rs | 2 +- evm_loader/lib/src/syscall_stubs.rs | 60 ------------------- .../program/src/account/ether_balance.rs | 4 +- .../program/src/account/ether_contract.rs | 2 +- .../program/src/account/ether_storage.rs | 4 +- evm_loader/program/src/account/legacy/mod.rs | 16 +++-- evm_loader/program/src/account/program.rs | 7 ++- .../program/src/account_storage/apply.rs | 13 ++-- .../program/src/account_storage/backend.rs | 10 +++- .../program/src/account_storage/base.rs | 13 ++-- evm_loader/program/src/account_storage/mod.rs | 8 +++ evm_loader/program/src/debug.rs | 31 ++++++++++ evm_loader/program/src/entrypoint.rs | 2 +- evm_loader/program/src/error.rs | 10 ++-- evm_loader/program/src/evm/database.rs | 12 +++- evm_loader/program/src/evm/mod.rs | 6 +- evm_loader/program/src/evm/opcode.rs | 30 +++++----- .../executor/precompile_extension/metaplex.rs | 10 +--- .../precompile_extension/neon_token.rs | 10 ++-- .../precompile_extension/spl_token.rs | 20 ++----- evm_loader/program/src/executor/state.rs | 17 +++++- .../program/src/external_programs/metaplex.rs | 12 ++-- .../external_programs/spl_associated_token.rs | 5 +- .../src/instruction/account_block_add.rs | 2 +- .../src/instruction/account_create_balance.rs | 9 +-- .../src/instruction/account_holder_create.rs | 2 +- .../src/instruction/account_holder_delete.rs | 2 +- .../src/instruction/account_holder_write.rs | 5 +- .../src/instruction/collect_treasury.rs | 2 +- .../src/instruction/config_get_chain_count.rs | 2 +- .../src/instruction/config_get_chain_info.rs | 2 +- .../src/instruction/config_get_environment.rs | 2 +- .../config_get_property_by_index.rs | 2 +- .../config_get_property_by_name.rs | 2 +- .../instruction/config_get_property_count.rs | 2 +- .../src/instruction/config_get_status.rs | 2 +- .../src/instruction/config_get_version.rs | 2 +- .../src/instruction/create_main_treasury.rs | 6 +- .../src/instruction/neon_tokens_deposit.rs | 8 ++- .../src/instruction/transaction_cancel.rs | 9 +-- .../src/instruction/transaction_execute.rs | 3 +- .../transaction_execute_from_account.rs | 7 ++- .../transaction_execute_from_instruction.rs | 7 ++- .../src/instruction/transaction_step.rs | 9 ++- .../transaction_step_from_account.rs | 12 ++-- ...ransaction_step_from_account_no_chainid.rs | 2 +- .../transaction_step_from_instruction.rs | 11 ++-- 49 files changed, 247 insertions(+), 213 deletions(-) delete mode 100644 evm_loader/lib/src/syscall_stubs.rs diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index e7172e3b4..eaa6ed55a 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -8,7 +8,7 @@ use evm_loader::account_storage::find_slot_hash; use evm_loader::types::Address; use solana_sdk::rent::Rent; use solana_sdk::system_program; -use solana_sdk::sysvar::{slot_hashes, Sysvar}; +use solana_sdk::sysvar::slot_hashes; use std::collections::HashSet; use std::{cell::RefCell, collections::HashMap, convert::TryInto, rc::Rc}; @@ -51,6 +51,7 @@ pub struct EmulatorAccountStorage<'rpc, T: Rpc> { chains: Vec, block_number: u64, block_timestamp: i64, + rent: Rent, state_overrides: Option, } @@ -79,6 +80,14 @@ impl<'rpc, T: Rpc + BuildConfigSimulator> EmulatorAccountStorage<'rpc, T> { Some(chains) => chains, }; + let rent_account = rpc + .get_account(&solana_sdk::sysvar::rent::id()) + .await? + .value + .ok_or(NeonError::AccountNotFound(solana_sdk::sysvar::rent::id()))?; + let rent = bincode::deserialize::(&rent_account.data)?; + info!("Rent: {rent:?}"); + Ok(Self { accounts: RefCell::new(HashMap::new()), program_id, @@ -88,6 +97,7 @@ impl<'rpc, T: Rpc + BuildConfigSimulator> EmulatorAccountStorage<'rpc, T> { block_number, block_timestamp, state_overrides, + rent, }) } @@ -206,8 +216,6 @@ impl EmulatorAccountStorage<'_, T> { pub async fn apply_actions(&mut self, actions: Vec) -> Result<(), NeonError> { info!("apply_actions"); - let rent = Rent::get()?; - let mut new_balance_accounts = HashSet::new(); for action in actions { @@ -255,12 +263,13 @@ impl EmulatorAccountStorage<'_, T> { let empty_size = StorageCell::required_account_size(0); let gas = if account.is_none() { - rent.minimum_balance(cell_size) + self.rent.minimum_balance(cell_size) } else { let existing_value = self.storage(address, index).await; if existing_value == [0_u8; 32] { - rent.minimum_balance(cell_size) - .saturating_sub(rent.minimum_balance(empty_size)) + self.rent + .minimum_balance(cell_size) + .saturating_sub(self.rent.minimum_balance(empty_size)) } else { 0 } @@ -287,7 +296,7 @@ impl EmulatorAccountStorage<'_, T> { self.use_contract_account(address, true).await?; let space = ContractAccount::required_account_size(&code); - self.gas = self.gas.saturating_add(rent.minimum_balance(space)); + self.gas = self.gas.saturating_add(self.rent.minimum_balance(space)); } Action::EvmSelfDestruct { address } => { info!("selfdestruct {address}"); @@ -313,7 +322,8 @@ impl EmulatorAccountStorage<'_, T> { } self.gas = self.gas.saturating_add( - rent.minimum_balance(BalanceAccount::required_account_size()) + self.rent + .minimum_balance(BalanceAccount::required_account_size()) .saturating_mul(new_balance_accounts.len() as u64), ); @@ -324,8 +334,6 @@ impl EmulatorAccountStorage<'_, T> { let mut accounts = self.accounts.borrow_mut(); let mut additional_balances = Vec::new(); - let rent = Rent::get()?; - for (key, account) in accounts.iter_mut() { let Some(account_data) = account.data.as_mut() else { continue; @@ -354,7 +362,9 @@ impl EmulatorAccountStorage<'_, T> { if (legacy_data.code_size > 0) || (legacy_data.generation > 0) { // This is a contract, we need additional gas for conversion - let lamports = rent.minimum_balance(BalanceAccount::required_account_size()); + let lamports = self + .rent + .minimum_balance(BalanceAccount::required_account_size()); self.gas = self.gas.saturating_add(lamports); } } @@ -526,6 +536,16 @@ impl AccountStorage for EmulatorAccountStorage<'_, T> { self.block_timestamp.try_into().unwrap() } + fn rent(&self) -> &Rent { + &self.rent + } + + fn return_data(&self) -> Option<(Pubkey, Vec)> { + info!("return_data"); + // TODO: implement return_data() method with SyncedAccountStorage implementation + unimplemented!(); + } + async fn block_hash(&self, slot: u64) -> [u8; 32] { info!("block_hash {slot}"); diff --git a/evm_loader/lib/src/commands/emulate.rs b/evm_loader/lib/src/commands/emulate.rs index 05de4cd0c..05b76c922 100644 --- a/evm_loader/lib/src/commands/emulate.rs +++ b/evm_loader/lib/src/commands/emulate.rs @@ -8,7 +8,6 @@ use solana_sdk::pubkey::Pubkey; use crate::commands::get_config::BuildConfigSimulator; use crate::rpc::Rpc; -use crate::syscall_stubs::setup_emulator_syscall_stubs; use crate::tracing::tracers::Tracer; use crate::types::{EmulateRequest, TxParams}; use crate::{ @@ -78,7 +77,6 @@ pub async fn execute( let step_limit = emulate_request.step_limit.unwrap_or(100000); - setup_emulator_syscall_stubs(rpc).await?; emulate_trx(emulate_request.tx, &mut storage, step_limit, tracer).await } diff --git a/evm_loader/lib/src/lib.rs b/evm_loader/lib/src/lib.rs index eb80c7e78..d50c2f17b 100644 --- a/evm_loader/lib/src/lib.rs +++ b/evm_loader/lib/src/lib.rs @@ -5,7 +5,7 @@ pub mod commands; pub mod config; pub mod errors; pub mod rpc; -pub mod syscall_stubs; + pub mod tracing; pub mod types; diff --git a/evm_loader/lib/src/syscall_stubs.rs b/evm_loader/lib/src/syscall_stubs.rs deleted file mode 100644 index 0def2705b..000000000 --- a/evm_loader/lib/src/syscall_stubs.rs +++ /dev/null @@ -1,60 +0,0 @@ -use log::info; -use solana_sdk::{program_error::ProgramError, program_stubs::SyscallStubs, sysvar::rent::Rent}; - -use crate::{errors::NeonError, rpc::Rpc}; - -pub struct EmulatorStubs { - rent: Rent, -} - -impl EmulatorStubs { - pub async fn new(rpc: &impl Rpc) -> Result, NeonError> { - let rent_pubkey = solana_sdk::sysvar::rent::id(); - let data = rpc - .get_account(&rent_pubkey) - .await? - .value - .map(|a| a.data) - .unwrap_or_default(); - let rent = bincode::deserialize(&data).map_err(|_| ProgramError::InvalidArgument)?; - - Ok(Box::new(Self { rent })) - } -} - -impl SyscallStubs for EmulatorStubs { - fn sol_get_rent_sysvar(&self, pointer: *mut u8) -> u64 { - unsafe { - #[allow(clippy::cast_ptr_alignment)] - let rent = pointer.cast::(); - *rent = self.rent; - } - - 0 - } - - fn sol_log(&self, message: &str) { - info!("{}", message); - } - - fn sol_log_data(&self, fields: &[&[u8]]) { - let mut messages: Vec = Vec::new(); - - for f in fields { - if let Ok(str) = String::from_utf8(f.to_vec()) { - messages.push(str); - } else { - messages.push(hex::encode(f)); - } - } - - info!("Program Data: {}", messages.join(" ")); - } -} - -pub async fn setup_emulator_syscall_stubs(rpc: &impl Rpc) -> Result<(), NeonError> { - let syscall_stubs = EmulatorStubs::new(rpc).await?; - solana_sdk::program_stubs::set_syscall_stubs(syscall_stubs); - - Ok(()) -} diff --git a/evm_loader/program/src/account/ether_balance.rs b/evm_loader/program/src/account/ether_balance.rs index d84dd3925..dd316d95e 100644 --- a/evm_loader/program/src/account/ether_balance.rs +++ b/evm_loader/program/src/account/ether_balance.rs @@ -11,7 +11,7 @@ use crate::{ types::Address, }; use ethnum::U256; -use solana_program::{account_info::AccountInfo, pubkey::Pubkey, system_program}; +use solana_program::{account_info::AccountInfo, pubkey::Pubkey, rent::Rent, system_program}; use super::{AccountsDB, ACCOUNT_PREFIX_LEN, ACCOUNT_SEED_VERSION, TAG_ACCOUNT_BALANCE}; @@ -46,6 +46,7 @@ impl<'a> BalanceAccount<'a> { chain_id: u64, accounts: &AccountsDB<'a>, keys: Option<&KeysCache>, + rent: &Rent, ) -> Result { let (pubkey, bump_seed) = keys.map_or_else( || address.find_balance_address(&crate::ID, chain_id), @@ -93,6 +94,7 @@ impl<'a> BalanceAccount<'a> { &account, program_seeds, ACCOUNT_PREFIX_LEN + size_of::
(), + rent, )?; super::set_tag(&crate::ID, &account, TAG_ACCOUNT_BALANCE)?; diff --git a/evm_loader/program/src/account/ether_contract.rs b/evm_loader/program/src/account/ether_contract.rs index 4eb41c658..64c30a91b 100644 --- a/evm_loader/program/src/account/ether_contract.rs +++ b/evm_loader/program/src/account/ether_contract.rs @@ -78,7 +78,7 @@ impl<'a> ContractAccount<'a> { if system_program::check_id(info.owner) { let seeds: &[&[u8]] = &[&[ACCOUNT_SEED_VERSION], address.as_bytes(), &[bump_seed]]; let space = required_size.min(MAX_PERMITTED_DATA_INCREASE); - system.create_pda_account(&crate::ID, operator, info, seeds, space)?; + system.create_pda_account(&crate::ID, operator, info, seeds, space, rent)?; } else if crate::check_id(info.owner) { super::validate_tag(&crate::ID, info, TAG_EMPTY)?; diff --git a/evm_loader/program/src/account/ether_storage.rs b/evm_loader/program/src/account/ether_storage.rs index f047b4da9..1e6b1dc97 100644 --- a/evm_loader/program/src/account/ether_storage.rs +++ b/evm_loader/program/src/account/ether_storage.rs @@ -97,6 +97,7 @@ impl<'a> StorageCell<'a> { allocate_cells: usize, accounts: &AccountsDB<'a>, signer_seeds: &[&[u8]], + rent: &Rent, ) -> Result { let base_account = accounts.get(&address.base); let cell_account = accounts.get(&address.pubkey); @@ -114,6 +115,7 @@ impl<'a> StorageCell<'a> { cell_account, address.seed(), space, + rent, )?; super::set_tag(&crate::ID, cell_account, TAG_STORAGE_CELL)?; @@ -200,7 +202,7 @@ impl<'a> StorageCell<'a> { Ok(()) } - pub fn sync_lamports(&mut self, rent: Rent, accounts: &AccountsDB<'a>) -> Result<()> { + pub fn sync_lamports(&mut self, rent: &Rent, accounts: &AccountsDB<'a>) -> Result<()> { let original_data_len = unsafe { self.account.original_data_len() }; if original_data_len == self.account.data_len() { return Ok(()); diff --git a/evm_loader/program/src/account/legacy/mod.rs b/evm_loader/program/src/account/legacy/mod.rs index cf730df67..414ad4e65 100644 --- a/evm_loader/program/src/account/legacy/mod.rs +++ b/evm_loader/program/src/account/legacy/mod.rs @@ -27,13 +27,12 @@ pub const TAG_HOLDER_DEPRECATED: u8 = 51; pub const TAG_ACCOUNT_CONTRACT_DEPRECATED: u8 = 12; pub const TAG_STORAGE_CELL_DEPRECATED: u8 = 42; -fn reduce_account_size(account: &AccountInfo, required_len: usize) -> Result { +fn reduce_account_size(account: &AccountInfo, required_len: usize, rent: &Rent) -> Result { assert!(account.data_len() > required_len); account.realloc(required_len, false)?; // Return excessive lamports to the operator - let rent = Rent::get()?; let minimum_balance = rent.minimum_balance(account.data_len()); if account.lamports() > minimum_balance { let value = account.lamports() - minimum_balance; @@ -59,6 +58,7 @@ fn update_ether_account( legacy_data: &LegacyEtherData, db: &AccountsDB, keys: &KeysCache, + rent: &Rent, ) -> Result { let pubkey = keys.contract(&crate::ID, legacy_data.address); let account = db.get(&pubkey); @@ -75,7 +75,7 @@ fn update_ether_account( // Make account smaller let required_len = ContractAccount::required_account_size(&code); - lamports_collected += reduce_account_size(account, required_len)?; + lamports_collected += reduce_account_size(account, required_len, rent)?; // Fill it with new data account.try_borrow_mut_data()?.fill(0); @@ -103,6 +103,7 @@ fn update_ether_account( crate::config::DEFAULT_CHAIN_ID, db, Some(keys), + rent, )?; balance.mint(legacy_data.balance)?; balance.increment_nonce_by(legacy_data.trx_count)?; @@ -117,6 +118,7 @@ fn update_storage_account( legacy_data: &LegacyStorageData, db: &AccountsDB, keys: &KeysCache, + rent: &Rent, ) -> Result { let mut lamports_collected = 0_u64; @@ -137,7 +139,7 @@ fn update_storage_account( // Make account smaller let required_len = StorageCell::required_account_size(cells.len()); - lamports_collected += reduce_account_size(&cell_account, required_len)?; + lamports_collected += reduce_account_size(&cell_account, required_len, rent)?; // Fill it with new data cell_account.try_borrow_mut_data()?.fill(0); @@ -187,6 +189,8 @@ pub fn update_holder_account(account: &AccountInfo) -> Result { pub fn update_legacy_accounts(accounts: &AccountsDB) -> Result { let keys = KeysCache::new(); + let rent = Rent::get()?; + let mut lamports_collected = 0_u64; let mut legacy_storage = Vec::with_capacity(accounts.accounts_len()); @@ -203,7 +207,7 @@ pub fn update_legacy_accounts(accounts: &AccountsDB) -> Result { match tag { LegacyEtherData::TAG => { let legacy_data = LegacyEtherData::from_account(&crate::ID, account)?; - lamports_collected += update_ether_account(&legacy_data, accounts, &keys)?; + lamports_collected += update_ether_account(&legacy_data, accounts, &keys, &rent)?; } LegacyStorageData::TAG => { let legacy_data = LegacyStorageData::from_account(&crate::ID, account)?; @@ -214,7 +218,7 @@ pub fn update_legacy_accounts(accounts: &AccountsDB) -> Result { } for data in legacy_storage { - lamports_collected += update_storage_account(&data, accounts, &keys)?; + lamports_collected += update_storage_account(&data, accounts, &keys, &rent)?; } Ok(lamports_collected) diff --git a/evm_loader/program/src/account/program.rs b/evm_loader/program/src/account/program.rs index 756d01220..0acdd48f0 100644 --- a/evm_loader/program/src/account/program.rs +++ b/evm_loader/program/src/account/program.rs @@ -3,7 +3,7 @@ use solana_program::account_info::AccountInfo; use solana_program::program::{invoke_signed_unchecked, invoke_unchecked}; use solana_program::program_error::ProgramError; use solana_program::pubkey::Pubkey; -use solana_program::{rent::Rent, system_instruction, sysvar::Sysvar}; +use solana_program::{rent::Rent, system_instruction}; use std::convert::From; use std::ops::Deref; @@ -31,8 +31,8 @@ impl<'a> System<'a> { new_account: &AccountInfo<'a>, new_account_seeds: &[&[u8]], space: usize, + rent: &Rent, ) -> Result<(), ProgramError> { - let rent = Rent::get()?; let minimum_balance = rent.minimum_balance(space).max(1); if new_account.lamports() > 0 { @@ -81,8 +81,9 @@ impl<'a> System<'a> { new_account: &AccountInfo<'a>, seed: &str, space: usize, + rent: &Rent, ) -> Result<(), ProgramError> { - let minimum_balance = Rent::get()?.minimum_balance(space).max(1); + let minimum_balance = rent.minimum_balance(space).max(1); if new_account.lamports() > 0 { let required_lamports = minimum_balance.saturating_sub(new_account.lamports()); diff --git a/evm_loader/program/src/account_storage/apply.rs b/evm_loader/program/src/account_storage/apply.rs index a98bfacde..0392d0a3a 100644 --- a/evm_loader/program/src/account_storage/apply.rs +++ b/evm_loader/program/src/account_storage/apply.rs @@ -4,9 +4,7 @@ use ethnum::U256; use solana_program::account_info::AccountInfo; use solana_program::instruction::Instruction; use solana_program::program::{invoke_signed_unchecked, invoke_unchecked}; -use solana_program::rent::Rent; use solana_program::system_program; -use solana_program::sysvar::Sysvar; use crate::account::BalanceAccount; use crate::account::{AllocateResult, ContractAccount, StorageCell}; @@ -48,14 +46,12 @@ impl<'a> ProgramAccountStorage<'a> { pub fn allocate(&mut self, actions: &[Action]) -> Result { let mut total_result = AllocateResult::Ready; - let rent = Rent::get()?; - for action in actions { if let Action::EvmSetCode { address, code, .. } = action { let result = ContractAccount::allocate( *address, code, - &rent, + &self.rent, &self.accounts, Some(&self.keys), )?; @@ -174,8 +170,6 @@ impl<'a> ProgramAccountStorage<'a> { fn apply_storage(&mut self, storage: HashMap>) -> Result<()> { const STATIC_STORAGE_LIMIT: U256 = U256::new(STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT as u128); - let rent = Rent::get()?; - for (address, storage) in storage { let mut contract = self.contract_account(address)?; @@ -208,7 +202,8 @@ impl<'a> ProgramAccountStorage<'a> { let sign: &[&[u8]] = &[&[ACCOUNT_SEED_VERSION], address.as_bytes(), &[bump]]; let len = values.len(); - let mut storage = StorageCell::create(cell_address, len, &self.accounts, sign)?; + let mut storage = + StorageCell::create(cell_address, len, &self.accounts, sign, &self.rent)?; let mut cells = storage.cells_mut(); assert_eq!(cells.len(), len); @@ -222,7 +217,7 @@ impl<'a> ProgramAccountStorage<'a> { storage.update(subindex, &value)?; } - storage.sync_lamports(rent, &self.accounts)?; + storage.sync_lamports(&self.rent, &self.accounts)?; }; } } diff --git a/evm_loader/program/src/account_storage/backend.rs b/evm_loader/program/src/account_storage/backend.rs index 7cbd6406a..d6f7b0a05 100644 --- a/evm_loader/program/src/account_storage/backend.rs +++ b/evm_loader/program/src/account_storage/backend.rs @@ -5,7 +5,7 @@ use crate::executor::OwnedAccountInfo; use crate::types::Address; use ethnum::U256; use solana_program::account_info::AccountInfo; -use solana_program::{pubkey::Pubkey, sysvar::slot_hashes}; +use solana_program::{pubkey::Pubkey, rent::Rent, sysvar::slot_hashes}; use std::convert::TryInto; impl<'a> AccountStorage for ProgramAccountStorage<'a> { @@ -28,6 +28,14 @@ impl<'a> AccountStorage for ProgramAccountStorage<'a> { .expect("Timestamp is positive") } + fn rent(&self) -> &Rent { + &self.rent + } + + fn return_data(&self) -> Option<(Pubkey, Vec)> { + solana_program::program::get_return_data() + } + fn block_hash(&self, slot: u64) -> [u8; 32] { let slot_hashes_account = self.accounts.get(&slot_hashes::ID); let slot_hashes_data = slot_hashes_account.data.borrow(); diff --git a/evm_loader/program/src/account_storage/base.rs b/evm_loader/program/src/account_storage/base.rs index 3169d66a1..24464937d 100644 --- a/evm_loader/program/src/account_storage/base.rs +++ b/evm_loader/program/src/account_storage/base.rs @@ -6,9 +6,7 @@ use crate::config::DEFAULT_CHAIN_ID; use crate::error::Result; use crate::types::Address; use ethnum::U256; -use solana_program::clock::Clock; -use solana_program::system_program; -use solana_program::sysvar::Sysvar; +use solana_program::{clock::Clock, rent::Rent, system_program, sysvar::Sysvar}; use super::keys_cache::KeysCache; @@ -16,6 +14,7 @@ impl<'a> ProgramAccountStorage<'a> { pub fn new(accounts: AccountsDB<'a>) -> Result { Ok(Self { clock: Clock::get()?, + rent: Rent::get()?, accounts, keys: KeysCache::new(), }) @@ -88,6 +87,12 @@ impl<'a> ProgramAccountStorage<'a> { address: Address, chain_id: u64, ) -> Result> { - BalanceAccount::create(address, chain_id, &self.accounts, Some(&self.keys)) + BalanceAccount::create( + address, + chain_id, + &self.accounts, + Some(&self.keys), + &self.rent, + ) } } diff --git a/evm_loader/program/src/account_storage/mod.rs b/evm_loader/program/src/account_storage/mod.rs index 43489fe03..90972705f 100644 --- a/evm_loader/program/src/account_storage/mod.rs +++ b/evm_loader/program/src/account_storage/mod.rs @@ -8,6 +8,7 @@ use solana_program::account_info::AccountInfo; use {crate::account::AccountsDB, solana_program::clock::Clock}; use solana_program::pubkey::Pubkey; +use solana_program::rent::Rent; #[cfg(target_os = "solana")] mod apply; @@ -24,6 +25,7 @@ pub use keys_cache::KeysCache; #[cfg(target_os = "solana")] pub struct ProgramAccountStorage<'a> { clock: Clock, + rent: Rent, accounts: AccountsDB<'a>, keys: keys_cache::KeysCache, } @@ -44,6 +46,12 @@ pub trait AccountStorage { /// Get block hash async fn block_hash(&self, number: u64) -> [u8; 32]; + /// Get rent info + fn rent(&self) -> &Rent; + + /// Get return data from Solana + fn return_data(&self) -> Option<(Pubkey, Vec)>; + /// Get account nonce async fn nonce(&self, address: Address, chain_id: u64) -> u64; /// Get account balance diff --git a/evm_loader/program/src/debug.rs b/evm_loader/program/src/debug.rs index a23d4429d..e7fe5153f 100644 --- a/evm_loader/program/src/debug.rs +++ b/evm_loader/program/src/debug.rs @@ -15,3 +15,34 @@ macro_rules! debug_print { macro_rules! debug_print { ($( $args:expr ),*) => {}; } + +#[cfg(target_os = "solana")] +macro_rules! log_msg { + ($($arg:tt)*) => (solana_program::msg!($($arg)*)); +} + +#[cfg(not(target_os = "solana"))] +macro_rules! log_msg { + ($($arg:tt)*) => (log::info!($($arg)*)); +} + +#[inline] +pub fn log_data(data: &[&[u8]]) { + #[cfg(target_os = "solana")] + solana_program::log::sol_log_data(data); + + #[cfg(not(target_os = "solana"))] + { + let mut messages: Vec = Vec::new(); + + for f in data { + if let Ok(str) = String::from_utf8(f.to_vec()) { + messages.push(str); + } else { + messages.push(hex::encode(f)); + } + } + + log::info!("Program Data: {}", messages.join(" ")); + } +} diff --git a/evm_loader/program/src/entrypoint.rs b/evm_loader/program/src/entrypoint.rs index daa05f33c..3f64b0757 100644 --- a/evm_loader/program/src/entrypoint.rs +++ b/evm_loader/program/src/entrypoint.rs @@ -49,7 +49,7 @@ fn process_instruction<'a>( instruction::config_get_version::process(program_id, accounts, instruction) } _ => { - solana_program::msg!("Emergency image: all instructions are rejected"); + log_msg!("Emergency image: all instructions are rejected"); Err(ProgramError::InvalidInstructionData.into()) } } diff --git a/evm_loader/program/src/error.rs b/evm_loader/program/src/error.rs index d0049f7af..fdf64bccb 100644 --- a/evm_loader/program/src/error.rs +++ b/evm_loader/program/src/error.rs @@ -181,7 +181,7 @@ pub type Result = std::result::Result; impl From for ProgramError { fn from(e: Error) -> Self { - solana_program::msg!("{}", e); + log_msg!("{}", e); match e { Error::ProgramError(e) => e, _ => Self::Custom(0), @@ -269,18 +269,18 @@ fn format_revert_panic(msg: &[u8]) -> Option { pub fn print_revert_message(msg: &[u8]) { if msg.is_empty() { - return solana_program::msg!("Revert"); + return log_msg!("Revert"); } if let Some(reason) = format_revert_error(msg) { - return solana_program::msg!("Revert: Error(\"{}\")", reason); + return log_msg!("Revert: Error(\"{}\")", reason); } if let Some(reason) = format_revert_panic(msg) { - return solana_program::msg!("Revert: Panic({:#x})", reason); + return log_msg!("Revert: Panic({:#x})", reason); } - solana_program::msg!("Revert: {}", hex::encode(msg)); + log_msg!("Revert: {}", hex::encode(msg)); } #[must_use] diff --git a/evm_loader/program/src/evm/database.rs b/evm_loader/program/src/evm/database.rs index 73ea18cde..827bee83f 100644 --- a/evm_loader/program/src/evm/database.rs +++ b/evm_loader/program/src/evm/database.rs @@ -2,7 +2,7 @@ use super::{Buffer, Context}; use crate::{error::Result, types::Address}; use ethnum::U256; use maybe_async::maybe_async; -use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; +use solana_program::{account_info::AccountInfo, pubkey::Pubkey, rent::Rent}; #[maybe_async(?Send)] pub trait Database { @@ -32,6 +32,8 @@ pub trait Database { async fn block_hash(&self, number: U256) -> Result<[u8; 32]>; fn block_number(&self) -> Result; fn block_timestamp(&self) -> Result; + fn rent(&self) -> &Rent; + fn return_data(&self) -> Option<(Pubkey, Vec)>; async fn map_solana_account(&self, address: &Pubkey, action: F) -> R where @@ -224,6 +226,14 @@ mod tests { unimplemented!(); } + fn rent(&self) -> &Rent { + unimplemented!(); + } + + fn return_data(&self) -> Option<(Pubkey, Vec)> { + unimplemented!(); + } + async fn map_solana_account(&self, address: &Pubkey, action: F) -> R where F: FnOnce(&AccountInfo) -> R, diff --git a/evm_loader/program/src/evm/mod.rs b/evm_loader/program/src/evm/mod.rs index 8ac20e696..b26c65cc1 100644 --- a/evm_loader/program/src/evm/mod.rs +++ b/evm_loader/program/src/evm/mod.rs @@ -7,7 +7,6 @@ use std::{fmt::Display, marker::PhantomData, ops::Range}; use ethnum::U256; use maybe_async::maybe_async; use serde::{Deserialize, Serialize}; -use solana_program::log::sol_log_data; pub use buffer::Buffer; @@ -15,6 +14,7 @@ use crate::evm::tracing::EventListener; #[cfg(target_os = "solana")] use crate::evm::tracing::NoopEventListener; use crate::{ + debug::log_data, error::{build_revert_message, Error, Result}, evm::{opcode::Action, precompile::is_precompile_address}, types::{Address, Transaction}, @@ -263,7 +263,7 @@ impl Machine { assert!(trx.target().is_some()); let target = trx.target().unwrap(); - sol_log_data(&[b"ENTER", b"CALL", target.as_bytes()]); + log_data(&[b"ENTER", b"CALL", target.as_bytes()]); backend.increment_nonce(origin, chain_id)?; backend.snapshot(); @@ -312,7 +312,7 @@ impl Machine { assert!(trx.target().is_none()); let target = Address::from_create(&origin, trx.nonce()); - sol_log_data(&[b"ENTER", b"CREATE", target.as_bytes()]); + log_data(&[b"ENTER", b"CREATE", target.as_bytes()]); if (backend.nonce(target, chain_id).await? != 0) || (backend.code_size(target).await? != 0) { diff --git a/evm_loader/program/src/evm/opcode.rs b/evm_loader/program/src/evm/opcode.rs index d1d42d2df..38941e9eb 100644 --- a/evm_loader/program/src/evm/opcode.rs +++ b/evm_loader/program/src/evm/opcode.rs @@ -1,7 +1,6 @@ /// use ethnum::{I256, U256}; use maybe_async::maybe_async; -use solana_program::log::sol_log_data; use super::{ database::{Database, DatabaseExt}, @@ -9,6 +8,7 @@ use super::{ }; use crate::evm::tracing::EventListener; use crate::{ + debug::log_data, error::{Error, Result}, evm::{trace_end_step, Buffer}, types::Address, @@ -993,11 +993,11 @@ impl Machine { let address = self.context.contract.as_bytes(); match N { - 0 => sol_log_data(&[b"LOG0", address, &[0], data]), - 1 => sol_log_data(&[b"LOG1", address, &[1], &topics[0], data]), - 2 => sol_log_data(&[b"LOG2", address, &[2], &topics[0], &topics[1], data]), - 3 => sol_log_data(&[b"LOG3", address, &[3], &topics[0], &topics[1], &topics[2], data]), - 4 => sol_log_data(&[b"LOG4", address, &[4], &topics[0], &topics[1], &topics[2], &topics[3], data]), + 0 => log_data(&[b"LOG0", address, &[0], data]), + 1 => log_data(&[b"LOG1", address, &[1], &topics[0], data]), + 2 => log_data(&[b"LOG2", address, &[2], &topics[0], &topics[1], data]), + 3 => log_data(&[b"LOG3", address, &[3], &topics[0], &topics[1], &topics[2], data]), + 4 => log_data(&[b"LOG4", address, &[4], &topics[0], &topics[1], &topics[2], &topics[3], data]), _ => unreachable!(), } @@ -1099,7 +1099,7 @@ impl Machine { ); backend.snapshot(); - sol_log_data(&[b"ENTER", b"CREATE", address.as_bytes()]); + log_data(&[b"ENTER", b"CREATE", address.as_bytes()]); if (backend.nonce(address, chain_id).await? != 0) || (backend.code_size(address).await? != 0) @@ -1160,7 +1160,7 @@ impl Machine { ); backend.snapshot(); - sol_log_data(&[b"ENTER", b"CALL", address.as_bytes()]); + log_data(&[b"ENTER", b"CALL", address.as_bytes()]); if self.is_static && (value != U256::ZERO) { return Err(Error::StaticModeViolation(self.context.caller)); @@ -1216,7 +1216,7 @@ impl Machine { ); backend.snapshot(); - sol_log_data(&[b"ENTER", b"CALLCODE", address.as_bytes()]); + log_data(&[b"ENTER", b"CALLCODE", address.as_bytes()]); if backend.balance(self.context.caller, chain_id).await? < value { return Err(Error::InsufficientBalance( @@ -1270,7 +1270,7 @@ impl Machine { ); backend.snapshot(); - sol_log_data(&[b"ENTER", b"DELEGATECALL", address.as_bytes()]); + log_data(&[b"ENTER", b"DELEGATECALL", address.as_bytes()]); self.opcode_call_precompile_impl(backend, &address).await } @@ -1322,7 +1322,7 @@ impl Machine { backend.snapshot(); - sol_log_data(&[b"ENTER", b"STATICCALL", address.as_bytes()]); + log_data(&[b"ENTER", b"STATICCALL", address.as_bytes()]); self.opcode_call_precompile_impl(backend, &address).await } @@ -1375,7 +1375,7 @@ impl Machine { } backend.commit_snapshot(); - sol_log_data(&[b"EXIT", b"RETURN"]); + log_data(&[b"EXIT", b"RETURN"]); if self.parent.is_none() { return Ok(Action::Return(return_data)); @@ -1425,7 +1425,7 @@ impl Machine { backend: &mut B, ) -> Result { backend.revert_snapshot(); - sol_log_data(&[b"EXIT", b"REVERT", &return_data]); + log_data(&[b"EXIT", b"REVERT", &return_data]); if self.parent.is_none() { return Ok(Action::Revert(return_data)); @@ -1482,7 +1482,7 @@ impl Machine { backend.selfdestruct(self.context.contract)?; backend.commit_snapshot(); - sol_log_data(&[b"EXIT", b"SELFDESTRUCT"]); + log_data(&[b"EXIT", b"SELFDESTRUCT"]); if self.parent.is_none() { return Ok(Action::Suicide); @@ -1515,7 +1515,7 @@ impl Machine { #[maybe_async] pub async fn opcode_stop(&mut self, backend: &mut B) -> Result { backend.commit_snapshot(); - sol_log_data(&[b"EXIT", b"STOP"]); + log_data(&[b"EXIT", b"STOP"]); if self.parent.is_none() { return Ok(Action::Stop); diff --git a/evm_loader/program/src/executor/precompile_extension/metaplex.rs b/evm_loader/program/src/executor/precompile_extension/metaplex.rs index aaca012ee..be7ed8194 100644 --- a/evm_loader/program/src/executor/precompile_extension/metaplex.rs +++ b/evm_loader/program/src/executor/precompile_extension/metaplex.rs @@ -7,7 +7,7 @@ use mpl_token_metadata::state::{ Creator, Metadata, TokenMetadataAccount, TokenStandard, CREATE_FEE, MAX_MASTER_EDITION_LEN, MAX_METADATA_LEN, }; -use solana_program::{pubkey::Pubkey, rent::Rent, sysvar::Sysvar}; +use solana_program::pubkey::Pubkey; use crate::{ account::ACCOUNT_SEED_VERSION, @@ -193,9 +193,7 @@ impl ExecutorState<'_, B> { None, // Collection Details ); - let rent = Rent::get()?; - let fee = rent.minimum_balance(MAX_METADATA_LEN) + CREATE_FEE; - + let fee = self.backend.rent().minimum_balance(MAX_METADATA_LEN) + CREATE_FEE; self.queue_external_instruction(instruction, seeds, fee); Ok(metadata_pubkey.to_bytes().to_vec()) @@ -230,9 +228,7 @@ impl ExecutorState<'_, B> { max_supply, ); - let rent = Rent::get()?; - let fee = rent.minimum_balance(MAX_MASTER_EDITION_LEN) + CREATE_FEE; - + let fee = self.backend.rent().minimum_balance(MAX_MASTER_EDITION_LEN) + CREATE_FEE; self.queue_external_instruction(instruction, seeds, fee); Ok(edition_pubkey.to_bytes().to_vec()) diff --git a/evm_loader/program/src/executor/precompile_extension/neon_token.rs b/evm_loader/program/src/executor/precompile_extension/neon_token.rs index 31f6c2d70..8fef61051 100644 --- a/evm_loader/program/src/executor/precompile_extension/neon_token.rs +++ b/evm_loader/program/src/executor/precompile_extension/neon_token.rs @@ -3,9 +3,7 @@ use std::convert::TryInto; use arrayref::array_ref; use ethnum::U256; use maybe_async::maybe_async; -use solana_program::{ - account_info::IntoAccountInfo, program_pack::Pack, pubkey::Pubkey, rent::Rent, sysvar::Sysvar, -}; +use solana_program::{account_info::IntoAccountInfo, program_pack::Pack, pubkey::Pubkey}; use spl_associated_token_account::get_associated_token_address; use crate::{ @@ -118,8 +116,10 @@ impl ExecutorState<'_, B> { &spl_token::ID, ); - let rent = Rent::get()?; - let fee = rent.minimum_balance(spl_token::state::Account::LEN); + let fee = self + .backend + .rent() + .minimum_balance(spl_token::state::Account::LEN); self.queue_external_instruction(create_associated, vec![], fee); } diff --git a/evm_loader/program/src/executor/precompile_extension/spl_token.rs b/evm_loader/program/src/executor/precompile_extension/spl_token.rs index 39ca0b34e..20119d6ce 100644 --- a/evm_loader/program/src/executor/precompile_extension/spl_token.rs +++ b/evm_loader/program/src/executor/precompile_extension/spl_token.rs @@ -3,8 +3,8 @@ use std::convert::{Into, TryInto}; use ethnum::U256; use maybe_async::maybe_async; use solana_program::{ - program_error::ProgramError, program_pack::Pack, pubkey::Pubkey, rent::Rent, - system_instruction, system_program, sysvar::Sysvar, + program_error::ProgramError, program_pack::Pack, pubkey::Pubkey, system_instruction, + system_program, }; use crate::{ @@ -260,14 +260,8 @@ impl ExecutorState<'_, B> { } } - fn create_account( - &mut self, - account: &OwnedAccountInfo, - space: usize, - seeds: Vec>, - ) -> Result<()> { - let rent = Rent::get()?; - let minimum_balance = rent.minimum_balance(space); + fn create_account(&mut self, account: &OwnedAccountInfo, space: usize, seeds: Vec>) { + let minimum_balance = self.backend.rent().minimum_balance(space); let required_lamports = minimum_balance.saturating_sub(account.lamports); @@ -285,8 +279,6 @@ impl ExecutorState<'_, B> { let assign = system_instruction::assign(&account.key, &spl_token::ID); self.queue_external_instruction(assign, seeds, 0); - - Ok(()) } #[maybe_async] @@ -324,7 +316,7 @@ impl ExecutorState<'_, B> { vec![bump_seed], ]; - self.create_account(&account, spl_token::state::Mint::LEN, seeds)?; + self.create_account(&account, spl_token::state::Mint::LEN, seeds); let initialize_mint = spl_token::instruction::initialize_mint( &spl_token::ID, @@ -372,7 +364,7 @@ impl ExecutorState<'_, B> { vec![bump_seed], ]; - self.create_account(&account, spl_token::state::Account::LEN, seeds)?; + self.create_account(&account, spl_token::state::Account::LEN, seeds); let initialize_mint = spl_token::instruction::initialize_account2( &spl_token::ID, diff --git a/evm_loader/program/src/executor/state.rs b/evm_loader/program/src/executor/state.rs index 5a79b16a8..9fc3b1980 100644 --- a/evm_loader/program/src/executor/state.rs +++ b/evm_loader/program/src/executor/state.rs @@ -5,6 +5,7 @@ use ethnum::{AsU256, U256}; use maybe_async::maybe_async; use solana_program::instruction::Instruction; use solana_program::pubkey::Pubkey; +use solana_program::rent::Rent; use crate::account_storage::AccountStorage; use crate::error::{Error, Result}; @@ -155,10 +156,16 @@ impl<'a, B: AccountStorage> ExecutorState<'a, B> { data, meta, &mut accounts, + self.rent(), )?; } program_id if mpl_token_metadata::check_id(program_id) => { - crate::external_programs::metaplex::emulate(data, meta, &mut accounts)?; + crate::external_programs::metaplex::emulate( + data, + meta, + &mut accounts, + self.rent(), + )?; } _ => { return Err(Error::Custom(format!( @@ -387,6 +394,14 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { Ok(cache.block_timestamp) } + fn rent(&self) -> &Rent { + self.backend.rent() + } + + fn return_data(&self) -> Option<(Pubkey, Vec)> { + self.backend.return_data() + } + async fn map_solana_account(&self, address: &Pubkey, action: F) -> R where F: FnOnce(&solana_program::account_info::AccountInfo) -> R, diff --git a/evm_loader/program/src/external_programs/metaplex.rs b/evm_loader/program/src/external_programs/metaplex.rs index 0f2c513ad..a9fe278b8 100644 --- a/evm_loader/program/src/external_programs/metaplex.rs +++ b/evm_loader/program/src/external_programs/metaplex.rs @@ -6,7 +6,6 @@ use solana_program::account_info::IntoAccountInfo; use solana_program::instruction::AccountMeta; use solana_program::program_option::COption; use solana_program::rent::Rent; -use solana_program::sysvar::Sysvar; use spl_token::state::Mint; use std::collections::BTreeMap; @@ -26,13 +25,14 @@ pub fn emulate( instruction: &[u8], meta: &[AccountMeta], accounts: &mut BTreeMap, + rent: &Rent, ) -> ProgramResult { match MetadataInstruction::try_from_slice(instruction)? { MetadataInstruction::CreateMetadataAccountV3(args) => { - create_metadata_accounts_v3(meta, accounts, &args) + create_metadata_accounts_v3(meta, accounts, &args, rent) } MetadataInstruction::CreateMasterEditionV3(args) => { - create_master_edition_v3(meta, accounts, &args) + create_master_edition_v3(meta, accounts, &args, rent) } _ => Err!(ProgramError::InvalidInstructionData; "Unknown Metaplex instruction"), } @@ -42,6 +42,7 @@ fn create_metadata_accounts_v3( meta: &[AccountMeta], accounts: &mut BTreeMap, args: &CreateMetadataAccountArgsV3, + rent: &Rent, ) -> ProgramResult { let metadata_account_key = &meta[0].pubkey; let mint_key = &meta[1].pubkey; @@ -52,8 +53,6 @@ fn create_metadata_accounts_v3( // let _rent_key = &meta[6].pubkey; let mut metadata: Metadata = { - let rent = Rent::get()?; - let metadata_account = accounts.get_mut(metadata_account_key).unwrap(); metadata_account.data.resize(MAX_METADATA_LEN, 0); metadata_account.owner = mpl_token_metadata::ID; @@ -123,6 +122,7 @@ fn create_master_edition_v3( meta: &[AccountMeta], accounts: &mut BTreeMap, args: &CreateMasterEditionArgs, + rent: &Rent, ) -> ProgramResult { let edition_account_key = &meta[0].pubkey; let mint_key = &meta[1].pubkey; @@ -160,8 +160,6 @@ fn create_master_edition_v3( } { - let rent = Rent::get()?; - let edition_account = accounts.get_mut(edition_account_key).unwrap(); edition_account.data.resize(MAX_MASTER_EDITION_LEN, 0); edition_account.owner = mpl_token_metadata::ID; diff --git a/evm_loader/program/src/external_programs/spl_associated_token.rs b/evm_loader/program/src/external_programs/spl_associated_token.rs index 9ef2ae843..0491cc903 100644 --- a/evm_loader/program/src/external_programs/spl_associated_token.rs +++ b/evm_loader/program/src/external_programs/spl_associated_token.rs @@ -4,7 +4,7 @@ use crate::executor::OwnedAccountInfo; use borsh::BorshDeserialize; use solana_program::{ entrypoint::ProgramResult, instruction::AccountMeta, program_error::ProgramError, - program_pack::Pack, pubkey::Pubkey, rent::Rent, sysvar::Sysvar, + program_pack::Pack, pubkey::Pubkey, rent::Rent, }; use spl_associated_token_account::instruction::AssociatedTokenAccountInstruction; @@ -12,6 +12,7 @@ pub fn emulate( instruction: &[u8], meta: &[AccountMeta], accounts: &mut BTreeMap, + rent: &Rent, ) -> ProgramResult { let instruction = if instruction.is_empty() { AssociatedTokenAccountInstruction::Create @@ -33,8 +34,6 @@ pub fn emulate( let required_lamports = { let associated_token_account = &accounts[associated_token_account_key]; - - let rent = Rent::get()?; rent.minimum_balance(spl_token::state::Account::LEN) .max(1) .saturating_sub(associated_token_account.lamports) diff --git a/evm_loader/program/src/instruction/account_block_add.rs b/evm_loader/program/src/instruction/account_block_add.rs index ab2f5254b..b875f6a12 100644 --- a/evm_loader/program/src/instruction/account_block_add.rs +++ b/evm_loader/program/src/instruction/account_block_add.rs @@ -10,7 +10,7 @@ pub fn process<'a>( let stack_height = solana_program::instruction::get_stack_height(); assert_eq!(stack_height, TRANSACTION_LEVEL_STACK_HEIGHT); - solana_program::msg!("Instruction: Block Accounts"); + log_msg!("Instruction: Block Accounts"); todo!(); diff --git a/evm_loader/program/src/instruction/account_create_balance.rs b/evm_loader/program/src/instruction/account_create_balance.rs index 878eb4c78..8693310ab 100644 --- a/evm_loader/program/src/instruction/account_create_balance.rs +++ b/evm_loader/program/src/instruction/account_create_balance.rs @@ -1,5 +1,5 @@ use arrayref::array_ref; -use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; +use solana_program::{account_info::AccountInfo, pubkey::Pubkey, rent::Rent, sysvar::Sysvar}; use crate::account::{program, AccountsDB, BalanceAccount, Operator}; use crate::config::{CHAIN_ID_LIST, DEFAULT_CHAIN_ID}; @@ -11,7 +11,7 @@ pub fn process<'a>( accounts: &'a [AccountInfo<'a>], instruction: &[u8], ) -> Result<()> { - solana_program::msg!("Instruction: Create Balance Account"); + log_msg!("Instruction: Create Balance Account"); let operator = unsafe { Operator::from_account_not_whitelisted(&accounts[0]) }?; let system = program::System::from_account(&accounts[1])?; @@ -28,7 +28,7 @@ pub fn process<'a>( .binary_search_by_key(&chain_id, |c| c.0) .map_err(|_| Error::InvalidChainId(chain_id))?; - solana_program::msg!("Address: {}, ChainID: {}", address, chain_id); + log_msg!("Address: {}, ChainID: {}", address, chain_id); let mut excessive_lamports = 0; if chain_id == DEFAULT_CHAIN_ID { @@ -36,7 +36,8 @@ pub fn process<'a>( excessive_lamports += crate::account::legacy::update_legacy_accounts(&accounts_db)?; }; - BalanceAccount::create(address, chain_id, &accounts_db, None)?; + let rent = Rent::get()?; + BalanceAccount::create(address, chain_id, &accounts_db, None, &rent)?; **accounts_db.operator().try_borrow_mut_lamports()? += excessive_lamports; diff --git a/evm_loader/program/src/instruction/account_holder_create.rs b/evm_loader/program/src/instruction/account_holder_create.rs index 7509b9d1c..ac6687d2b 100644 --- a/evm_loader/program/src/instruction/account_holder_create.rs +++ b/evm_loader/program/src/instruction/account_holder_create.rs @@ -8,7 +8,7 @@ pub fn process<'a>( accounts: &'a [AccountInfo<'a>], instruction: &[u8], ) -> Result<()> { - solana_program::msg!("Instruction: Create Holder Account"); + log_msg!("Instruction: Create Holder Account"); let holder = accounts[0].clone(); let operator = unsafe { Operator::from_account_not_whitelisted(&accounts[1]) }?; diff --git a/evm_loader/program/src/instruction/account_holder_delete.rs b/evm_loader/program/src/instruction/account_holder_delete.rs index 8873f2642..6920b803b 100644 --- a/evm_loader/program/src/instruction/account_holder_delete.rs +++ b/evm_loader/program/src/instruction/account_holder_delete.rs @@ -7,7 +7,7 @@ pub fn process<'a>( accounts: &'a [AccountInfo<'a>], _instruction: &[u8], ) -> Result<()> { - solana_program::msg!("Instruction: Delete Holder Account"); + log_msg!("Instruction: Delete Holder Account"); let holder_info = accounts[0].clone(); let operator = unsafe { Operator::from_account_not_whitelisted(&accounts[1]) }?; diff --git a/evm_loader/program/src/instruction/account_holder_write.rs b/evm_loader/program/src/instruction/account_holder_write.rs index 47cca15eb..e9a5e8781 100644 --- a/evm_loader/program/src/instruction/account_holder_write.rs +++ b/evm_loader/program/src/instruction/account_holder_write.rs @@ -1,4 +1,5 @@ use crate::account::{Holder, Operator}; +use crate::debug::log_data; use crate::error::Result; use arrayref::array_ref; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; @@ -8,7 +9,7 @@ pub fn process<'a>( accounts: &'a [AccountInfo<'a>], instruction: &[u8], ) -> Result<()> { - solana_program::msg!("Instruction: Write To Holder"); + log_msg!("Instruction: Write To Holder"); let transaction_hash = *array_ref![instruction, 0, 32]; let offset = usize::from_le_bytes(*array_ref![instruction, 32, 8]); @@ -23,7 +24,7 @@ pub fn process<'a>( holder.validate_owner(&operator)?; holder.update_transaction_hash(transaction_hash); - solana_program::log::sol_log_data(&[b"HASH", &transaction_hash]); + log_data(&[b"HASH", &transaction_hash]); holder.write(offset, data)?; diff --git a/evm_loader/program/src/instruction/collect_treasury.rs b/evm_loader/program/src/instruction/collect_treasury.rs index bc950d378..af7547e26 100644 --- a/evm_loader/program/src/instruction/collect_treasury.rs +++ b/evm_loader/program/src/instruction/collect_treasury.rs @@ -13,7 +13,7 @@ pub fn process<'a>( accounts: &'a [AccountInfo<'a>], instruction: &[u8], ) -> ProgramResult { - solana_program::msg!("Instruction: Collect treasury"); + log_msg!("Instruction: Collect treasury"); let treasury_index = u32::from_le_bytes(*array_ref![instruction, 0, 4]); diff --git a/evm_loader/program/src/instruction/config_get_chain_count.rs b/evm_loader/program/src/instruction/config_get_chain_count.rs index bc932f2e9..d917b85a6 100644 --- a/evm_loader/program/src/instruction/config_get_chain_count.rs +++ b/evm_loader/program/src/instruction/config_get_chain_count.rs @@ -7,7 +7,7 @@ pub fn process<'a>( _accounts: &'a [AccountInfo<'a>], _instruction: &[u8], ) -> Result<()> { - solana_program::msg!("Instruction: Config Get Chain Count"); + log_msg!("Instruction: Config Get Chain Count"); let count = crate::config::CHAIN_ID_LIST.len(); diff --git a/evm_loader/program/src/instruction/config_get_chain_info.rs b/evm_loader/program/src/instruction/config_get_chain_info.rs index 13b1a397e..157539c8e 100644 --- a/evm_loader/program/src/instruction/config_get_chain_info.rs +++ b/evm_loader/program/src/instruction/config_get_chain_info.rs @@ -7,7 +7,7 @@ pub fn process<'a>( _accounts: &'a [AccountInfo<'a>], instruction: &[u8], ) -> Result<()> { - solana_program::msg!("Instruction: Config Get Chain Info"); + log_msg!("Instruction: Config Get Chain Info"); let bytes = instruction.try_into()?; let index = usize::from_le_bytes(bytes); diff --git a/evm_loader/program/src/instruction/config_get_environment.rs b/evm_loader/program/src/instruction/config_get_environment.rs index e4c8513f7..8a9e08074 100644 --- a/evm_loader/program/src/instruction/config_get_environment.rs +++ b/evm_loader/program/src/instruction/config_get_environment.rs @@ -7,7 +7,7 @@ pub fn process<'a>( _accounts: &'a [AccountInfo<'a>], _instruction: &[u8], ) -> Result<()> { - solana_program::msg!("Instruction: Config Get Environment"); + log_msg!("Instruction: Config Get Environment"); let environment: &str = if cfg!(feature = "mainnet") { "mainnet" diff --git a/evm_loader/program/src/instruction/config_get_property_by_index.rs b/evm_loader/program/src/instruction/config_get_property_by_index.rs index 19c6d6e31..ac9f62627 100644 --- a/evm_loader/program/src/instruction/config_get_property_by_index.rs +++ b/evm_loader/program/src/instruction/config_get_property_by_index.rs @@ -7,7 +7,7 @@ pub fn process<'a>( _accounts: &'a [AccountInfo<'a>], instruction: &[u8], ) -> Result<()> { - solana_program::msg!("Instruction: Config Get Property by Index"); + log_msg!("Instruction: Config Get Property by Index"); let bytes = instruction.try_into()?; let index = usize::from_le_bytes(bytes); diff --git a/evm_loader/program/src/instruction/config_get_property_by_name.rs b/evm_loader/program/src/instruction/config_get_property_by_name.rs index 3937c7c69..e4397b2e9 100644 --- a/evm_loader/program/src/instruction/config_get_property_by_name.rs +++ b/evm_loader/program/src/instruction/config_get_property_by_name.rs @@ -7,7 +7,7 @@ pub fn process<'a>( _accounts: &'a [AccountInfo<'a>], instruction: &[u8], ) -> Result<()> { - solana_program::msg!("Instruction: Config Get Property by Name"); + log_msg!("Instruction: Config Get Property by Name"); let requested_property = std::str::from_utf8(instruction)?; diff --git a/evm_loader/program/src/instruction/config_get_property_count.rs b/evm_loader/program/src/instruction/config_get_property_count.rs index c246b6b0a..2732f22f2 100644 --- a/evm_loader/program/src/instruction/config_get_property_count.rs +++ b/evm_loader/program/src/instruction/config_get_property_count.rs @@ -7,7 +7,7 @@ pub fn process<'a>( _accounts: &'a [AccountInfo<'a>], _instruction: &[u8], ) -> Result<()> { - solana_program::msg!("Instruction: Config Get Property Count"); + log_msg!("Instruction: Config Get Property Count"); let count = crate::config::PARAMETERS.len(); diff --git a/evm_loader/program/src/instruction/config_get_status.rs b/evm_loader/program/src/instruction/config_get_status.rs index 42c5b9af0..158e2c46d 100644 --- a/evm_loader/program/src/instruction/config_get_status.rs +++ b/evm_loader/program/src/instruction/config_get_status.rs @@ -7,7 +7,7 @@ pub fn process<'a>( _accounts: &'a [AccountInfo<'a>], _instruction: &[u8], ) -> Result<()> { - solana_program::msg!("Instruction: Config Get Status"); + log_msg!("Instruction: Config Get Status"); if cfg!(feature = "emergency") { solana_program::program::set_return_data(&[0]); diff --git a/evm_loader/program/src/instruction/config_get_version.rs b/evm_loader/program/src/instruction/config_get_version.rs index 3d16b2b52..9d0b0dc1a 100644 --- a/evm_loader/program/src/instruction/config_get_version.rs +++ b/evm_loader/program/src/instruction/config_get_version.rs @@ -10,7 +10,7 @@ pub fn process<'a>( _accounts: &'a [AccountInfo<'a>], _instruction: &[u8], ) -> Result<()> { - solana_program::msg!("Instruction: Config Get Version"); + log_msg!("Instruction: Config Get Version"); let version = std::str::from_utf8(&NEON_PKG_VERSION)?; let revision = std::str::from_utf8(&NEON_REVISION)?; diff --git a/evm_loader/program/src/instruction/create_main_treasury.rs b/evm_loader/program/src/instruction/create_main_treasury.rs index 86c5f7972..1378551ad 100644 --- a/evm_loader/program/src/instruction/create_main_treasury.rs +++ b/evm_loader/program/src/instruction/create_main_treasury.rs @@ -6,10 +6,11 @@ use crate::{ use solana_program::{ account_info::AccountInfo, bpf_loader_upgradeable::{self, UpgradeableLoaderState}, - msg, program_pack::Pack, pubkey::Pubkey, + rent::Rent, system_program, + sysvar::Sysvar, }; struct Accounts<'a> { @@ -69,7 +70,7 @@ pub fn process<'a>( accounts: &'a [AccountInfo<'a>], _instruction: &[u8], ) -> Result<()> { - msg!("Instruction: Create Main Treasury"); + log_msg!("Instruction: Create Main Treasury"); let accounts = Accounts::from_slice(accounts)?; let (expected_key, bump_seed) = MainTreasury::address(program_id); @@ -120,6 +121,7 @@ pub fn process<'a>( accounts.main_treasury, &[TREASURY_POOL_SEED.as_bytes(), &[bump_seed]], spl_token::state::Account::LEN, + &Rent::get()?, )?; accounts.token_program.create_account( diff --git a/evm_loader/program/src/instruction/neon_tokens_deposit.rs b/evm_loader/program/src/instruction/neon_tokens_deposit.rs index b0ecb80fc..bfab10115 100644 --- a/evm_loader/program/src/instruction/neon_tokens_deposit.rs +++ b/evm_loader/program/src/instruction/neon_tokens_deposit.rs @@ -1,7 +1,7 @@ use arrayref::array_ref; use ethnum::U256; use solana_program::program::invoke_signed; -use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; +use solana_program::{account_info::AccountInfo, pubkey::Pubkey, rent::Rent, sysvar::Sysvar}; use spl_associated_token_account::get_associated_token_address; use crate::account::{program, token, AccountsDB, BalanceAccount, Operator, ACCOUNT_SEED_VERSION}; @@ -42,7 +42,7 @@ pub fn process<'a>( accounts: &'a [AccountInfo<'a>], instruction: &[u8], ) -> Result<()> { - solana_program::msg!("Instruction: Deposit"); + log_msg!("Instruction: Deposit"); let parsed_accounts = Accounts::from_slice(accounts)?; @@ -162,7 +162,9 @@ fn execute(program_id: &Pubkey, accounts: Accounts, address: Address, chain_id: excessive_lamports += crate::account::legacy::update_legacy_accounts(&accounts_db)?; } - let mut balance_account = BalanceAccount::create(address, chain_id, &accounts_db, None)?; + let rent = Rent::get()?; + + let mut balance_account = BalanceAccount::create(address, chain_id, &accounts_db, None, &rent)?; balance_account.mint(deposit)?; **accounts_db.operator().try_borrow_mut_lamports()? += excessive_lamports; diff --git a/evm_loader/program/src/instruction/transaction_cancel.rs b/evm_loader/program/src/instruction/transaction_cancel.rs index 21360e828..bfe195ea5 100644 --- a/evm_loader/program/src/instruction/transaction_cancel.rs +++ b/evm_loader/program/src/instruction/transaction_cancel.rs @@ -1,4 +1,5 @@ use crate::account::{AccountsDB, BalanceAccount, Operator, StateAccount}; +use crate::debug::log_data; use crate::error::{Error, Result}; use crate::gasometer::{CANCEL_TRX_COST, LAST_ITERATION_COST}; use arrayref::array_ref; @@ -10,7 +11,7 @@ pub fn process<'a>( accounts: &'a [AccountInfo<'a>], instruction: &[u8], ) -> Result<()> { - solana_program::msg!("Instruction: Cancel Transaction"); + log_msg!("Instruction: Cancel Transaction"); let transaction_hash = array_ref![instruction, 0, 32]; @@ -18,8 +19,8 @@ pub fn process<'a>( let operator = Operator::from_account(&accounts[1])?; let operator_balance = BalanceAccount::from_account(program_id, accounts[2].clone())?; - solana_program::log::sol_log_data(&[b"HASH", transaction_hash]); - solana_program::log::sol_log_data(&[b"MINER", operator_balance.address().as_bytes()]); + log_data(&[b"HASH", transaction_hash]); + log_data(&[b"MINER", operator_balance.address().as_bytes()]); let accounts_db = AccountsDB::new(&accounts[3..], operator, Some(operator_balance), None, None); let storage = StateAccount::restore(program_id, storage_info, &accounts_db, true)?; @@ -46,7 +47,7 @@ fn execute<'a>( ) -> Result<()> { let used_gas = U256::ZERO; let total_used_gas = storage.gas_used(); - solana_program::log::sol_log_data(&[ + log_data(&[ b"GAS", &used_gas.to_le_bytes(), &total_used_gas.to_le_bytes(), diff --git a/evm_loader/program/src/instruction/transaction_execute.rs b/evm_loader/program/src/instruction/transaction_execute.rs index a55800d5b..9bac6d615 100644 --- a/evm_loader/program/src/instruction/transaction_execute.rs +++ b/evm_loader/program/src/instruction/transaction_execute.rs @@ -2,6 +2,7 @@ use solana_program::pubkey::Pubkey; use crate::account::{AccountsDB, AllocateResult}; use crate::account_storage::ProgramAccountStorage; +use crate::debug::log_data; use crate::error::{Error, Result}; use crate::evm::tracing::NoopEventListener; use crate::evm::Machine; @@ -61,7 +62,7 @@ pub fn execute( return Err(Error::OutOfGas(gas_limit, used_gas)); } - solana_program::log::sol_log_data(&[b"GAS", &used_gas.to_le_bytes(), &used_gas.to_le_bytes()]); + log_data(&[b"GAS", &used_gas.to_le_bytes(), &used_gas.to_le_bytes()]); let gas_cost = used_gas.saturating_mul(gas_price); account_storage.transfer_gas_payment(origin, chain_id, gas_cost)?; diff --git a/evm_loader/program/src/instruction/transaction_execute_from_account.rs b/evm_loader/program/src/instruction/transaction_execute_from_account.rs index 5b28216f6..fbea0adfe 100644 --- a/evm_loader/program/src/instruction/transaction_execute_from_account.rs +++ b/evm_loader/program/src/instruction/transaction_execute_from_account.rs @@ -1,4 +1,5 @@ use crate::account::{program, AccountsDB, BalanceAccount, Holder, Operator, Treasury}; +use crate::debug::log_data; use crate::error::Result; use crate::gasometer::Gasometer; use crate::types::Transaction; @@ -12,7 +13,7 @@ pub fn process<'a>( accounts: &'a [AccountInfo<'a>], instruction: &[u8], ) -> Result<()> { - solana_program::msg!("Instruction: Execute Transaction from Account"); + log_msg!("Instruction: Execute Transaction from Account"); let treasury_index = u32::from_le_bytes(*array_ref![instruction, 0, 4]); @@ -29,8 +30,8 @@ pub fn process<'a>( let origin = trx.recover_caller_address()?; - solana_program::log::sol_log_data(&[b"HASH", &trx.hash()]); - solana_program::log::sol_log_data(&[b"MINER", operator_balance.address().as_bytes()]); + log_data(&[b"HASH", &trx.hash()]); + log_data(&[b"MINER", operator_balance.address().as_bytes()]); let accounts_db = AccountsDB::new( &accounts[5..], diff --git a/evm_loader/program/src/instruction/transaction_execute_from_instruction.rs b/evm_loader/program/src/instruction/transaction_execute_from_instruction.rs index ffe964728..a2cd8117f 100644 --- a/evm_loader/program/src/instruction/transaction_execute_from_instruction.rs +++ b/evm_loader/program/src/instruction/transaction_execute_from_instruction.rs @@ -1,4 +1,5 @@ use crate::account::{program, AccountsDB, BalanceAccount, Operator, Treasury}; +use crate::debug::log_data; use crate::error::Result; use crate::gasometer::Gasometer; use crate::types::Transaction; @@ -12,7 +13,7 @@ pub fn process<'a>( accounts: &'a [AccountInfo<'a>], instruction: &[u8], ) -> Result<()> { - solana_program::msg!("Instruction: Execute Transaction from Instruction"); + log_msg!("Instruction: Execute Transaction from Instruction"); let treasury_index = u32::from_le_bytes(*array_ref![instruction, 0, 4]); let messsage = &instruction[4..]; @@ -25,8 +26,8 @@ pub fn process<'a>( let trx = Transaction::from_rlp(messsage)?; let origin = trx.recover_caller_address()?; - solana_program::log::sol_log_data(&[b"HASH", &trx.hash()]); - solana_program::log::sol_log_data(&[b"MINER", operator_balance.address().as_bytes()]); + log_data(&[b"HASH", &trx.hash()]); + log_data(&[b"MINER", operator_balance.address().as_bytes()]); let accounts_db = AccountsDB::new( &accounts[4..], diff --git a/evm_loader/program/src/instruction/transaction_step.rs b/evm_loader/program/src/instruction/transaction_step.rs index f6ba7d642..83dc853d9 100644 --- a/evm_loader/program/src/instruction/transaction_step.rs +++ b/evm_loader/program/src/instruction/transaction_step.rs @@ -1,6 +1,7 @@ use crate::account::{AccountsDB, AllocateResult, StateAccount}; use crate::account_storage::{AccountStorage, ProgramAccountStorage}; use crate::config::{EVM_STEPS_LAST_ITERATION_MAX, EVM_STEPS_MIN}; +use crate::debug::log_data; use crate::error::{Error, Result}; use crate::evm::tracing::NoopEventListener; use crate::evm::{ExitStatus, Machine}; @@ -103,7 +104,7 @@ fn finalize<'a>( let used_gas = gasometer.used_gas(); let total_used_gas = gasometer.used_gas_total(); - solana_program::log::sol_log_data(&[ + log_data(&[ b"GAS", &used_gas.to_le_bytes(), &total_used_gas.to_le_bytes(), @@ -124,8 +125,6 @@ fn finalize<'a>( } pub fn log_return_value(status: &ExitStatus) { - use solana_program::log::sol_log_data; - let code: u8 = match status { ExitStatus::Stop => 0x11, ExitStatus::Return(_) => 0x12, @@ -134,12 +133,12 @@ pub fn log_return_value(status: &ExitStatus) { ExitStatus::StepLimit => unreachable!(), }; - solana_program::msg!("exit_status={:#04X}", code); // Tests compatibility + log_msg!("exit_status={:#04X}", code); // Tests compatibility if let ExitStatus::Revert(msg) = status { crate::error::print_revert_message(msg); } - sol_log_data(&[b"RETURN", &[code]]); + log_data(&[b"RETURN", &[code]]); } fn serialize_evm_state( diff --git a/evm_loader/program/src/instruction/transaction_step_from_account.rs b/evm_loader/program/src/instruction/transaction_step_from_account.rs index 2697a430b..6d7e21aa5 100644 --- a/evm_loader/program/src/instruction/transaction_step_from_account.rs +++ b/evm_loader/program/src/instruction/transaction_step_from_account.rs @@ -3,7 +3,7 @@ use crate::account::{ program, AccountsDB, BalanceAccount, Holder, Operator, StateAccount, Treasury, TAG_HOLDER, TAG_STATE, TAG_STATE_FINALIZED, }; - +use crate::debug::log_data; use crate::error::{Error, Result}; use crate::gasometer::Gasometer; use crate::instruction::transaction_step::{do_begin, do_continue}; @@ -17,7 +17,7 @@ pub fn process<'a>( accounts: &'a [AccountInfo<'a>], instruction: &[u8], ) -> Result<()> { - solana_program::msg!("Instruction: Begin or Continue Transaction from Account"); + log_msg!("Instruction: Begin or Continue Transaction from Account"); process_inner(program_id, accounts, instruction, false) } @@ -69,8 +69,8 @@ pub fn process_inner<'a>( trx }; - solana_program::log::sol_log_data(&[b"HASH", &trx.hash]); - solana_program::log::sol_log_data(&[b"MINER", miner_address.as_bytes()]); + log_data(&[b"HASH", &trx.hash]); + log_data(&[b"MINER", miner_address.as_bytes()]); let origin = trx.recover_caller_address()?; @@ -101,8 +101,8 @@ pub fn process_inner<'a>( let storage = StateAccount::restore(program_id, holder_or_storage.clone(), &accounts_db, false)?; - solana_program::log::sol_log_data(&[b"HASH", &storage.trx_hash()]); - solana_program::log::sol_log_data(&[b"MINER", miner_address.as_bytes()]); + log_data(&[b"HASH", &storage.trx_hash()]); + log_data(&[b"MINER", miner_address.as_bytes()]); let mut gasometer = Gasometer::new(storage.gas_used(), accounts_db.operator())?; gasometer.record_solana_transaction_cost(); diff --git a/evm_loader/program/src/instruction/transaction_step_from_account_no_chainid.rs b/evm_loader/program/src/instruction/transaction_step_from_account_no_chainid.rs index 041ac6b42..f911b998a 100644 --- a/evm_loader/program/src/instruction/transaction_step_from_account_no_chainid.rs +++ b/evm_loader/program/src/instruction/transaction_step_from_account_no_chainid.rs @@ -6,7 +6,7 @@ pub fn process<'a>( accounts: &'a [AccountInfo<'a>], instruction: &[u8], ) -> Result<()> { - solana_program::msg!("Instruction: Begin or Continue Transaction from Account Without ChainId"); + log_msg!("Instruction: Begin or Continue Transaction from Account Without ChainId"); super::transaction_step_from_account::process_inner(program_id, accounts, instruction, true) } diff --git a/evm_loader/program/src/instruction/transaction_step_from_instruction.rs b/evm_loader/program/src/instruction/transaction_step_from_instruction.rs index 656d8915d..cd41be54a 100644 --- a/evm_loader/program/src/instruction/transaction_step_from_instruction.rs +++ b/evm_loader/program/src/instruction/transaction_step_from_instruction.rs @@ -3,6 +3,7 @@ use crate::account::{ program, AccountsDB, BalanceAccount, Operator, StateAccount, Treasury, TAG_HOLDER, TAG_STATE, TAG_STATE_FINALIZED, }; +use crate::debug::log_data; use crate::error::{Error, Result}; use crate::gasometer::Gasometer; use crate::instruction::transaction_step::{do_begin, do_continue}; @@ -16,7 +17,7 @@ pub fn process<'a>( accounts: &'a [AccountInfo<'a>], instruction: &[u8], ) -> Result<()> { - solana_program::msg!("Instruction: Begin or Continue Transaction from Instruction"); + log_msg!("Instruction: Begin or Continue Transaction from Instruction"); let treasury_index = u32::from_le_bytes(*array_ref![instruction, 0, 4]); let step_count = u64::from(u32::from_le_bytes(*array_ref![instruction, 4, 4])); @@ -52,8 +53,8 @@ pub fn process<'a>( let trx = Transaction::from_rlp(message)?; let origin = trx.recover_caller_address()?; - solana_program::log::sol_log_data(&[b"HASH", &trx.hash()]); - solana_program::log::sol_log_data(&[b"MINER", miner_address.as_bytes()]); + log_data(&[b"HASH", &trx.hash()]); + log_data(&[b"MINER", miner_address.as_bytes()]); let mut gasometer = Gasometer::new(U256::ZERO, accounts_db.operator())?; gasometer.record_solana_transaction_cost(); @@ -69,8 +70,8 @@ pub fn process<'a>( TAG_STATE => { let storage = StateAccount::restore(program_id, storage_info, &accounts_db, false)?; - solana_program::log::sol_log_data(&[b"HASH", &storage.trx_hash()]); - solana_program::log::sol_log_data(&[b"MINER", miner_address.as_bytes()]); + log_data(&[b"HASH", &storage.trx_hash()]); + log_data(&[b"MINER", miner_address.as_bytes()]); let mut gasometer = Gasometer::new(storage.gas_used(), accounts_db.operator())?; gasometer.record_solana_transaction_cost(); From 3a179a973ada2c5c2c803f3294bb7e75d768fe63 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Thu, 22 Feb 2024 10:44:24 +0300 Subject: [PATCH 091/318] Add Account Revision (#276) * Add account revision --- evm_loader/cli/src/main.rs | 4 +- evm_loader/lib/src/account_storage.rs | 54 ++- evm_loader/lib/src/account_update.rs | 45 +++ evm_loader/lib/src/commands/cancel_trx.rs | 34 +- evm_loader/lib/src/commands/emulate.rs | 6 +- evm_loader/lib/src/commands/get_balance.rs | 7 +- evm_loader/lib/src/commands/get_config.rs | 12 + evm_loader/lib/src/commands/get_contract.rs | 4 +- evm_loader/lib/src/commands/get_holder.rs | 32 +- evm_loader/lib/src/lib.rs | 1 + evm_loader/program/src/account/holder.rs | 4 +- evm_loader/program/src/account/legacy/mod.rs | 45 ++- .../program/src/account/legacy/update.rs | 34 ++ evm_loader/program/src/account/mod.rs | 53 +-- evm_loader/program/src/account/state.rs | 356 +++++++----------- .../program/src/account/state_finalized.rs | 25 +- .../program/src/account_storage/apply.rs | 46 ++- .../program/src/account_storage/base.rs | 14 +- evm_loader/program/src/entrypoint.rs | 3 - evm_loader/program/src/evm/mod.rs | 32 +- evm_loader/program/src/executor/action.rs | 109 +----- evm_loader/program/src/executor/state.rs | 3 +- .../src/instruction/account_block_add.rs | 50 --- evm_loader/program/src/instruction/mod.rs | 5 - .../src/instruction/transaction_cancel.rs | 15 +- .../src/instruction/transaction_execute.rs | 22 +- .../transaction_execute_from_account.rs | 1 - .../transaction_execute_from_instruction.rs | 1 - .../src/instruction/transaction_step.rs | 57 +-- .../transaction_step_from_account.rs | 31 +- .../transaction_step_from_instruction.rs | 16 +- evm_loader/program/src/types/mod.rs | 1 + evm_loader/program/src/types/serde.rs | 130 +++++++ evm_loader/program/src/types/transaction.rs | 92 ++++- 34 files changed, 735 insertions(+), 609 deletions(-) create mode 100644 evm_loader/lib/src/account_update.rs create mode 100644 evm_loader/program/src/account/legacy/update.rs delete mode 100644 evm_loader/program/src/instruction/account_block_add.rs create mode 100644 evm_loader/program/src/types/serde.rs diff --git a/evm_loader/cli/src/main.rs b/evm_loader/cli/src/main.rs index 36d6b16d7..3f3210849 100644 --- a/evm_loader/cli/src/main.rs +++ b/evm_loader/cli/src/main.rs @@ -90,12 +90,12 @@ async fn run(options: &ArgMatches<'_>) -> NeonCliResult { .map(|result| json!(result)) } ("cancel-trx", Some(params)) => { - let rpc_client = config.build_solana_rpc_client(); + let rpc_client = config.build_clone_solana_rpc_client(); let signer = build_signer(config)?; let storage_account = pubkey_of(params, "storage_account").expect("storage_account parse error"); - cancel_trx::execute(&rpc_client, &*signer, config.evm_loader, &storage_account) + cancel_trx::execute(rpc_client, &*signer, config.evm_loader, &storage_account) .await .map(|result| json!(result)) } diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index eaa6ed55a..9720c6bb1 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -1,9 +1,10 @@ use async_trait::async_trait; use evm_loader::account::legacy::{ - LegacyEtherData, LegacyStorageData, TAG_ACCOUNT_CONTRACT_DEPRECATED, - TAG_STORAGE_CELL_DEPRECATED, + LegacyEtherData, LegacyStorageData, ACCOUNT_PREFIX_LEN_BEFORE_REVISION, + TAG_ACCOUNT_BALANCE_BEFORE_REVISION, TAG_ACCOUNT_CONTRACT_BEFORE_REVISION, + TAG_ACCOUNT_CONTRACT_DEPRECATED, TAG_STORAGE_CELL_BEFORE_REVISION, TAG_STORAGE_CELL_DEPRECATED, }; -use evm_loader::account::{TAG_ACCOUNT_CONTRACT, TAG_STORAGE_CELL}; +use evm_loader::account::{ACCOUNT_PREFIX_LEN, TAG_ACCOUNT_CONTRACT, TAG_STORAGE_CELL}; use evm_loader::account_storage::find_slot_hash; use evm_loader::types::Address; use solana_sdk::rent::Rent; @@ -12,6 +13,8 @@ use solana_sdk::sysvar::slot_hashes; use std::collections::HashSet; use std::{cell::RefCell, collections::HashMap, convert::TryInto, rc::Rc}; +use crate::account_update::update_account; +use crate::NeonResult; use crate::{rpc::Rpc, NeonError}; use ethnum::U256; use evm_loader::{ @@ -172,9 +175,13 @@ impl EmulatorAccountStorage<'_, T> { address: Address, chain_id: u64, is_writable: bool, - ) -> client_error::Result<(Pubkey, Option, Option)> { + ) -> NeonResult<(Pubkey, Option, Option)> { let (pubkey, _) = address.find_balance_address(self.program_id(), chain_id); - let account = self.use_account(pubkey, is_writable).await?; + let mut account = self.use_account(pubkey, is_writable).await?; + + if let Some(account) = &mut account { + update_account(&self.program_id, &pubkey, account)?; + } let legacy_account = if account.is_none() && (chain_id == self.default_chain_id()) { let (legacy_pubkey, _) = address.find_solana_address(self.program_id()); @@ -190,9 +197,13 @@ impl EmulatorAccountStorage<'_, T> { &self, address: Address, is_writable: bool, - ) -> client_error::Result<(Pubkey, Option)> { + ) -> NeonResult<(Pubkey, Option)> { let (pubkey, _) = address.find_solana_address(self.program_id()); - let account = self.use_account(pubkey, is_writable).await?; + let mut account = self.use_account(pubkey, is_writable).await?; + + if let Some(account) = &mut account { + update_account(&self.program_id, &pubkey, account)?; + } Ok((pubkey, account)) } @@ -202,14 +213,18 @@ impl EmulatorAccountStorage<'_, T> { address: Address, index: U256, is_writable: bool, - ) -> client_error::Result<(Pubkey, Option)> { + ) -> NeonResult<(Pubkey, Option)> { let (base, _) = address.find_solana_address(self.program_id()); let cell_address = StorageCellAddress::new(self.program_id(), &base, &index); - let account = self + let mut account = self .use_account(*cell_address.pubkey(), is_writable) .await?; + if let Some(account) = &mut account { + update_account(&self.program_id, cell_address.pubkey(), account)?; + } + Ok((*cell_address.pubkey(), account)) } @@ -368,6 +383,27 @@ impl EmulatorAccountStorage<'_, T> { self.gas = self.gas.saturating_add(lamports); } } + + if matches!( + tag, + TAG_ACCOUNT_BALANCE_BEFORE_REVISION + | TAG_ACCOUNT_CONTRACT_BEFORE_REVISION + | TAG_STORAGE_CELL_BEFORE_REVISION + ) { + const PREFIX_BEFORE: usize = ACCOUNT_PREFIX_LEN_BEFORE_REVISION; + const PREFIX_AFTER: usize = ACCOUNT_PREFIX_LEN; + const EXPANSION_LEN: usize = PREFIX_AFTER - PREFIX_BEFORE; + + account.is_writable = true; + account.is_legacy = true; + + let lamports = self + .rent + .minimum_balance(EXPANSION_LEN) + .saturating_sub(self.rent.minimum_balance(0)); + + self.gas = self.gas.saturating_add(lamports); + } } for a in additional_balances { diff --git a/evm_loader/lib/src/account_update.rs b/evm_loader/lib/src/account_update.rs new file mode 100644 index 000000000..9927fb020 --- /dev/null +++ b/evm_loader/lib/src/account_update.rs @@ -0,0 +1,45 @@ +use evm_loader::account::{ + legacy::{ + ACCOUNT_PREFIX_LEN_BEFORE_REVISION, TAG_ACCOUNT_BALANCE_BEFORE_REVISION, + TAG_ACCOUNT_CONTRACT_BEFORE_REVISION, TAG_STORAGE_CELL_BEFORE_REVISION, + }, + ACCOUNT_PREFIX_LEN, TAG_ACCOUNT_BALANCE, TAG_ACCOUNT_CONTRACT, TAG_STORAGE_CELL, +}; +use solana_sdk::{account::Account, pubkey::Pubkey}; + +use crate::{account_storage::account_info, NeonResult}; + +fn from_before_revision(account: &mut Account, new_tag: u8) { + const PREFIX_BEFORE: usize = ACCOUNT_PREFIX_LEN_BEFORE_REVISION; + const PREFIX_AFTER: usize = ACCOUNT_PREFIX_LEN; + + assert!(account.data.len() > PREFIX_BEFORE); + + let required_len = account.data.len() + PREFIX_AFTER - PREFIX_BEFORE; + account.data.resize(required_len, 0); + + account.data.copy_within(PREFIX_BEFORE.., PREFIX_AFTER); + account.data[0] = new_tag; +} + +pub fn update_account(program_id: &Pubkey, key: &Pubkey, account: &mut Account) -> NeonResult<()> { + let tag = { + let info = account_info(key, account); + evm_loader::account::tag(program_id, &info)? + }; + + match tag { + TAG_ACCOUNT_BALANCE_BEFORE_REVISION => { + from_before_revision(account, TAG_ACCOUNT_BALANCE); + } + TAG_ACCOUNT_CONTRACT_BEFORE_REVISION => { + from_before_revision(account, TAG_ACCOUNT_CONTRACT); + } + TAG_STORAGE_CELL_BEFORE_REVISION => { + from_before_revision(account, TAG_STORAGE_CELL); + } + _ => {} + } + + Ok(()) +} diff --git a/evm_loader/lib/src/commands/cancel_trx.rs b/evm_loader/lib/src/commands/cancel_trx.rs index 22e288c41..f68ee6441 100644 --- a/evm_loader/lib/src/commands/cancel_trx.rs +++ b/evm_loader/lib/src/commands/cancel_trx.rs @@ -2,7 +2,6 @@ use evm_loader::account::StateAccount; use log::info; use serde::{Deserialize, Serialize}; -use solana_client::nonblocking::rpc_client::RpcClient; use solana_sdk::{ instruction::{AccountMeta, Instruction}, pubkey::Pubkey, @@ -10,7 +9,9 @@ use solana_sdk::{ signer::Signer, }; -use crate::{account_storage::account_info, commands::send_transaction, NeonResult}; +use crate::{ + account_storage::account_info, commands::send_transaction, rpc::CloneRpcClient, NeonResult, +}; #[derive(Debug, Serialize, Deserialize)] pub struct CancelTrxReturn { @@ -18,20 +19,23 @@ pub struct CancelTrxReturn { } pub async fn execute( - rpc_client: &RpcClient, + rpc_client: CloneRpcClient, signer: &dyn Signer, - evm_loader: Pubkey, + program_id: Pubkey, storage_account: &Pubkey, ) -> NeonResult { let mut acc = rpc_client.get_account(storage_account).await?; let storage_info = account_info(storage_account, &mut acc); - let storage = StateAccount::from_account(&evm_loader, storage_info)?; + let storage = StateAccount::from_account(&program_id, storage_info)?; let operator = &signer.pubkey(); + let default_chain_id = + crate::commands::get_config::read_default_chain_id(&rpc_client, program_id).await?; + let chain_id = storage.trx().chain_id().unwrap_or(default_chain_id); + let origin = storage.trx_origin(); - let chain_id: u64 = storage.trx_chain_id(); - let (origin_pubkey, _) = origin.find_balance_address(&evm_loader, chain_id); + let (origin_pubkey, _) = origin.find_balance_address(&program_id, chain_id); let mut accounts_meta: Vec = vec![ AccountMeta::new(*storage_account, false), // State account @@ -39,23 +43,19 @@ pub async fn execute( AccountMeta::new(origin_pubkey, false), ]; - for blocked_account_meta in storage.blocked_accounts().iter() { - if blocked_account_meta.is_writable { - accounts_meta.push(AccountMeta::new(blocked_account_meta.key, false)); - } else { - accounts_meta.push(AccountMeta::new_readonly(blocked_account_meta.key, false)); - } - } - for meta in &accounts_meta { + for key in storage.accounts() { + let meta = AccountMeta::new(*key, true); info!("\t{:?}", meta); + + accounts_meta.push(meta); } let cancel_with_nonce_instruction = - Instruction::new_with_bincode(evm_loader, &(0x37_u8, storage.trx_hash()), accounts_meta); + Instruction::new_with_bincode(program_id, &(0x37_u8, storage.trx().hash()), accounts_meta); let instructions = vec![cancel_with_nonce_instruction]; - let signature = send_transaction(rpc_client, signer, &instructions).await?; + let signature = send_transaction(&rpc_client, signer, &instructions).await?; Ok(CancelTrxReturn { transaction: signature, diff --git a/evm_loader/lib/src/commands/emulate.rs b/evm_loader/lib/src/commands/emulate.rs index 05b76c922..6501b0c82 100644 --- a/evm_loader/lib/src/commands/emulate.rs +++ b/evm_loader/lib/src/commands/emulate.rs @@ -1,4 +1,5 @@ use evm_loader::account::ContractAccount; +use evm_loader::account_storage::AccountStorage; use evm_loader::error::build_revert_message; use log::{debug, info}; use serde::{Deserialize, Serialize}; @@ -93,8 +94,11 @@ async fn emulate_trx( info!("origin: {:?}", origin); info!("tx: {:?}", tx); + let chain_id = tx.chain_id().unwrap_or_else(|| storage.default_chain_id()); + storage.use_balance_account(origin, chain_id, true).await?; + let mut backend = ExecutorState::new(storage); - let mut evm = match Machine::new(tx, origin, &mut backend, tracer).await { + let mut evm = match Machine::new(&tx, origin, &mut backend, tracer).await { Ok(evm) => evm, Err(e) => return Ok((EmulateResponse::revert(e), None)), }; diff --git a/evm_loader/lib/src/commands/get_balance.rs b/evm_loader/lib/src/commands/get_balance.rs index e9d6561a9..4879dd1c9 100644 --- a/evm_loader/lib/src/commands/get_balance.rs +++ b/evm_loader/lib/src/commands/get_balance.rs @@ -4,7 +4,10 @@ use evm_loader::account::BalanceAccount; use serde::{Deserialize, Serialize}; use solana_sdk::{account::Account, pubkey::Pubkey}; -use crate::{account_storage::account_info, rpc::Rpc, types::BalanceAddress, NeonResult}; +use crate::{ + account_storage::account_info, account_update::update_account, rpc::Rpc, types::BalanceAddress, + NeonResult, +}; use serde_with::{serde_as, DisplayFromStr}; @@ -48,6 +51,8 @@ fn read_account( ) -> NeonResult { let solana_address = address.find_pubkey(program_id); + update_account(program_id, &solana_address, &mut account)?; + let account_info = account_info(&solana_address, &mut account); let balance_account = BalanceAccount::from_account(program_id, account_info)?; diff --git a/evm_loader/lib/src/commands/get_config.rs b/evm_loader/lib/src/commands/get_config.rs index 84f2b8b17..3934ce22b 100644 --- a/evm_loader/lib/src/commands/get_config.rs +++ b/evm_loader/lib/src/commands/get_config.rs @@ -357,6 +357,18 @@ pub async fn read_chains( simulator.get_chains().await } +pub async fn read_default_chain_id( + rpc: &impl BuildConfigSimulator, + program_id: Pubkey, +) -> NeonResult { + let mut simulator = rpc.build_config_simulator(program_id).await?; + + let chains = simulator.get_chains().await?; + let default_chain = chains.iter().find(|chain| chain.name == "neon").unwrap(); + + Ok(default_chain.id) +} + impl CloneRpcClient { async fn get_account_with_sol(&self) -> ClientResult { let r = self diff --git a/evm_loader/lib/src/commands/get_contract.rs b/evm_loader/lib/src/commands/get_contract.rs index 6f1a3d324..938a1a4c6 100644 --- a/evm_loader/lib/src/commands/get_contract.rs +++ b/evm_loader/lib/src/commands/get_contract.rs @@ -5,7 +5,7 @@ use evm_loader::{ use serde::{Deserialize, Serialize}; use solana_sdk::{account::Account, pubkey::Pubkey}; -use crate::{account_storage::account_info, rpc::Rpc, NeonResult}; +use crate::{account_storage::account_info, account_update::update_account, rpc::Rpc, NeonResult}; use serde_with::{hex::Hex, serde_as, DisplayFromStr}; @@ -51,6 +51,8 @@ fn read_account( return Ok(GetContractResponse::empty(solana_address)); }; + update_account(program_id, &solana_address, &mut account)?; + let account_info = account_info(&solana_address, &mut account); let (chain_id, code) = if let Ok(contract) = ContractAccount::from_account(program_id, account_info.clone()) { diff --git a/evm_loader/lib/src/commands/get_holder.rs b/evm_loader/lib/src/commands/get_holder.rs index 1ad6aff13..aa1cddb25 100644 --- a/evm_loader/lib/src/commands/get_holder.rs +++ b/evm_loader/lib/src/commands/get_holder.rs @@ -1,4 +1,3 @@ -use ethnum::U256; use evm_loader::account::{ legacy::{ LegacyFinalizedData, LegacyHolderData, TAG_HOLDER_DEPRECATED, @@ -24,14 +23,6 @@ pub enum Status { Finalized, } -#[serde_as] -#[derive(Debug, Default, Serialize)] -pub struct AccountMeta { - pub is_writable: bool, - #[serde_as(as = "DisplayFromStr")] - pub key: Pubkey, -} - #[serde_as] #[skip_serializing_none] #[derive(Debug, Default, Serialize)] @@ -45,11 +36,8 @@ pub struct GetHolderResponse { pub tx: Option<[u8; 32]>, pub chain_id: Option, - pub gas_price: Option, - pub gas_limit: Option, - pub gas_used: Option, - - pub accounts: Option>, + #[serde_as(as = "Option>")] + pub accounts: Option>, } impl GetHolderResponse { @@ -114,24 +102,14 @@ pub fn read_holder(program_id: &Pubkey, info: AccountInfo) -> NeonResult { let state = StateAccount::from_account(program_id, info)?; - let accounts = state - .blocked_accounts() - .iter() - .map(|a| AccountMeta { - is_writable: a.is_writable, - key: a.key, - }) - .collect(); + let accounts = state.accounts().copied().collect(); Ok(GetHolderResponse { status: Status::Active, len: Some(data_len), owner: Some(state.owner()), - tx: Some(state.trx_hash()), - chain_id: Some(state.trx_chain_id()), - gas_limit: Some(state.trx_gas_limit()), - gas_price: Some(state.trx_gas_price()), - gas_used: Some(state.gas_used()), + tx: Some(state.trx().hash()), + chain_id: state.trx().chain_id(), accounts: Some(accounts), }) } diff --git a/evm_loader/lib/src/lib.rs b/evm_loader/lib/src/lib.rs index d50c2f17b..512257992 100644 --- a/evm_loader/lib/src/lib.rs +++ b/evm_loader/lib/src/lib.rs @@ -1,4 +1,5 @@ pub mod account_storage; +pub mod account_update; pub mod build_info; pub mod build_info_common; pub mod commands; diff --git a/evm_loader/program/src/account/holder.rs b/evm_loader/program/src/account/holder.rs index cb12fc852..2d015555d 100644 --- a/evm_loader/program/src/account/holder.rs +++ b/evm_loader/program/src/account/holder.rs @@ -7,7 +7,7 @@ use crate::account::TAG_STATE_FINALIZED; use crate::error::{Error, Result}; use crate::types::Transaction; -use super::{Operator, ACCOUNT_PREFIX_LEN, TAG_EMPTY, TAG_HOLDER}; +use super::{Operator, HOLDER_PREFIX_LEN, TAG_EMPTY, TAG_HOLDER}; /// Ethereum holder data account #[repr(C, packed)] @@ -21,7 +21,7 @@ pub struct Holder<'a> { account: AccountInfo<'a>, } -const HEADER_OFFSET: usize = ACCOUNT_PREFIX_LEN; +const HEADER_OFFSET: usize = HOLDER_PREFIX_LEN; const BUFFER_OFFSET: usize = HEADER_OFFSET + size_of::
(); impl<'a> Holder<'a> { diff --git a/evm_loader/program/src/account/legacy/mod.rs b/evm_loader/program/src/account/legacy/mod.rs index 414ad4e65..2a92e275c 100644 --- a/evm_loader/program/src/account/legacy/mod.rs +++ b/evm_loader/program/src/account/legacy/mod.rs @@ -1,6 +1,7 @@ mod legacy_ether; mod legacy_holder; mod legacy_storage_cell; +mod update; pub use legacy_ether::LegacyEtherData; pub use legacy_holder::LegacyFinalizedData; @@ -12,6 +13,8 @@ use solana_program::{account_info::AccountInfo, rent::Rent, sysvar::Sysvar}; use super::Holder; use super::StateFinalizedAccount; +use super::TAG_ACCOUNT_BALANCE; +use super::TAG_ACCOUNT_CONTRACT; use super::TAG_HOLDER; use super::TAG_STATE_FINALIZED; use super::{AccountsDB, ContractAccount, TAG_STORAGE_CELL}; @@ -21,11 +24,19 @@ use crate::{ error::Result, }; +// First version pub const TAG_STATE_DEPRECATED: u8 = 22; pub const TAG_STATE_FINALIZED_DEPRECATED: u8 = 31; pub const TAG_HOLDER_DEPRECATED: u8 = 51; pub const TAG_ACCOUNT_CONTRACT_DEPRECATED: u8 = 12; pub const TAG_STORAGE_CELL_DEPRECATED: u8 = 42; +// Before account revision (Holder and Finalized remain the same) +pub const TAG_STATE_BEFORE_REVISION: u8 = 23; +pub const TAG_ACCOUNT_BALANCE_BEFORE_REVISION: u8 = 60; +pub const TAG_ACCOUNT_CONTRACT_BEFORE_REVISION: u8 = 70; +pub const TAG_STORAGE_CELL_BEFORE_REVISION: u8 = 43; + +pub const ACCOUNT_PREFIX_LEN_BEFORE_REVISION: usize = 2; fn reduce_account_size(account: &AccountInfo, required_len: usize, rent: &Rent) -> Result { assert!(account.data_len() > required_len); @@ -54,7 +65,7 @@ fn kill_account(account: &AccountInfo) -> Result { Ok(value) } -fn update_ether_account( +fn update_ether_account_from_v1( legacy_data: &LegacyEtherData, db: &AccountsDB, keys: &KeysCache, @@ -89,8 +100,6 @@ fn update_ether_account( Some(keys), )?; contract.set_storage_multiple_values(0, &storage); - - super::set_block(&crate::ID, account, legacy_data.rw_blocked)?; } else { // This is not contract. Just kill it. lamports_collected += kill_account(account)?; @@ -107,14 +116,12 @@ fn update_ether_account( )?; balance.mint(legacy_data.balance)?; balance.increment_nonce_by(legacy_data.trx_count)?; - - super::set_block(&crate::ID, db.get(balance.pubkey()), legacy_data.rw_blocked)?; } Ok(lamports_collected) } -fn update_storage_account( +fn update_storage_account_from_v1( legacy_data: &LegacyStorageData, db: &AccountsDB, keys: &KeysCache, @@ -157,7 +164,6 @@ pub fn update_holder_account(account: &AccountInfo) -> Result { let legacy_data = LegacyHolderData::from_account(&crate::ID, account)?; super::set_tag(&crate::ID, account, TAG_HOLDER)?; - super::set_block(&crate::ID, account, false)?; let mut holder = Holder::from_account(&crate::ID, account.clone())?; holder.update(|data| { @@ -172,7 +178,6 @@ pub fn update_holder_account(account: &AccountInfo) -> Result { let legacy_data = LegacyFinalizedData::from_account(&crate::ID, account)?; super::set_tag(&crate::ID, account, TAG_STATE_FINALIZED)?; - super::set_block(&crate::ID, account, false)?; let mut state = StateFinalizedAccount::from_account(&crate::ID, account.clone())?; state.update(|data| { @@ -189,11 +194,13 @@ pub fn update_holder_account(account: &AccountInfo) -> Result { pub fn update_legacy_accounts(accounts: &AccountsDB) -> Result { let keys = KeysCache::new(); - let rent = Rent::get()?; - let mut lamports_collected = 0_u64; let mut legacy_storage = Vec::with_capacity(accounts.accounts_len()); + let rent = Rent::get()?; + let op = accounts.operator(); + let system = accounts.system(); + for account in accounts { if !crate::check_id(account.owner) { continue; @@ -207,18 +214,28 @@ pub fn update_legacy_accounts(accounts: &AccountsDB) -> Result { match tag { LegacyEtherData::TAG => { let legacy_data = LegacyEtherData::from_account(&crate::ID, account)?; - lamports_collected += update_ether_account(&legacy_data, accounts, &keys, &rent)?; + lamports_collected += + update_ether_account_from_v1(&legacy_data, accounts, &keys, &rent)?; } LegacyStorageData::TAG => { let legacy_data = LegacyStorageData::from_account(&crate::ID, account)?; legacy_storage.push(legacy_data); } + TAG_ACCOUNT_BALANCE_BEFORE_REVISION => { + update::from_before_revision(account, TAG_ACCOUNT_BALANCE, op, system, &rent)?; + } + TAG_ACCOUNT_CONTRACT_BEFORE_REVISION => { + update::from_before_revision(account, TAG_ACCOUNT_CONTRACT, op, system, &rent)?; + } + TAG_STORAGE_CELL_BEFORE_REVISION => { + update::from_before_revision(account, TAG_STORAGE_CELL, op, system, &rent)?; + } _ => {} } } for data in legacy_storage { - lamports_collected += update_storage_account(&data, accounts, &keys, &rent)?; + lamports_collected += update_storage_account_from_v1(&data, accounts, &keys, &rent)?; } Ok(lamports_collected) @@ -233,5 +250,9 @@ pub fn is_legacy_tag(tag: u8) -> bool { | TAG_HOLDER_DEPRECATED | TAG_STATE_FINALIZED_DEPRECATED | TAG_STATE_DEPRECATED + | TAG_STATE_BEFORE_REVISION + | TAG_ACCOUNT_BALANCE_BEFORE_REVISION + | TAG_ACCOUNT_CONTRACT_BEFORE_REVISION + | TAG_STORAGE_CELL_BEFORE_REVISION ) } diff --git a/evm_loader/program/src/account/legacy/update.rs b/evm_loader/program/src/account/legacy/update.rs new file mode 100644 index 000000000..19670df64 --- /dev/null +++ b/evm_loader/program/src/account/legacy/update.rs @@ -0,0 +1,34 @@ +use crate::account::legacy::ACCOUNT_PREFIX_LEN_BEFORE_REVISION; +use solana_program::account_info::AccountInfo; +use solana_program::rent::Rent; + +use crate::account::program::System; +use crate::account::Operator; +use crate::account::ACCOUNT_PREFIX_LEN; +use crate::error::Result; + +pub fn from_before_revision<'a>( + account: &AccountInfo<'a>, + new_tag: u8, + operator: &Operator<'a>, + system: &System<'a>, + rent: &Rent, +) -> Result<()> { + const PREFIX_BEFORE: usize = ACCOUNT_PREFIX_LEN_BEFORE_REVISION; + const PREFIX_AFTER: usize = ACCOUNT_PREFIX_LEN; + + let required_len = account.data_len() + PREFIX_AFTER - PREFIX_BEFORE; + account.realloc(required_len, false)?; + + let minimum_balance = rent.minimum_balance(account.data_len()); + if account.lamports() < minimum_balance { + let required_lamports = minimum_balance - account.lamports(); + system.transfer(operator, account, required_lamports)?; + } + + let mut account_data = account.try_borrow_mut_data()?; + account_data[0] = new_tag; + account_data.copy_within(PREFIX_BEFORE.., PREFIX_AFTER); + + Ok(()) +} diff --git a/evm_loader/program/src/account/mod.rs b/evm_loader/program/src/account/mod.rs index 8ba611a8c..0be5568cd 100644 --- a/evm_loader/program/src/account/mod.rs +++ b/evm_loader/program/src/account/mod.rs @@ -6,13 +6,13 @@ use std::cell::{Ref, RefMut}; pub use crate::config::ACCOUNT_SEED_VERSION; -pub use ether_balance::BalanceAccount; -pub use ether_contract::{AllocateResult, ContractAccount}; +pub use ether_balance::{BalanceAccount, Header as BalanceHeader}; +pub use ether_contract::{AllocateResult, ContractAccount, Header as ContractHeader}; pub use ether_storage::{StorageCell, StorageCellAddress}; pub use holder::Holder; pub use incinerator::Incinerator; pub use operator::Operator; -pub use state::StateAccount; +pub use state::{AccountsStatus, StateAccount}; pub use state_finalized::StateFinalizedAccount; pub use treasury::{MainTreasury, Treasury}; @@ -32,15 +32,16 @@ pub mod token; mod treasury; pub const TAG_EMPTY: u8 = 0; -pub const TAG_STATE: u8 = 23; +pub const TAG_STATE: u8 = 24; pub const TAG_STATE_FINALIZED: u8 = 32; pub const TAG_HOLDER: u8 = 52; -pub const TAG_ACCOUNT_BALANCE: u8 = 60; -pub const TAG_ACCOUNT_CONTRACT: u8 = 70; -pub const TAG_STORAGE_CELL: u8 = 43; +pub const TAG_ACCOUNT_BALANCE: u8 = 61; +pub const TAG_ACCOUNT_CONTRACT: u8 = 71; +pub const TAG_STORAGE_CELL: u8 = 44; -const ACCOUNT_PREFIX_LEN: usize = 2; +pub const ACCOUNT_PREFIX_LEN: usize = 1/*tag*/ + 4/*revision*/; +pub const HOLDER_PREFIX_LEN: usize = 1/*tag*/ + 1/*reserved*/; #[inline] fn section<'r, T>(account: &'r AccountInfo<'_>, offset: usize) -> Ref<'r, T> { @@ -106,7 +107,7 @@ pub fn validate_tag(program_id: &Pubkey, info: &AccountInfo, tag: u8) -> Result< } } -pub fn is_blocked(program_id: &Pubkey, info: &AccountInfo) -> Result { +pub fn revision(program_id: &Pubkey, info: &AccountInfo) -> Result { if info.owner != program_id { return Err(Error::AccountInvalidOwner(*info.key, *program_id)); } @@ -116,43 +117,27 @@ pub fn is_blocked(program_id: &Pubkey, info: &AccountInfo) -> Result { return Err(Error::AccountInvalidData(*info.key)); } - if legacy::is_legacy_tag(data[0]) { - return Err(Error::AccountLegacy(*info.key)); - } - - Ok(data[1] == 1) + let buffer = arrayref::array_ref![data, 1, 4]; + Ok(u32::from_le_bytes(*buffer)) } -#[inline] -fn set_block(program_id: &Pubkey, info: &AccountInfo, block: bool) -> Result<()> { - assert_eq!(info.owner, program_id); +pub fn increment_revision(program_id: &Pubkey, info: &AccountInfo) -> Result<()> { + if info.owner != program_id { + return Err(Error::AccountInvalidOwner(*info.key, *program_id)); + } let mut data = info.try_borrow_mut_data()?; if data.len() < ACCOUNT_PREFIX_LEN { return Err(Error::AccountInvalidData(*info.key)); } - if legacy::is_legacy_tag(data[0]) { - return Err(Error::AccountLegacy(*info.key)); - } - - if block && (data[1] != 0) { - return Err(Error::AccountBlocked(*info.key)); - } - - data[1] = block.into(); + let buffer = arrayref::array_mut_ref![data, 1, 4]; + let revision = u32::from_le_bytes(*buffer); + *buffer = (revision + 1).to_le_bytes(); Ok(()) } -pub fn block(program_id: &Pubkey, info: &AccountInfo) -> Result<()> { - set_block(program_id, info, true) -} - -pub fn unblock(program_id: &Pubkey, info: &AccountInfo) -> Result<()> { - set_block(program_id, info, false) -} - /// # Safety /// *Permanently delete all data* in the account. Transfer lamports to the operator. pub unsafe fn delete(account: &AccountInfo, operator: &Operator) { diff --git a/evm_loader/program/src/account/state.rs b/evm_loader/program/src/account/state.rs index 53d22e382..f4e7b147f 100644 --- a/evm_loader/program/src/account/state.rs +++ b/evm_loader/program/src/account/state.rs @@ -1,66 +1,72 @@ use std::cell::{Ref, RefMut}; +use std::collections::BTreeMap; use std::mem::size_of; -use crate::config::GAS_LIMIT_MULTIPLIER_NO_CHAINID; +use crate::account_storage::AccountStorage; +use crate::config::DEFAULT_CHAIN_ID; use crate::error::{Error, Result}; use crate::types::{Address, Transaction}; use ethnum::U256; -use solana_program::clock::Clock; -use solana_program::program_error::ProgramError; -use solana_program::sysvar::Sysvar; +use serde::{Deserialize, Serialize}; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; use super::{ - AccountsDB, BalanceAccount, Operator, ACCOUNT_PREFIX_LEN, TAG_EMPTY, TAG_HOLDER, TAG_STATE, - TAG_STATE_FINALIZED, + revision, AccountsDB, BalanceAccount, Holder, StateFinalizedAccount, HOLDER_PREFIX_LEN, + TAG_HOLDER, TAG_STATE, TAG_STATE_FINALIZED, }; +#[derive(PartialEq, Eq)] +pub enum AccountsStatus { + Ok, + RevisionChanged, +} + /// Storage data account to store execution metainfo between steps for iterative execution -#[repr(C, packed)] -pub struct Header { +#[derive(Serialize, Deserialize)] +struct Data { pub owner: Pubkey, - pub transaction_hash: [u8; 32], + pub transaction: Transaction, /// Ethereum transaction caller address pub origin: Address, - /// Ethereum transaction chain_id - pub chain_id: u64, - /// Ethereum transaction gas limit - pub gas_limit: U256, - /// Ethereum transaction gas price - pub gas_price: U256, + /// Stored accounts + pub revisions: BTreeMap, /// Ethereum transaction gas used and paid + #[serde(with = "ethnum::serde::bytes::le")] pub gas_used: U256, - /// Operator public key - pub operator: Pubkey, - /// Starting slot for this operator - pub slot: u64, - /// Stored accounts length - pub accounts_len: usize, - /// Stored EVM State length - pub evm_state_len: usize, - /// Stored EVM Machine length - pub evm_machine_len: usize, } #[repr(C, packed)] -pub struct BlockedAccount { - pub is_writable: bool, - pub blocked: bool, - pub key: Pubkey, +struct Header { + pub evm_state_len: usize, + pub evm_machine_len: usize, + pub data_len: usize, } pub struct StateAccount<'a> { account: AccountInfo<'a>, + data: Data, } -const HEADER_OFFSET: usize = ACCOUNT_PREFIX_LEN; -const BLOCKED_ACCOUNTS_OFFSET: usize = HEADER_OFFSET + size_of::
(); +const HEADER_OFFSET: usize = HOLDER_PREFIX_LEN; +const BUFFER_OFFSET: usize = HEADER_OFFSET + size_of::
(); impl<'a> StateAccount<'a> { pub fn from_account(program_id: &Pubkey, account: AccountInfo<'a>) -> Result { super::validate_tag(program_id, &account, TAG_STATE)?; - Ok(Self { account }) + let (offset, len) = { + let header = super::section::
(&account, HEADER_OFFSET); + let offset = BUFFER_OFFSET + header.evm_state_len + header.evm_machine_len; + (offset, header.data_len) + }; + + let data = { + let account_data = account.try_borrow_data()?; + let buffer = &account_data[offset..(offset + len)]; + bincode::deserialize(buffer)? + }; + + Ok(Self { account, data }) } pub fn new( @@ -68,108 +74,101 @@ impl<'a> StateAccount<'a> { info: AccountInfo<'a>, accounts: &AccountsDB<'a>, origin: Address, - trx: &Transaction, + transaction: Transaction, ) -> Result { - let tag = super::tag(program_id, &info)?; - if matches!(tag, TAG_HOLDER | TAG_STATE_FINALIZED) { - super::set_tag(program_id, &info, TAG_STATE)?; - } - - let mut state = Self::from_account(program_id, info)?; - state.validate_owner(accounts.operator())?; - - if (tag == TAG_STATE_FINALIZED) && (state.trx_hash() == trx.hash) { - return Err(Error::StorageAccountFinalized); - } - - // Set header + let owner = match super::tag(program_id, &info)? { + TAG_HOLDER => { + let holder = Holder::from_account(program_id, info.clone())?; + holder.validate_owner(accounts.operator())?; + holder.owner() + } + TAG_STATE_FINALIZED => { + let finalized = StateFinalizedAccount::from_account(program_id, info.clone())?; + finalized.validate_owner(accounts.operator())?; + finalized.validate_trx(&transaction)?; + finalized.owner() + } + tag => return Err(Error::AccountInvalidTag(*info.key, tag)), + }; + + // todo: get revision from account + let revisions = accounts + .into_iter() + .map(|account| { + let revision = revision(program_id, account).unwrap_or(0); + (*account.key, revision) + }) + .collect(); + + let data = Data { + owner, + transaction, + origin, + revisions, + gas_used: U256::ZERO, + }; + + super::set_tag(program_id, &info, TAG_STATE)?; { - let mut header = state.header_mut(); - header.transaction_hash = trx.hash(); - header.origin = origin; - header.chain_id = trx.chain_id().unwrap_or(crate::config::DEFAULT_CHAIN_ID); - header.gas_limit = trx.gas_limit(); - header.gas_price = trx.gas_price(); - header.gas_used = U256::ZERO; - header.operator = accounts.operator_key(); - header.slot = Clock::get()?.slot; - header.accounts_len = accounts.accounts_len(); - header.evm_machine_len = 0; + // Set header + let mut header = super::section_mut::
(&info, HEADER_OFFSET); header.evm_state_len = 0; - } - // Block accounts - for (block, account) in state.blocked_accounts_mut().iter_mut().zip(accounts) { - block.is_writable = account.is_writable; - block.key = *account.key; - if (account.owner == program_id) && !account.data_is_empty() { - super::block(program_id, account)?; - block.blocked = true; - } else { - block.blocked = false; - } + header.evm_machine_len = 0; + header.data_len = 0; } - Ok(state) + Ok(Self { + account: info, + data, + }) } pub fn restore( program_id: &Pubkey, info: AccountInfo<'a>, accounts: &AccountsDB, - is_canceling: bool, - ) -> Result { + ) -> Result<(Self, AccountsStatus)> { let mut state = Self::from_account(program_id, info)?; - - if state.blocked_accounts_len() != accounts.accounts_len() { - return Err(ProgramError::NotEnoughAccountKeys.into()); - } - - // Check blocked accounts - for (block, account) in state.blocked_accounts().iter().zip(accounts) { - if &block.key != account.key { - return Err(Error::AccountInvalidKey(*account.key, block.key)); - } - - if block.is_writable && !account.is_writable { - return Err(Error::AccountNotWritable(*account.key)); - } - - if !is_canceling && (account.owner == program_id) && !block.blocked { - if super::is_blocked(program_id, account)? { - return Err(Error::AccountCreatedByAnotherTransaction(*account.key)); - } - - super::validate_tag(program_id, account, TAG_EMPTY) - .map_err(|_| Error::AccountCreatedByAnotherTransaction(*account.key))?; + let mut status = AccountsStatus::Ok; + + for account in accounts { + let account_revision = revision(program_id, account).unwrap_or(0); + let stored_revision = state + .data + .revisions + .entry(*account.key) + .or_insert(account_revision); + + if stored_revision != &account_revision { + status = AccountsStatus::RevisionChanged; + *stored_revision = account_revision; } } - state.update_current_operator(&accounts.operator); - - Ok(state) + Ok((state, status)) } - pub fn finalize(self, program_id: &Pubkey, accounts: &AccountsDB) -> Result<()> { + pub fn finalize(self, program_id: &Pubkey) -> Result<()> { debug_print!("Finalize Storage {}", self.account.key); - // Unblock accounts - for (block, account) in self.blocked_accounts().iter().zip(accounts) { - if &block.key != account.key { - return Err(Error::AccountInvalidKey(*account.key, block.key)); - } - - if !block.blocked { - continue; - } - - super::unblock(program_id, account)?; - } + let owner = self.owner(); + let trx_hash = self.trx().hash(); // Change tag to finalized let account = self.account.clone(); std::mem::drop(self); - super::set_tag(account.owner, &account, TAG_STATE_FINALIZED) + super::set_tag(account.owner, &account, TAG_STATE_FINALIZED)?; + StateFinalizedAccount::from_account(program_id, account)?.update(|f| { + f.owner = owner; + f.transaction_hash = trx_hash; + }); + + Ok(()) + } + + pub fn accounts(&self) -> impl Iterator { + self.data.revisions.keys() } #[inline] @@ -184,62 +183,16 @@ impl<'a> StateAccount<'a> { super::section_mut(&self.account, HEADER_OFFSET) } - #[inline] - #[must_use] - fn blocked_accounts_len(&self) -> usize { - self.header().accounts_len - } - - #[inline] - #[must_use] - pub fn blocked_accounts(&self) -> Ref<[BlockedAccount]> { - let accounts_len = self.blocked_accounts_len(); - let accounts_len_bytes = accounts_len * size_of::(); - - let data = self.account.data.borrow(); - Ref::map(data, |d| { - let bytes = &d[BLOCKED_ACCOUNTS_OFFSET..][..accounts_len_bytes]; - - unsafe { - let ptr = bytes.as_ptr().cast(); - std::slice::from_raw_parts(ptr, accounts_len) - } - }) - } - - #[inline] - #[must_use] - fn blocked_accounts_mut(&mut self) -> RefMut<[BlockedAccount]> { - let accounts_len = self.blocked_accounts_len(); - let accounts_len_bytes = accounts_len * size_of::(); - - let data = self.account.data.borrow_mut(); - RefMut::map(data, |d| { - let bytes: &mut [u8] = &mut d[BLOCKED_ACCOUNTS_OFFSET..][..accounts_len_bytes]; - - unsafe { - let ptr = bytes.as_mut_ptr().cast(); - std::slice::from_raw_parts_mut(ptr, accounts_len) - } - }) - } - #[must_use] pub fn buffer(&self) -> Ref<[u8]> { - let accounts_len_bytes = self.blocked_accounts_len() * size_of::(); - let buffer_offset = BLOCKED_ACCOUNTS_OFFSET + accounts_len_bytes; - let data = self.account.data.borrow(); - Ref::map(data, |d| &d[buffer_offset..]) + Ref::map(data, |d| &d[BUFFER_OFFSET..]) } #[must_use] pub fn buffer_mut(&mut self) -> RefMut<[u8]> { - let accounts_len_bytes = self.blocked_accounts_len() * size_of::(); - let buffer_offset = BLOCKED_ACCOUNTS_OFFSET + accounts_len_bytes; - let data = self.account.data.borrow_mut(); - RefMut::map(data, |d| &mut d[buffer_offset..]) + RefMut::map(data, |d| &mut d[BUFFER_OFFSET..]) } #[must_use] @@ -254,69 +207,56 @@ impl<'a> StateAccount<'a> { header.evm_machine_len = evm_machine_len; } - #[must_use] - pub fn owner(&self) -> Pubkey { - self.header().owner - } + pub fn save_data(&mut self) -> Result<()> { + let (evm_state_len, evm_machine_len) = self.buffer_variables(); + let offset = BUFFER_OFFSET + evm_state_len + evm_machine_len; - fn validate_owner(&self, operator: &Operator) -> Result<()> { - let owner = self.owner(); - let operator = *operator.key; + let data_len: usize = { + let mut data = self.account.data.borrow_mut(); + let buffer = &mut data[offset..]; - if owner != operator { - return Err(Error::HolderInvalidOwner(owner, operator)); - } + let mut cursor = std::io::Cursor::new(buffer); + bincode::serialize_into(&mut cursor, &self.data)?; - Ok(()) - } + cursor.position().try_into()? + }; - fn update_current_operator(&mut self, operator: &Operator) { - let mut header = self.header_mut(); - header.operator = *operator.key; - } + self.header_mut().data_len = data_len; - #[must_use] - pub fn trx_hash(&self) -> [u8; 32] { - self.header().transaction_hash + Ok(()) } #[must_use] - pub fn trx_origin(&self) -> Address { - self.header().origin + pub fn owner(&self) -> Pubkey { + self.data.owner } #[must_use] - pub fn trx_chain_id(&self) -> u64 { - self.header().chain_id + pub fn trx(&self) -> &Transaction { + &self.data.transaction } #[must_use] - pub fn trx_gas_price(&self) -> U256 { - self.header().gas_price + pub fn trx_origin(&self) -> Address { + self.data.origin } #[must_use] - pub fn trx_gas_limit(&self) -> U256 { - self.header().gas_limit - } - - pub fn gas_limit_in_tokens(&self) -> Result { - let header = self.header(); - header - .gas_limit - .checked_mul(header.gas_price) - .ok_or(Error::IntegerOverflow) + pub fn trx_chain_id(&self, backend: &impl AccountStorage) -> u64 { + self.data + .transaction + .chain_id() + .unwrap_or_else(|| backend.default_chain_id()) } #[must_use] pub fn gas_used(&self) -> U256 { - self.header().gas_used + self.data.gas_used } #[must_use] pub fn gas_available(&self) -> U256 { - let header = self.header(); - header.gas_limit.saturating_sub(header.gas_used) + self.trx().gas_limit().saturating_sub(self.gas_used()) } pub fn consume_gas(&mut self, amount: U256, receiver: &mut BalanceAccount) -> Result<()> { @@ -324,39 +264,33 @@ impl<'a> StateAccount<'a> { return Ok(()); } - let mut header = self.header_mut(); - - if receiver.chain_id() != header.chain_id { + let trx_chain_id = self.trx().chain_id().unwrap_or(DEFAULT_CHAIN_ID); + if receiver.chain_id() != trx_chain_id { return Err(Error::GasReceiverInvalidChainId); } - let total_gas_used = header.gas_used.saturating_add(amount); - let gas_limit = header.gas_limit; + let total_gas_used = self.data.gas_used.saturating_add(amount); + let gas_limit = self.trx().gas_limit(); if total_gas_used > gas_limit { return Err(Error::OutOfGas(gas_limit, total_gas_used)); } - header.gas_used = total_gas_used; + self.data.gas_used = total_gas_used; let tokens = amount - .checked_mul(header.gas_price) + .checked_mul(self.trx().gas_price()) .ok_or(Error::IntegerOverflow)?; receiver.mint(tokens) } pub fn refund_unused_gas(&mut self, origin: &mut BalanceAccount) -> Result<()> { - assert!(origin.chain_id() == self.trx_chain_id()); + let trx_chain_id = self.trx().chain_id().unwrap_or(DEFAULT_CHAIN_ID); + + assert!(origin.chain_id() == trx_chain_id); assert!(origin.address() == self.trx_origin()); let unused_gas = self.gas_available(); self.consume_gas(unused_gas, origin) } - - pub fn use_gas_limit_multiplier(&mut self) { - let mut header = self.header_mut(); - - let gas_multiplier = U256::from(GAS_LIMIT_MULTIPLIER_NO_CHAINID); - header.gas_limit = header.gas_limit.saturating_mul(gas_multiplier); - } } diff --git a/evm_loader/program/src/account/state_finalized.rs b/evm_loader/program/src/account/state_finalized.rs index 5e73c9801..03e07d43e 100644 --- a/evm_loader/program/src/account/state_finalized.rs +++ b/evm_loader/program/src/account/state_finalized.rs @@ -1,7 +1,10 @@ use std::cell::{Ref, RefMut}; -use super::{ACCOUNT_PREFIX_LEN, TAG_STATE_FINALIZED}; -use crate::error::Result; +use super::{Operator, HOLDER_PREFIX_LEN, TAG_STATE_FINALIZED}; +use crate::{ + error::{Error, Result}, + types::Transaction, +}; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; /// Storage data account to store execution metainfo between steps for iterative execution @@ -15,7 +18,7 @@ pub struct StateFinalizedAccount<'a> { account: AccountInfo<'a>, } -const HEADER_OFFSET: usize = ACCOUNT_PREFIX_LEN; +const HEADER_OFFSET: usize = HOLDER_PREFIX_LEN; impl<'a> StateFinalizedAccount<'a> { pub fn from_account(program_id: &Pubkey, account: AccountInfo<'a>) -> Result { @@ -52,4 +55,20 @@ impl<'a> StateFinalizedAccount<'a> { pub fn trx_hash(&self) -> [u8; 32] { self.header().transaction_hash } + + pub fn validate_owner(&self, operator: &Operator) -> Result<()> { + if &self.owner() != operator.key { + return Err(Error::HolderInvalidOwner(self.owner(), *operator.key)); + } + + Ok(()) + } + + pub fn validate_trx(&self, transaction: &Transaction) -> Result<()> { + if self.trx_hash() == transaction.hash { + return Err(Error::StorageAccountFinalized); + } + + Ok(()) + } } diff --git a/evm_loader/program/src/account_storage/apply.rs b/evm_loader/program/src/account_storage/apply.rs index 0392d0a3a..ea7e50cd6 100644 --- a/evm_loader/program/src/account_storage/apply.rs +++ b/evm_loader/program/src/account_storage/apply.rs @@ -1,14 +1,15 @@ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use ethnum::U256; use solana_program::account_info::AccountInfo; use solana_program::instruction::Instruction; use solana_program::program::{invoke_signed_unchecked, invoke_unchecked}; +use solana_program::pubkey::Pubkey; use solana_program::system_program; -use crate::account::BalanceAccount; +use crate::account::{increment_revision, BalanceAccount}; use crate::account::{AllocateResult, ContractAccount, StorageCell}; -use crate::account_storage::ProgramAccountStorage; +use crate::account_storage::{AccountStorage, ProgramAccountStorage}; use crate::config::{ ACCOUNT_SEED_VERSION, PAYMENT_TO_TREASURE, STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT, }; @@ -68,6 +69,7 @@ impl<'a> ProgramAccountStorage<'a> { pub fn apply_state_change(&mut self, actions: Vec) -> Result<()> { debug_print!("Applies begin"); + let mut modified_accounts: HashSet = HashSet::with_capacity(64); let mut storage = HashMap::with_capacity(16); for action in actions { @@ -81,6 +83,9 @@ impl<'a> ProgramAccountStorage<'a> { let mut source = self.balance_account(source, chain_id)?; let mut target = self.create_balance_account(target, chain_id)?; source.transfer(&mut target, value)?; + + modified_accounts.insert(*source.pubkey()); + modified_accounts.insert(*target.pubkey()); } Action::Burn { source, @@ -89,6 +94,8 @@ impl<'a> ProgramAccountStorage<'a> { } => { let mut account = self.create_balance_account(source, chain_id)?; account.burn(value)?; + + modified_accounts.insert(*account.pubkey()); } Action::EvmSetStorage { address, @@ -103,13 +110,15 @@ impl<'a> ProgramAccountStorage<'a> { Action::EvmIncrementNonce { address, chain_id } => { let mut account = self.create_balance_account(address, chain_id)?; account.increment_nonce()?; + + // Nonce increment is not count as account modification } Action::EvmSetCode { address, chain_id, code, } => { - ContractAccount::init( + let account = ContractAccount::init( address, chain_id, 0, @@ -117,6 +126,8 @@ impl<'a> ProgramAccountStorage<'a> { &self.accounts, Some(&self.keys), )?; + + modified_accounts.insert(*account.pubkey()); } Action::EvmSelfDestruct { address: _ } => { // EIP-6780: SELFDESTRUCT only in the same transaction @@ -161,23 +172,38 @@ impl<'a> ProgramAccountStorage<'a> { } } - self.apply_storage(storage)?; + self.apply_storage(storage, &mut modified_accounts)?; + + for pubkey in modified_accounts { + let account = self.accounts.get(&pubkey); + increment_revision(self.program_id(), account)?; + } + debug_print!("Applies done"); Ok(()) } - fn apply_storage(&mut self, storage: HashMap>) -> Result<()> { + fn apply_storage( + &mut self, + storage: HashMap>, + modified_accounts: &mut HashSet, + ) -> Result<()> { const STATIC_STORAGE_LIMIT: U256 = U256::new(STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT as u128); for (address, storage) in storage { - let mut contract = self.contract_account(address)?; + let mut contract: Option = None; let mut infinite_values: HashMap> = HashMap::with_capacity(storage.len()); for (index, value) in storage { if index < STATIC_STORAGE_LIMIT { + let contract = contract.get_or_insert_with(|| { + self.contract_account(address) + .expect("contract already created") + }); + // Static Storage - Write into contract account let index: usize = index.as_usize(); contract.set_storage_value(index, &value); @@ -193,10 +219,16 @@ impl<'a> ProgramAccountStorage<'a> { } } + if let Some(contract) = contract { + modified_accounts.insert(*contract.pubkey()); + } + for (index, values) in infinite_values { let cell_address = self.keys.storage_cell_address(&crate::ID, address, index); let account = self.accounts.get(cell_address.pubkey()); + modified_accounts.insert(*account.key); + if system_program::check_id(account.owner) { let (_, bump) = self.keys.contract_with_bump_seed(&crate::ID, address); let sign: &[&[u8]] = &[&[ACCOUNT_SEED_VERSION], address.as_bytes(), &[bump]]; diff --git a/evm_loader/program/src/account_storage/base.rs b/evm_loader/program/src/account_storage/base.rs index 24464937d..df43c2ae4 100644 --- a/evm_loader/program/src/account_storage/base.rs +++ b/evm_loader/program/src/account_storage/base.rs @@ -4,11 +4,12 @@ use crate::account::{ use crate::account_storage::ProgramAccountStorage; use crate::config::DEFAULT_CHAIN_ID; use crate::error::Result; -use crate::types::Address; +use crate::types::{Address, Transaction}; use ethnum::U256; use solana_program::{clock::Clock, rent::Rent, system_program, sysvar::Sysvar}; use super::keys_cache::KeysCache; +use super::AccountStorage; impl<'a> ProgramAccountStorage<'a> { pub fn new(accounts: AccountsDB<'a>) -> Result { @@ -95,4 +96,15 @@ impl<'a> ProgramAccountStorage<'a> { &self.rent, ) } + + pub fn origin( + &self, + address: Address, + transaction: &Transaction, + ) -> Result> { + let chain_id = transaction + .chain_id() + .unwrap_or_else(|| self.default_chain_id()); + self.create_balance_account(address, chain_id) + } } diff --git a/evm_loader/program/src/entrypoint.rs b/evm_loader/program/src/entrypoint.rs index 3f64b0757..eaf4edc69 100644 --- a/evm_loader/program/src/entrypoint.rs +++ b/evm_loader/program/src/entrypoint.rs @@ -125,9 +125,6 @@ fn process_instruction<'a>( instruction::create_main_treasury::process(program_id, accounts, instruction) .map_err(Error::from) } - EvmInstruction::AccountBlockAdd => { - instruction::account_block_add::process(program_id, accounts, instruction) - } EvmInstruction::AccountCreateBalance => { instruction::account_create_balance::process(program_id, accounts, instruction) } diff --git a/evm_loader/program/src/evm/mod.rs b/evm_loader/program/src/evm/mod.rs index b26c65cc1..d26a722cf 100644 --- a/evm_loader/program/src/evm/mod.rs +++ b/evm_loader/program/src/evm/mod.rs @@ -210,27 +210,13 @@ impl Machine { impl Machine { #[maybe_async] pub async fn new( - trx: Transaction, + trx: &Transaction, origin: Address, backend: &mut B, tracer: Option, ) -> Result { let trx_chain_id = trx.chain_id().unwrap_or_else(|| backend.default_chain_id()); - if !backend.is_valid_chain_id(trx_chain_id) { - return Err(Error::InvalidChainId(trx_chain_id)); - } - - let nonce = backend.nonce(origin, trx_chain_id).await?; - - if nonce == u64::MAX { - return Err(Error::NonceOverflow(origin)); - } - - if nonce != trx.nonce() { - return Err(Error::InvalidTransactionNonce(origin, nonce, trx.nonce())); - } - if backend.balance(origin, trx_chain_id).await? < trx.value() { return Err(Error::InsufficientBalance( origin, @@ -239,12 +225,6 @@ impl Machine { )); } - // TODO may be remove. This requires additional account - // Never actually happens, or at least should not - // if backend.code_size(origin).await? != 0 { - // return Err(Error::SenderHasDeployedCode(origin)); - // } - if trx.target().is_some() { Self::new_call(trx_chain_id, trx, origin, backend, tracer).await } else { @@ -255,7 +235,7 @@ impl Machine { #[maybe_async] async fn new_call( chain_id: u64, - trx: Transaction, + trx: &Transaction, origin: Address, backend: &mut B, tracer: Option, @@ -265,7 +245,6 @@ impl Machine { let target = trx.target().unwrap(); log_data(&[b"ENTER", b"CALL", target.as_bytes()]); - backend.increment_nonce(origin, chain_id)?; backend.snapshot(); backend @@ -287,7 +266,7 @@ impl Machine { gas_price: trx.gas_price(), gas_limit: trx.gas_limit(), execution_code, - call_data: trx.into_call_data(), + call_data: Buffer::from_slice(trx.call_data()), return_data: Buffer::empty(), return_range: 0..0, stack: Stack::new(), @@ -304,7 +283,7 @@ impl Machine { #[maybe_async] async fn new_create( chain_id: u64, - trx: Transaction, + trx: &Transaction, origin: Address, backend: &mut B, tracer: Option, @@ -319,7 +298,6 @@ impl Machine { return Err(Error::DeployToExistingAccount(target, origin)); } - backend.increment_nonce(origin, chain_id)?; backend.snapshot(); backend.increment_nonce(target, chain_id)?; @@ -346,7 +324,7 @@ impl Machine { pc: 0_usize, is_static: false, reason: Reason::Create, - execution_code: trx.into_call_data(), + execution_code: Buffer::from_slice(trx.call_data()), call_data: Buffer::empty(), parent: None, phantom: PhantomData, diff --git a/evm_loader/program/src/executor/action.rs b/evm_loader/program/src/executor/action.rs index 326224c16..d98eaf922 100644 --- a/evm_loader/program/src/executor/action.rs +++ b/evm_loader/program/src/executor/action.rs @@ -2,7 +2,7 @@ use ethnum::U256; use serde::{Deserialize, Serialize}; use solana_program::{instruction::AccountMeta, pubkey::Pubkey}; -use crate::types::Address; +use crate::types::{serde::bytes_32, Address}; #[derive(Debug, Clone, Serialize, Deserialize)] pub enum Action { @@ -31,7 +31,7 @@ pub enum Action { address: Address, #[serde(with = "ethnum::serde::bytes::le")] index: U256, - #[serde(with = "serde_bytes_32")] + #[serde(with = "bytes_32")] value: [u8; 32], }, EvmIncrementNonce { @@ -80,108 +80,3 @@ pub fn filter_selfdestruct(actions: Vec) -> Vec { }) .collect() } - -mod serde_bytes_32 { - pub fn serialize(value: &[u8; 32], serializer: S) -> Result - where - S: serde::ser::Serializer, - { - if serializer.is_human_readable() { - serializer.serialize_str(&hex::encode(value)) - } else { - serializer.serialize_bytes(value) - } - } - - pub fn deserialize<'de, D>(deserializer: D) -> Result<[u8; 32], D::Error> - where - D: serde::Deserializer<'de>, - { - struct BytesVisitor; - - impl<'de> serde::de::Visitor<'de> for BytesVisitor { - type Value = [u8; 32]; - - fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.write_str("[u8; 32]") - } - - fn visit_str(self, value: &str) -> Result - where - E: serde::de::Error, - { - use serde::de::Unexpected::Str; - - let value = hex::decode(value) - .map_err(|_| serde::de::Error::invalid_value(Str(value), &self))?; - - let value_len = value.len(); - value - .try_into() - .map_err(|_| serde::de::Error::invalid_length(value_len, &self)) - } - - fn visit_bytes(self, value: &[u8]) -> Result - where - E: serde::de::Error, - { - value - .try_into() - .map_err(|_| serde::de::Error::invalid_length(value.len(), &self)) - } - - fn visit_seq(self, mut seq: S) -> Result - where - S: serde::de::SeqAccess<'de>, - { - let mut bytes = Vec::with_capacity(32); - while let Some(b) = seq.next_element()? { - bytes.push(b); - } - bytes - .try_into() - .map_err(|_| serde::de::Error::custom("Invalid [u8; 32] value")) - } - } - - if deserializer.is_human_readable() { - deserializer.deserialize_str(BytesVisitor) - } else { - deserializer.deserialize_bytes(BytesVisitor) - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn roundtrip_bincode() { - let action = Action::EvmSetStorage { - address: Address::default(), - index: U256::from_le_bytes([ - 255, 46, 185, 41, 144, 201, 3, 36, 227, 18, 148, 147, 106, 131, 110, 6, 229, 235, - 44, 154, 71, 124, 159, 144, 47, 119, 77, 5, 154, 49, 23, 54, - ]), - value: Default::default(), - }; - let serialized = bincode::serialize(&action).unwrap(); - let _deserialized: Action = bincode::deserialize(&serialized).unwrap(); - } - - #[cfg(not(target_os = "solana"))] - #[test] - fn roundtrip_json() { - let action = Action::EvmSetStorage { - address: Address::default(), - index: U256::from_le_bytes([ - 255, 46, 185, 41, 144, 201, 3, 36, 227, 18, 148, 147, 106, 131, 110, 6, 229, 235, - 44, 154, 71, 124, 159, 144, 47, 119, 77, 5, 154, 49, 23, 54, - ]), - value: Default::default(), - }; - let serialized = serde_json::to_string(&action).unwrap(); - let _deserialized: Action = serde_json::from_str(&serialized).unwrap(); - } -} diff --git a/evm_loader/program/src/executor/state.rs b/evm_loader/program/src/executor/state.rs index 9fc3b1980..6c25f57c3 100644 --- a/evm_loader/program/src/executor/state.rs +++ b/evm_loader/program/src/executor/state.rs @@ -423,8 +423,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { if self.stack.is_empty() { // sanity check - assert_eq!(self.actions.len(), 1); - assert!(matches!(self.actions[0], Action::EvmIncrementNonce { .. })); + assert!(self.actions.is_empty()); } } diff --git a/evm_loader/program/src/instruction/account_block_add.rs b/evm_loader/program/src/instruction/account_block_add.rs deleted file mode 100644 index b875f6a12..000000000 --- a/evm_loader/program/src/instruction/account_block_add.rs +++ /dev/null @@ -1,50 +0,0 @@ -use crate::error::Result; -use solana_program::instruction::TRANSACTION_LEVEL_STACK_HEIGHT; -use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; - -pub fn process<'a>( - _program_id: &'a Pubkey, - _accounts: &'a [AccountInfo<'a>], - _instruction: &[u8], -) -> Result<()> { - let stack_height = solana_program::instruction::get_stack_height(); - assert_eq!(stack_height, TRANSACTION_LEVEL_STACK_HEIGHT); - - log_msg!("Instruction: Block Accounts"); - - todo!(); - - // let mut state = State::from_account(program_id, &accounts[0])?; - // let operator = Operator::from_account(&accounts[1])?; - - // if &state.owner != operator.key { - // return Err(Error::HolderInvalidOwner(state.owner, *operator.key)); - // } - - // let mut blocked_accounts = state.read_blocked_accounts()?; - // let mut blocked_keys: BTreeSet = blocked_accounts.iter().map(|a| a.key).collect(); - - // for account_info in &accounts[2..] { - // if blocked_keys.contains(account_info.key) { - // continue; - // } - - // let mut meta = BlockedAccountMeta { - // key: *account_info.key, - // exists: false, - // is_writable: account_info.is_writable, - // }; - - // if let Ok(mut account) = EthereumAccount::from_account(program_id, account_info) { - // account.check_blocked()?; - // account.rw_blocked = true; - - // meta.exists = true; - // } - - // blocked_accounts.push(meta); - // blocked_keys.insert(*account_info.key); - // } - - // state.update_blocked_accounts(blocked_accounts.into_iter()) -} diff --git a/evm_loader/program/src/instruction/mod.rs b/evm_loader/program/src/instruction/mod.rs index d5468775a..3a805e782 100644 --- a/evm_loader/program/src/instruction/mod.rs +++ b/evm_loader/program/src/instruction/mod.rs @@ -157,9 +157,6 @@ pub enum EvmInstruction { /// None CreateMainTreasury, - /// Block additional accounts - AccountBlockAdd, - /// Create a User Balance account /// /// Accounts: @@ -194,7 +191,6 @@ impl EvmInstruction { 0x25 => Self::HolderDelete, // 37 0x26 => Self::HolderWrite, // 38 0x29 => Self::CreateMainTreasury, // 41 - 0x2B => Self::AccountBlockAdd, // 43 0x30 => Self::AccountCreateBalance, // 48 0x31 => Self::Deposit, // 49 @@ -218,7 +214,6 @@ impl EvmInstruction { } } -pub mod account_block_add; pub mod account_create_balance; pub mod account_holder_create; pub mod account_holder_delete; diff --git a/evm_loader/program/src/instruction/transaction_cancel.rs b/evm_loader/program/src/instruction/transaction_cancel.rs index bfe195ea5..489685363 100644 --- a/evm_loader/program/src/instruction/transaction_cancel.rs +++ b/evm_loader/program/src/instruction/transaction_cancel.rs @@ -1,4 +1,5 @@ use crate::account::{AccountsDB, BalanceAccount, Operator, StateAccount}; +use crate::config::DEFAULT_CHAIN_ID; use crate::debug::log_data; use crate::error::{Error, Result}; use crate::gasometer::{CANCEL_TRX_COST, LAST_ITERATION_COST}; @@ -23,16 +24,16 @@ pub fn process<'a>( log_data(&[b"MINER", operator_balance.address().as_bytes()]); let accounts_db = AccountsDB::new(&accounts[3..], operator, Some(operator_balance), None, None); - let storage = StateAccount::restore(program_id, storage_info, &accounts_db, true)?; + let (storage, _) = StateAccount::restore(program_id, storage_info, &accounts_db)?; validate(&storage, transaction_hash)?; execute(program_id, accounts_db, storage) } fn validate(storage: &StateAccount, transaction_hash: &[u8; 32]) -> Result<()> { - if &storage.trx_hash() != transaction_hash { + if &storage.trx().hash() != transaction_hash { return Err(Error::HolderInvalidHash( - storage.trx_hash(), + storage.trx().hash(), *transaction_hash, )); } @@ -45,6 +46,8 @@ fn execute<'a>( mut accounts: AccountsDB<'a>, mut storage: StateAccount<'a>, ) -> Result<()> { + let trx_chain_id = storage.trx().chain_id().unwrap_or(DEFAULT_CHAIN_ID); + let used_gas = U256::ZERO; let total_used_gas = storage.gas_used(); log_data(&[ @@ -57,15 +60,13 @@ fn execute<'a>( let _ = storage.consume_gas(gas, accounts.operator_balance()); // ignore error let origin = storage.trx_origin(); - let (origin_pubkey, _) = origin.find_balance_address(program_id, storage.trx_chain_id()); + let (origin_pubkey, _) = origin.find_balance_address(program_id, trx_chain_id); { let origin_info = accounts.get(&origin_pubkey).clone(); let mut account = BalanceAccount::from_account(program_id, origin_info)?; - account.increment_nonce()?; - storage.refund_unused_gas(&mut account)?; } - storage.finalize(program_id, &accounts) + storage.finalize(program_id) } diff --git a/evm_loader/program/src/instruction/transaction_execute.rs b/evm_loader/program/src/instruction/transaction_execute.rs index 9bac6d615..85dbed504 100644 --- a/evm_loader/program/src/instruction/transaction_execute.rs +++ b/evm_loader/program/src/instruction/transaction_execute.rs @@ -1,5 +1,3 @@ -use solana_program::pubkey::Pubkey; - use crate::account::{AccountsDB, AllocateResult}; use crate::account_storage::ProgramAccountStorage; use crate::debug::log_data; @@ -11,20 +9,6 @@ use crate::gasometer::Gasometer; use crate::instruction::transaction_step::log_return_value; use crate::types::{Address, Transaction}; -pub fn validate(program_id: &Pubkey, accounts: &AccountsDB) -> Result<()> { - for account in accounts { - if account.owner != program_id { - continue; - } - - if crate::account::is_blocked(program_id, account)? { - return Err(Error::AccountBlocked(*account.key)); - } - } - - Ok(()) -} - pub fn execute( accounts: AccountsDB<'_>, mut gasometer: Gasometer, @@ -37,10 +21,14 @@ pub fn execute( let mut account_storage = ProgramAccountStorage::new(accounts)?; + trx.validate(origin, &account_storage)?; + + account_storage.origin(origin, &trx)?.increment_nonce()?; + let (exit_reason, apply_state) = { let mut backend = ExecutorState::new(&account_storage); - let mut evm = Machine::new(trx, origin, &mut backend, None::)?; + let mut evm = Machine::new(&trx, origin, &mut backend, None::)?; let (result, _, _) = evm.execute(u64::MAX, &mut backend)?; let actions = backend.into_actions(); diff --git a/evm_loader/program/src/instruction/transaction_execute_from_account.rs b/evm_loader/program/src/instruction/transaction_execute_from_account.rs index fbea0adfe..7d7ad6c2d 100644 --- a/evm_loader/program/src/instruction/transaction_execute_from_account.rs +++ b/evm_loader/program/src/instruction/transaction_execute_from_account.rs @@ -46,6 +46,5 @@ pub fn process<'a>( gasometer.record_address_lookup_table(accounts); gasometer.record_write_to_holder(&trx); - super::transaction_execute::validate(program_id, &accounts_db)?; super::transaction_execute::execute(accounts_db, gasometer, trx, origin) } diff --git a/evm_loader/program/src/instruction/transaction_execute_from_instruction.rs b/evm_loader/program/src/instruction/transaction_execute_from_instruction.rs index a2cd8117f..b51d593d8 100644 --- a/evm_loader/program/src/instruction/transaction_execute_from_instruction.rs +++ b/evm_loader/program/src/instruction/transaction_execute_from_instruction.rs @@ -41,6 +41,5 @@ pub fn process<'a>( gasometer.record_solana_transaction_cost(); gasometer.record_address_lookup_table(accounts); - super::transaction_execute::validate(program_id, &accounts_db)?; super::transaction_execute::execute(accounts_db, gasometer, trx, origin) } diff --git a/evm_loader/program/src/instruction/transaction_step.rs b/evm_loader/program/src/instruction/transaction_step.rs index 83dc853d9..aa377f6db 100644 --- a/evm_loader/program/src/instruction/transaction_step.rs +++ b/evm_loader/program/src/instruction/transaction_step.rs @@ -7,7 +7,6 @@ use crate::evm::tracing::NoopEventListener; use crate::evm::{ExitStatus, Machine}; use crate::executor::{Action, ExecutorState}; use crate::gasometer::Gasometer; -use crate::types::{Address, Transaction}; type EvmBackend<'a, 'r> = ExecutorState<'r, ProgramAccountStorage<'a>>; type Evm<'a, 'r> = Machine, NoopEventListener>; @@ -16,23 +15,34 @@ pub fn do_begin<'a>( accounts: AccountsDB<'a>, mut storage: StateAccount<'a>, gasometer: Gasometer, - trx: Transaction, - origin: Address, ) -> Result<()> { debug_print!("do_begin"); - let accounts = ProgramAccountStorage::new(accounts)?; + let account_storage = ProgramAccountStorage::new(accounts)?; + + let origin = storage.trx_origin(); + + storage.trx().validate(origin, &account_storage)?; - let mut backend = ExecutorState::new(&accounts); - let evm = Machine::new(trx, origin, &mut backend, None::)?; + // Increment origin nonce in the first iteration + // This allows us to run multiple iterative transactions from the same sender in parallel + // These transactions are guaranteed to start in a correct sequence + // BUT they finalize in an undefined order + let mut origin_account = account_storage.origin(origin, storage.trx())?; + origin_account.increment_nonce()?; // Burn `gas_limit` tokens from the origin account // Later we will mint them to the operator - let mut origin_balance = accounts.create_balance_account(origin, storage.trx_chain_id())?; - origin_balance.burn(storage.gas_limit_in_tokens()?)?; + // Remaining tokens are returned to the origin in the last iteration + let gas_limit_in_tokens = storage.trx().gas_limit_in_tokens()?; + origin_account.burn(gas_limit_in_tokens)?; + + // Initialize EVM and serialize it to the Holder + let mut backend = ExecutorState::new(&account_storage); + let evm = Machine::new(storage.trx(), origin, &mut backend, None)?; serialize_evm_state(&mut storage, &backend, &evm)?; - finalize(0, storage, accounts, None, gasometer) + finalize(0, storage, account_storage, None, gasometer) } pub fn do_continue<'a>( @@ -40,32 +50,35 @@ pub fn do_continue<'a>( accounts: AccountsDB<'a>, mut storage: StateAccount<'a>, gasometer: Gasometer, + reset: bool, ) -> Result<()> { debug_print!("do_continue"); - if (step_count < EVM_STEPS_MIN) && (storage.trx_gas_price() > 0) { + if (step_count < EVM_STEPS_MIN) && (storage.trx().gas_price() > 0) { return Err(Error::Custom(format!( "Step limit {step_count} below minimum {EVM_STEPS_MIN}" ))); } let account_storage = ProgramAccountStorage::new(accounts)?; - let (mut backend, mut evm) = deserialize_evm_state(&storage, &account_storage)?; + let (mut backend, mut evm) = if reset { + let mut backend = ExecutorState::new(&account_storage); + let evm = Machine::new(storage.trx(), storage.trx_origin(), &mut backend, None)?; + (backend, evm) + } else { + deserialize_evm_state(&storage, &account_storage)? + }; - let (result, steps_executed, _) = { - match backend.exit_status() { - Some(status) => (status.clone(), 0_u64, None), - None => evm.execute(step_count, &mut backend)?, - } + let (result, steps_executed, _) = match backend.exit_status() { + Some(status) => (status.clone(), 0_u64, None), + None => evm.execute(step_count, &mut backend)?, }; if (result != ExitStatus::StepLimit) && (steps_executed > 0) { backend.set_exit_status(result.clone()); } - if steps_executed > 0 { - serialize_evm_state(&mut storage, &backend, &evm)?; - } + serialize_evm_state(&mut storage, &backend, &evm)?; let results = match result { ExitStatus::StepLimit => None, @@ -115,10 +128,12 @@ fn finalize<'a>( if let Some(status) = status { log_return_value(&status); - let mut origin = accounts.balance_account(storage.trx_origin(), storage.trx_chain_id())?; + let mut origin = accounts.origin(storage.trx_origin(), storage.trx())?; storage.refund_unused_gas(&mut origin)?; - storage.finalize(accounts.program_id(), accounts.db())?; + storage.finalize(accounts.program_id())?; + } else { + storage.save_data()?; } Ok(()) diff --git a/evm_loader/program/src/instruction/transaction_step_from_account.rs b/evm_loader/program/src/instruction/transaction_step_from_account.rs index 6d7e21aa5..4cc712ba7 100644 --- a/evm_loader/program/src/instruction/transaction_step_from_account.rs +++ b/evm_loader/program/src/instruction/transaction_step_from_account.rs @@ -1,7 +1,7 @@ use crate::account::legacy::{TAG_HOLDER_DEPRECATED, TAG_STATE_FINALIZED_DEPRECATED}; use crate::account::{ - program, AccountsDB, BalanceAccount, Holder, Operator, StateAccount, Treasury, TAG_HOLDER, - TAG_STATE, TAG_STATE_FINALIZED, + program, AccountsDB, AccountsStatus, BalanceAccount, Holder, Operator, StateAccount, Treasury, + TAG_HOLDER, TAG_STATE, TAG_STATE_FINALIZED, }; use crate::debug::log_data; use crate::error::{Error, Result}; @@ -57,7 +57,7 @@ pub fn process_inner<'a>( match tag { TAG_HOLDER | TAG_HOLDER_DEPRECATED => { - let trx = { + let mut trx = { let holder = Holder::from_account(program_id, holder_or_storage.clone())?; holder.validate_owner(accounts_db.operator())?; @@ -72,6 +72,11 @@ pub fn process_inner<'a>( log_data(&[b"HASH", &trx.hash]); log_data(&[b"MINER", miner_address.as_bytes()]); + if increase_gas_limit { + assert!(trx.chain_id().is_none()); + trx.use_gas_limit_multiplier(); + } + let origin = trx.recover_caller_address()?; let mut gasometer = Gasometer::new(U256::ZERO, accounts_db.operator())?; @@ -82,32 +87,28 @@ pub fn process_inner<'a>( excessive_lamports += crate::account::legacy::update_legacy_accounts(&accounts_db)?; gasometer.refund_lamports(excessive_lamports); - let mut storage = StateAccount::new( + let storage = StateAccount::new( program_id, holder_or_storage.clone(), &accounts_db, origin, - &trx, + trx, )?; - if increase_gas_limit { - assert!(trx.chain_id().is_none()); - storage.use_gas_limit_multiplier(); - } - - do_begin(accounts_db, storage, gasometer, trx, origin) + do_begin(accounts_db, storage, gasometer) } TAG_STATE => { - let storage = - StateAccount::restore(program_id, holder_or_storage.clone(), &accounts_db, false)?; + let (storage, accounts_status) = + StateAccount::restore(program_id, holder_or_storage.clone(), &accounts_db)?; - log_data(&[b"HASH", &storage.trx_hash()]); + log_data(&[b"HASH", &storage.trx().hash()]); log_data(&[b"MINER", miner_address.as_bytes()]); let mut gasometer = Gasometer::new(storage.gas_used(), accounts_db.operator())?; gasometer.record_solana_transaction_cost(); - do_continue(step_count, accounts_db, storage, gasometer) + let reset = accounts_status != AccountsStatus::Ok; + do_continue(step_count, accounts_db, storage, gasometer, reset) } TAG_STATE_FINALIZED | TAG_STATE_FINALIZED_DEPRECATED => Err(Error::StorageAccountFinalized), _ => Err(Error::AccountInvalidTag(*holder_or_storage.key, TAG_HOLDER)), diff --git a/evm_loader/program/src/instruction/transaction_step_from_instruction.rs b/evm_loader/program/src/instruction/transaction_step_from_instruction.rs index cd41be54a..adc2b7ae6 100644 --- a/evm_loader/program/src/instruction/transaction_step_from_instruction.rs +++ b/evm_loader/program/src/instruction/transaction_step_from_instruction.rs @@ -1,7 +1,7 @@ use crate::account::legacy::{TAG_HOLDER_DEPRECATED, TAG_STATE_FINALIZED_DEPRECATED}; use crate::account::{ - program, AccountsDB, BalanceAccount, Operator, StateAccount, Treasury, TAG_HOLDER, TAG_STATE, - TAG_STATE_FINALIZED, + program, AccountsDB, AccountsStatus, BalanceAccount, Operator, StateAccount, Treasury, + TAG_HOLDER, TAG_STATE, TAG_STATE_FINALIZED, }; use crate::debug::log_data; use crate::error::{Error, Result}; @@ -63,20 +63,22 @@ pub fn process<'a>( excessive_lamports += crate::account::legacy::update_legacy_accounts(&accounts_db)?; gasometer.refund_lamports(excessive_lamports); - let storage = StateAccount::new(program_id, storage_info, &accounts_db, origin, &trx)?; + let storage = StateAccount::new(program_id, storage_info, &accounts_db, origin, trx)?; - do_begin(accounts_db, storage, gasometer, trx, origin) + do_begin(accounts_db, storage, gasometer) } TAG_STATE => { - let storage = StateAccount::restore(program_id, storage_info, &accounts_db, false)?; + let (storage, accounts_status) = + StateAccount::restore(program_id, storage_info, &accounts_db)?; - log_data(&[b"HASH", &storage.trx_hash()]); + log_data(&[b"HASH", &storage.trx().hash()]); log_data(&[b"MINER", miner_address.as_bytes()]); let mut gasometer = Gasometer::new(storage.gas_used(), accounts_db.operator())?; gasometer.record_solana_transaction_cost(); - do_continue(step_count, accounts_db, storage, gasometer) + let reset = accounts_status != AccountsStatus::Ok; + do_continue(step_count, accounts_db, storage, gasometer, reset) } _ => Err(Error::AccountInvalidTag(*storage_info.key, TAG_HOLDER)), }?; diff --git a/evm_loader/program/src/types/mod.rs b/evm_loader/program/src/types/mod.rs index 04afe313f..756a5a409 100644 --- a/evm_loader/program/src/types/mod.rs +++ b/evm_loader/program/src/types/mod.rs @@ -6,4 +6,5 @@ pub use transaction::Transaction; pub use transaction::TransactionPayload; mod address; +pub mod serde; mod transaction; diff --git a/evm_loader/program/src/types/serde.rs b/evm_loader/program/src/types/serde.rs new file mode 100644 index 000000000..eb94cfbbe --- /dev/null +++ b/evm_loader/program/src/types/serde.rs @@ -0,0 +1,130 @@ +// use ethnum::U256; + +// serde_with::serde_conv!( +// pub U256AsWords, +// U256, +// |value: &U256| { value.into_words() }, +// |words: (u128, u128)| -> Result<_, std::convert::Infallible> { Ok(U256::from_words(words.0, words.1)) } +// ); + +pub mod option_u256 { + use std::fmt::{self, Formatter}; + + use ethnum::U256; + use serde::{de::Visitor, Deserializer, Serializer}; + + pub fn serialize(value: &Option, serializer: S) -> Result + where + S: Serializer, + { + if let Some(value) = value { + serializer.serialize_bytes(&value.to_le_bytes()) + } else { + serializer.serialize_bytes(&[]) + } + } + + struct BytesVisitor; + + impl<'de> Visitor<'de> for BytesVisitor { + type Value = Option; + + fn expecting(&self, f: &mut Formatter) -> fmt::Result { + f.write_str(concat!("32 bytes in little endian")) + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: serde::de::Error, + { + if v.is_empty() { + return Ok(None); + } + + let bytes = v + .try_into() + .map_err(|_| E::invalid_length(v.len(), &self))?; + + Ok(Some(U256::from_le_bytes(bytes))) + } + } + + #[doc(hidden)] + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + deserializer.deserialize_bytes(BytesVisitor) + } +} + +pub mod bytes_32 { + pub fn serialize(value: &[u8; 32], serializer: S) -> Result + where + S: serde::ser::Serializer, + { + if serializer.is_human_readable() { + serializer.serialize_str(&hex::encode(value)) + } else { + serializer.serialize_bytes(value) + } + } + + pub fn deserialize<'de, D>(deserializer: D) -> Result<[u8; 32], D::Error> + where + D: serde::Deserializer<'de>, + { + struct BytesVisitor; + + impl<'de> serde::de::Visitor<'de> for BytesVisitor { + type Value = [u8; 32]; + + fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.write_str("[u8; 32]") + } + + fn visit_str(self, value: &str) -> Result + where + E: serde::de::Error, + { + use serde::de::Unexpected::Str; + + let value = hex::decode(value) + .map_err(|_| serde::de::Error::invalid_value(Str(value), &self))?; + + let value_len = value.len(); + value + .try_into() + .map_err(|_| serde::de::Error::invalid_length(value_len, &self)) + } + + fn visit_bytes(self, value: &[u8]) -> Result + where + E: serde::de::Error, + { + value + .try_into() + .map_err(|_| serde::de::Error::invalid_length(value.len(), &self)) + } + + fn visit_seq(self, mut seq: S) -> Result + where + S: serde::de::SeqAccess<'de>, + { + let mut bytes = Vec::with_capacity(32); + while let Some(b) = seq.next_element()? { + bytes.push(b); + } + bytes + .try_into() + .map_err(|_| serde::de::Error::custom("Invalid [u8; 32] value")) + } + } + + if deserializer.is_human_readable() { + deserializer.deserialize_str(BytesVisitor) + } else { + deserializer.deserialize_bytes(BytesVisitor) + } + } +} diff --git a/evm_loader/program/src/types/transaction.rs b/evm_loader/program/src/types/transaction.rs index bae39cf34..c3d82173e 100644 --- a/evm_loader/program/src/types/transaction.rs +++ b/evm_loader/program/src/types/transaction.rs @@ -1,13 +1,22 @@ use ethnum::U256; +use maybe_async::maybe_async; +use serde::{Deserialize, Serialize}; use std::convert::TryInto; -use crate::error::Error; +use crate::{ + account_storage::AccountStorage, config::GAS_LIMIT_MULTIPLIER_NO_CHAINID, error::Error, +}; -use super::Address; +use super::{ + serde::{bytes_32, option_u256}, + Address, +}; #[repr(transparent)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] -pub struct StorageKey([u8; 32]); +#[derive( + Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize, +)] +pub struct StorageKey(#[serde(with = "bytes_32")] [u8; 32]); impl rlp::Decodable for StorageKey { fn decode(rlp: &rlp::Rlp) -> Result { @@ -67,17 +76,25 @@ impl TransactionEnvelope { } } -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize)] pub struct LegacyTx { pub nonce: u64, + #[serde(with = "ethnum::serde::bytes::le")] pub gas_price: U256, + #[serde(with = "ethnum::serde::bytes::le")] pub gas_limit: U256, pub target: Option
, + #[serde(with = "ethnum::serde::bytes::le")] pub value: U256, + #[serde(with = "serde_bytes")] pub call_data: Vec, + #[serde(with = "ethnum::serde::bytes::le")] pub v: U256, + #[serde(with = "ethnum::serde::bytes::le")] pub r: U256, + #[serde(with = "ethnum::serde::bytes::le")] pub s: U256, + #[serde(with = "option_u256")] pub chain_id: Option, pub recovery_id: u8, } @@ -148,16 +165,23 @@ impl rlp::Decodable for LegacyTx { } } -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize)] pub struct AccessListTx { pub nonce: u64, + #[serde(with = "ethnum::serde::bytes::le")] pub gas_price: U256, + #[serde(with = "ethnum::serde::bytes::le")] pub gas_limit: U256, pub target: Option
, + #[serde(with = "ethnum::serde::bytes::le")] pub value: U256, + #[serde(with = "serde_bytes")] pub call_data: Vec, + #[serde(with = "ethnum::serde::bytes::le")] pub r: U256, + #[serde(with = "ethnum::serde::bytes::le")] pub s: U256, + #[serde(with = "ethnum::serde::bytes::le")] pub chain_id: U256, pub recovery_id: u8, pub access_list: Vec<(Address, Vec)>, @@ -245,17 +269,19 @@ impl rlp::Decodable for AccessListTx { // TODO: Will be added as a part of EIP-1559 // struct DynamicFeeTx {} -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize)] pub enum TransactionPayload { Legacy(LegacyTx), AccessList(AccessListTx), } -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize)] pub struct Transaction { pub transaction: TransactionPayload, pub byte_len: usize, + #[serde(with = "bytes_32")] pub hash: [u8; 32], + #[serde(with = "bytes_32")] pub signed_hash: [u8; 32], } @@ -491,6 +517,12 @@ impl Transaction { } } + pub fn gas_limit_in_tokens(&self) -> Result { + self.gas_price() + .checked_mul(self.gas_limit()) + .ok_or(Error::IntegerOverflow) + } + #[must_use] pub fn target(&self) -> Option
{ match self.transaction { @@ -515,16 +547,6 @@ impl Transaction { } } - #[must_use] - pub fn into_call_data(self) -> crate::evm::Buffer { - match self.transaction { - TransactionPayload::Legacy(LegacyTx { call_data, .. }) - | TransactionPayload::AccessList(AccessListTx { call_data, .. }) => { - crate::evm::Buffer::from_vec(call_data) - } - } - } - #[must_use] pub fn r(&self) -> U256 { match self.transaction { @@ -582,6 +604,40 @@ impl Transaction { TransactionPayload::Legacy(_) => None, } } + + pub fn use_gas_limit_multiplier(&mut self) { + let gas_multiplier = U256::from(GAS_LIMIT_MULTIPLIER_NO_CHAINID); + + match &mut self.transaction { + TransactionPayload::AccessList(AccessListTx { gas_limit, .. }) + | TransactionPayload::Legacy(LegacyTx { gas_limit, .. }) => { + *gas_limit = gas_limit.saturating_mul(gas_multiplier); + } + } + } + + #[maybe_async] + pub async fn validate( + &self, + origin: Address, + backend: &impl AccountStorage, + ) -> Result<(), crate::error::Error> { + let chain_id = self + .chain_id() + .unwrap_or_else(|| backend.default_chain_id()); + + if !backend.is_valid_chain_id(chain_id) { + return Err(Error::InvalidChainId(chain_id)); + } + + let origin_nonce = backend.nonce(origin, chain_id).await; + if origin_nonce != self.nonce() { + let error = Error::InvalidTransactionNonce(origin, origin_nonce, self.nonce()); + return Err(error); + } + + Ok(()) + } } #[inline] From 9d58ae78ef5d16b7cad673aaf1bf4c1d7f3e9c09 Mon Sep 17 00:00:00 2001 From: Kristina Nikolaeva <112946046+kristinaNikolaevaa@users.noreply.github.com> Date: Thu, 22 Feb 2024 13:47:49 +0100 Subject: [PATCH 092/318] added test solana programs (#284) --- .github/workflows/deploy.py | 9 ++++++--- .github/workflows/github_api_client.py | 9 +++++++++ .github/workflows/pipeline.yml | 5 +++-- Dockerfile | 6 +++--- ci/solana-run-neon.sh | 12 ++++++++---- 5 files changed, 29 insertions(+), 12 deletions(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index 1c5eecfb6..20d7ef6a1 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -105,16 +105,19 @@ def run_subprocess(command): @cli.command(name="run_tests") @click.option('--github_sha') @click.option('--neon_test_branch') -def run_tests(github_sha, neon_test_branch): +@click.option('--base_ref_branch') +def run_tests(github_sha, neon_test_branch, base_ref_branch): os.environ["EVM_LOADER_IMAGE"] = f"{IMAGE_NAME}:{github_sha}" - if neon_test_branch in GithubClient.get_branches_list(NEON_TESTS_ENDPOINT) \ + if GithubClient.is_branch_exist(NEON_TESTS_ENDPOINT, neon_test_branch) \ and neon_test_branch not in ('master', 'develop'): neon_test_image_tag = neon_test_branch + elif re.match(VERSION_BRANCH_TEMPLATE, base_ref_branch): # PR to version branch + neon_test_image_tag = base_ref_branch else: neon_test_image_tag = 'latest' os.environ["NEON_TESTS_IMAGE"] = f"{NEON_TEST_IMAGE_NAME}:{neon_test_image_tag}" - + click.echo(f"NEON_TESTS_IMAGE: {os.environ['NEON_TESTS_IMAGE']}") project_name = f"neon-evm-{github_sha}" stop_containers(project_name) diff --git a/.github/workflows/github_api_client.py b/.github/workflows/github_api_client.py index 198a4892a..3aa3fd850 100644 --- a/.github/workflows/github_api_client.py +++ b/.github/workflows/github_api_client.py @@ -42,6 +42,15 @@ def get_branches_list(endpoint): proxy_branches_obj = requests.get( f"{endpoint}/branches?per_page=100").json() return [item["name"] for item in proxy_branches_obj] + @staticmethod + def is_branch_exist(endpoint, branch): + if branch: + response = requests.get(f"{endpoint}/branches/{branch}") + if response.status_code == 200: + click.echo(f"The branch {branch} exist in the {endpoint} repository") + return True + else: + return False def get_proxy_run_info(self, id): response = requests.get( diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index 0418a9cf7..e1e58d6e3 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -64,7 +64,7 @@ jobs: elif [[ "${{ steps.tag_creation.outputs.base_branch }}" != "" ]]; then # tag creation tag=${{ steps.tag_creation.outputs.base_branch }} - elif [[ "${{ github.head_ref }}" != "" ]]; then # pr to feature or version branch + elif [[ "${{ github.head_ref }}" != "" ]]; then # pr to feature or version branch or develop tag=${{ github.head_ref }} else tag='develop' @@ -75,7 +75,8 @@ jobs: run: | python3 ./.github/workflows/deploy.py run_tests \ --github_sha=${GITHUB_SHA} \ - --neon_test_branch=${{ steps.neon_test_branch.outputs.value }} + --neon_test_branch=${{ steps.neon_test_branch.outputs.value }} \ + --base_ref_branch=${{ github.base_ref }} trigger-proxy-tests: runs-on: trigger-runner needs: diff --git a/Dockerfile b/Dockerfile index 04bf9c5c8..75f4656c4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -29,7 +29,7 @@ RUN cargo fmt --check && \ # Add neon_test_invoke_program to the genesis -FROM neonlabsorg/neon_test_invoke_program:develop AS neon_test_invoke_program +FROM neonlabsorg/neon_test_programs:latest AS neon_test_programs # Define solana-image that contains utility FROM builder AS base @@ -40,8 +40,8 @@ COPY --from=evm-loader-builder /opt/neon-evm/evm_loader/target/deploy/evm_loader COPY --from=evm-loader-builder /opt/neon-evm/evm_loader/target/deploy/evm_loader-dump.txt /opt/ COPY --from=evm-loader-builder /opt/neon-evm/evm_loader/target/release/neon-cli /opt/ COPY --from=evm-loader-builder /opt/neon-evm/evm_loader/target/release/neon-api /opt/ -COPY --from=neon_test_invoke_program /opt/neon_test_invoke_program.so /opt/ -COPY --from=neon_test_invoke_program /opt/neon_test_invoke_program-keypair.json /opt/ + +COPY --from=neon_test_programs /opt/deploy/ /opt/deploy/ COPY ci/wait-for-solana.sh \ ci/wait-for-neon.sh \ diff --git a/ci/solana-run-neon.sh b/ci/solana-run-neon.sh index 8f58a1122..0deda3f77 100755 --- a/ci/solana-run-neon.sh +++ b/ci/solana-run-neon.sh @@ -12,9 +12,6 @@ EVM_LOADER_PATH=${NEON_BIN}/evm_loader.so METAPLEX=metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s METAPLEX_PATH=${NEON_BIN}/metaplex.so -TEST_INVOKE_PROGRAM_ID_KEYPAIR=${NEON_BIN}/neon_test_invoke_program-keypair.json -TEST_INVOKE=$(solana address -k ${TEST_INVOKE_PROGRAM_ID_KEYPAIR}) -TEST_INVOKE_PATH=${NEON_BIN}/neon_test_invoke_program.so VALIDATOR_ARGS=( --reset @@ -23,9 +20,16 @@ VALIDATOR_ARGS=( --ticks-per-slot 16 --upgradeable-program ${EVM_LOADER} ${EVM_LOADER_PATH} ${EVM_LOADER_AUTHORITY_KEYPAIR} --bpf-program ${METAPLEX} ${METAPLEX_PATH} - --bpf-program ${TEST_INVOKE} ${TEST_INVOKE_PATH} ) +LIST_OF_TEST_PROGRAMS=("test_invoke_program" "counter" "cross_program_invocation" "transfer_sol" "transfer_tokens") + +for program in "${LIST_OF_TEST_PROGRAMS[@]}"; do + keypair="${NEON_BIN}/deploy/${program}/${program}-keypair.json" + address=$(solana address -k $keypair) + VALIDATOR_ARGS+=(--bpf-program $address ${NEON_BIN}/deploy/$program/$program.so) +done + if [[ -n $GEYSER_PLUGIN_CONFIG ]]; then echo "Using geyser plugin with config: $GEYSER_PLUGIN_CONFIG" VALIDATOR_ARGS+=(--geyser-plugin-config $GEYSER_PLUGIN_CONFIG) From 07298214723e04ccd084406712ada47523628f7a Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Fri, 23 Feb 2024 09:30:20 +0300 Subject: [PATCH 093/318] Fix account migration from before revision (#285) --- evm_loader/lib/src/account_update.rs | 13 ++++++++----- evm_loader/program/src/account/legacy/update.rs | 7 +++++-- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/evm_loader/lib/src/account_update.rs b/evm_loader/lib/src/account_update.rs index 9927fb020..a51dda7b2 100644 --- a/evm_loader/lib/src/account_update.rs +++ b/evm_loader/lib/src/account_update.rs @@ -13,13 +13,16 @@ fn from_before_revision(account: &mut Account, new_tag: u8) { const PREFIX_BEFORE: usize = ACCOUNT_PREFIX_LEN_BEFORE_REVISION; const PREFIX_AFTER: usize = ACCOUNT_PREFIX_LEN; - assert!(account.data.len() > PREFIX_BEFORE); + let data: &mut Vec = &mut account.data; - let required_len = account.data.len() + PREFIX_AFTER - PREFIX_BEFORE; - account.data.resize(required_len, 0); + assert!(data.len() > PREFIX_BEFORE); + let data_len = data.len() - PREFIX_BEFORE; - account.data.copy_within(PREFIX_BEFORE.., PREFIX_AFTER); - account.data[0] = new_tag; + let required_len = data.len() + PREFIX_AFTER - PREFIX_BEFORE; + data.resize(required_len, 0); + + data.copy_within(PREFIX_BEFORE..(PREFIX_BEFORE + data_len), PREFIX_AFTER); + data[0] = new_tag; } pub fn update_account(program_id: &Pubkey, key: &Pubkey, account: &mut Account) -> NeonResult<()> { diff --git a/evm_loader/program/src/account/legacy/update.rs b/evm_loader/program/src/account/legacy/update.rs index 19670df64..27e9ff817 100644 --- a/evm_loader/program/src/account/legacy/update.rs +++ b/evm_loader/program/src/account/legacy/update.rs @@ -17,18 +17,21 @@ pub fn from_before_revision<'a>( const PREFIX_BEFORE: usize = ACCOUNT_PREFIX_LEN_BEFORE_REVISION; const PREFIX_AFTER: usize = ACCOUNT_PREFIX_LEN; + assert!(account.data_len() > PREFIX_BEFORE); + let data_len = account.data_len() - PREFIX_BEFORE; + let required_len = account.data_len() + PREFIX_AFTER - PREFIX_BEFORE; account.realloc(required_len, false)?; - let minimum_balance = rent.minimum_balance(account.data_len()); + let minimum_balance = rent.minimum_balance(required_len); if account.lamports() < minimum_balance { let required_lamports = minimum_balance - account.lamports(); system.transfer(operator, account, required_lamports)?; } let mut account_data = account.try_borrow_mut_data()?; + account_data.copy_within(PREFIX_BEFORE..(PREFIX_BEFORE + data_len), PREFIX_AFTER); account_data[0] = new_tag; - account_data.copy_within(PREFIX_BEFORE.., PREFIX_AFTER); Ok(()) } From 7fae4ce9ebe183d011b7abf5dc7460dda7b05e99 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Tue, 27 Feb 2024 10:34:37 +0300 Subject: [PATCH 094/318] Update Solana SDK to v1.17 (#286) * Update Solana SDK to 1.17.23 and Rust to 1.73 --- .github/workflows/deploy.py | 4 +- Dockerfile | 2 +- evm_loader/Cargo.lock | 1716 ++++++++--------- evm_loader/api/Cargo.toml | 4 +- evm_loader/cli/Cargo.toml | 8 +- evm_loader/lib/Cargo.toml | 18 +- evm_loader/lib/src/commands/get_config.rs | 6 +- evm_loader/lib/src/commands/get_holder.rs | 2 +- evm_loader/lib/src/types/tracer_ch_common.rs | 2 +- evm_loader/program/Cargo.toml | 10 +- .../program/src/account/ether_storage.rs | 4 +- evm_loader/program/src/account/holder.rs | 2 +- evm_loader/program/src/account/mod.rs | 7 +- evm_loader/program/src/error.rs | 3 + evm_loader/program/src/evm/opcode.rs | 2 + .../program/src/evm/precompile/ecrecover.rs | 4 +- .../executor/precompile_extension/metaplex.rs | 141 +- evm_loader/program/src/executor/state.rs | 3 +- .../program/src/external_programs/metaplex.rs | 180 +- .../config_get_property_by_name.rs | 5 +- .../src/instruction/neon_tokens_deposit.rs | 6 +- evm_loader/program/src/types/transaction.rs | 4 +- rust-toolchain.toml | 2 +- 23 files changed, 1072 insertions(+), 1063 deletions(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index 20d7ef6a1..dbc64bf96 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -32,8 +32,8 @@ IMAGE_NAME = os.environ.get("IMAGE_NAME") RUN_LINK_REPO = os.environ.get("RUN_LINK_REPO") DOCKERHUB_ORG_NAME = os.environ.get("DOCKERHUB_ORG_NAME") -SOLANA_NODE_VERSION = 'v1.16.23' -SOLANA_BPF_VERSION = 'v1.16.23' +SOLANA_NODE_VERSION = 'v1.17.23' +SOLANA_BPF_VERSION = 'v1.17.23' VERSION_BRANCH_TEMPLATE = r"[vt]{1}\d{1,2}\.\d{1,2}\.x.*" docker_client = docker.APIClient() diff --git a/Dockerfile b/Dockerfile index 75f4656c4..0d44a9d57 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ ARG SOLANA_IMAGE # Install BPF SDK -FROM solanalabs/rust:1.69.0 AS builder +FROM solanalabs/rust:1.73.0 AS builder RUN cargo install rustfilt WORKDIR /opt ARG SOLANA_BPF_VERSION diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 617fa3580..850beb597 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -39,7 +39,7 @@ dependencies = [ "actix-rt", "actix-service", "actix-utils", - "ahash 0.8.3", + "ahash 0.8.5", "base64 0.21.4", "bitflags 2.4.0", "brotli", @@ -74,8 +74,8 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ - "quote 1.0.32", - "syn 2.0.28", + "quote", + "syn 2.0.50", ] [[package]] @@ -165,7 +165,7 @@ dependencies = [ "actix-service", "actix-utils", "actix-web-codegen", - "ahash 0.8.3", + "ahash 0.8.5", "bytes", "bytestring", "cfg-if", @@ -186,7 +186,7 @@ dependencies = [ "serde_urlencoded", "smallvec", "socket2 0.5.4", - "time 0.3.20", + "time", "url", ] @@ -197,9 +197,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb1f50ebbb30eca122b188319a4398b3f7bb4a8cdf50ecfb73bfc6a3c3ce54f5" dependencies = [ "actix-router", - "proc-macro2 1.0.66", - "quote 1.0.32", - "syn 2.0.28", + "proc-macro2", + "quote", + "syn 2.0.50", +] + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", ] [[package]] @@ -250,21 +259,22 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ - "getrandom 0.2.9", + "getrandom 0.2.12", "once_cell", "version_check", ] [[package]] name = "ahash" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +checksum = "cd7d5a2cecb58716e47d67d5703a249964b14c7be1ec3cad3affc295b2d1c35d" dependencies = [ "cfg-if", - "getrandom 0.2.9", + "getrandom 0.2.12", "once_cell", "version_check", + "zerocopy", ] [[package]] @@ -297,6 +307,12 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -362,7 +378,7 @@ dependencies = [ "derivative", "digest 0.10.7", "itertools 0.10.5", - "num-bigint 0.4.3", + "num-bigint 0.4.4", "num-traits", "paste", "rustc_version", @@ -375,7 +391,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" dependencies = [ - "quote 1.0.32", + "quote", "syn 1.0.109", ] @@ -385,10 +401,10 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" dependencies = [ - "num-bigint 0.4.3", + "num-bigint 0.4.4", "num-traits", - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -414,7 +430,7 @@ dependencies = [ "ark-serialize-derive", "ark-std", "digest 0.10.7", - "num-bigint 0.4.3", + "num-bigint 0.4.4", ] [[package]] @@ -423,8 +439,8 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -438,12 +454,6 @@ dependencies = [ "rand 0.8.5", ] -[[package]] -name = "array-bytes" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ad284aeb45c13f2fb4f084de4a420ebf447423bdf9386c0540ce33cb3ef4b8c" - [[package]] name = "arrayref" version = "0.3.7" @@ -452,9 +462,9 @@ checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" [[package]] name = "arrayvec" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "ascii" @@ -475,7 +485,7 @@ dependencies = [ "num-traits", "rusticata-macros", "thiserror", - "time 0.3.20", + "time", ] [[package]] @@ -484,8 +494,8 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "syn 1.0.109", "synstructure", ] @@ -496,8 +506,8 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -547,9 +557,9 @@ version = "0.1.74" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", - "syn 2.0.28", + "proc-macro2", + "quote", + "syn 2.0.50", ] [[package]] @@ -569,6 +579,21 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base64" version = "0.12.3" @@ -613,6 +638,9 @@ name = "bitflags" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +dependencies = [ + "serde", +] [[package]] name = "bitmaps" @@ -637,9 +665,9 @@ dependencies = [ [[package]] name = "blake3" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "199c42ab6972d92c9f8995f086273d25c42fc0f7b2a1fcefba465c1352d25ba5" +checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87" dependencies = [ "arrayref", "arrayvec", @@ -703,7 +731,7 @@ dependencies = [ "borsh-derive-internal 0.9.3", "borsh-schema-derive-internal 0.9.3", "proc-macro-crate 0.1.5", - "proc-macro2 1.0.66", + "proc-macro2", "syn 1.0.109", ] @@ -716,7 +744,7 @@ dependencies = [ "borsh-derive-internal 0.10.3", "borsh-schema-derive-internal 0.10.3", "proc-macro-crate 0.1.5", - "proc-macro2 1.0.66", + "proc-macro2", "syn 1.0.109", ] @@ -726,8 +754,8 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -737,8 +765,8 @@ version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -748,8 +776,8 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -759,8 +787,8 @@ version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -855,13 +883,13 @@ dependencies = [ "bincode", "build-info-common", "chrono", - "num-bigint 0.4.3", + "num-bigint 0.4.4", "num-traits", "proc-macro-error", - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "serde_json", - "syn 2.0.28", + "syn 2.0.50", "xz2", ] @@ -889,9 +917,9 @@ checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" [[package]] name = "bytemuck" -version = "1.14.0" +version = "1.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" +checksum = "a2ef034f05691a48569bd920a96c81b9d91bbad1ab5ac7c4616c1f6ef36cb79f" dependencies = [ "bytemuck_derive", ] @@ -902,9 +930,9 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", - "syn 2.0.28", + "proc-macro2", + "quote", + "syn 2.0.50", ] [[package]] @@ -915,9 +943,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "bytestring" @@ -1002,11 +1030,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.79" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ "jobserver", + "libc", ] [[package]] @@ -1017,18 +1046,17 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.24" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" +checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" dependencies = [ + "android-tzdata", "iana-time-zone", "js-sys", - "num-integer", "num-traits", "serde", - "time 0.1.45", "wasm-bindgen", - "winapi", + "windows-targets 0.52.3", ] [[package]] @@ -1117,8 +1145,8 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18af5425854858c507eec70f7deb4d5d8cec4216fcb086283a78872387281ea5" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "serde_derive_internals", "syn 1.0.109", ] @@ -1205,22 +1233,22 @@ checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" [[package]] name = "const_format" -version = "0.2.30" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7309d9b4d3d2c0641e018d449232f2e28f1b22933c137f157d3dbc14228b8c0e" +checksum = "e3a214c7af3d04997541b18d432afaff4c455e79e2029079647e72fc2bd27673" dependencies = [ "const_format_proc_macros", ] [[package]] name = "const_format_proc_macros" -version = "0.2.29" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f47bf7270cf70d370f8f98c1abb6d2d4cf60a6845d30e05bfb90c6568650" +checksum = "c7f6ff08fd20f4f299298a28e2dfa8a8ba1036e6cd2460ac1de7b425d76f2500" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", - "unicode-xid 0.2.4", + "proc-macro2", + "quote", + "unicode-xid", ] [[package]] @@ -1242,7 +1270,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" dependencies = [ "percent-encoding", - "time 0.3.20", + "time", "version_check", ] @@ -1416,10 +1444,10 @@ dependencies = [ "cc", "codespan-reporting", "once_cell", - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "scratch", - "syn 2.0.28", + "syn 2.0.50", ] [[package]] @@ -1434,9 +1462,9 @@ version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", - "syn 2.0.28", + "proc-macro2", + "quote", + "syn 2.0.50", ] [[package]] @@ -1457,10 +1485,10 @@ checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "strsim 0.10.0", - "syn 2.0.28", + "syn 2.0.50", ] [[package]] @@ -1470,8 +1498,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", - "quote 1.0.32", - "syn 2.0.28", + "quote", + "syn 2.0.50", ] [[package]] @@ -1509,7 +1537,7 @@ dependencies = [ "asn1-rs", "displaydoc", "nom", - "num-bigint 0.4.3", + "num-bigint 0.4.4", "num-traits", "rusticata-macros", ] @@ -1526,8 +1554,8 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -1538,8 +1566,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ "convert_case", - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "rustc_version", "syn 1.0.109", ] @@ -1618,32 +1646,32 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "syn 1.0.109", ] [[package]] -name = "dlopen" -version = "0.1.8" +name = "dlopen2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e80ad39f814a9abe68583cd50a2d45c8a67561c3361ab8da240587dda80937" +checksum = "09b4f5f101177ff01b8ec4ecc81eead416a8aa42819a2869311b3420fa114ffa" dependencies = [ - "dlopen_derive", - "lazy_static", + "dlopen2_derive", "libc", + "once_cell", "winapi", ] [[package]] -name = "dlopen_derive" -version = "0.1.4" +name = "dlopen2_derive" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f236d9e1b1fbd81cea0f9cbdc8dcc7e8ebcd80e6659cd7cb2ad5f6c05946c581" +checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" dependencies = [ - "libc", - "quote 0.6.13", - "syn 0.15.44", + "proc-macro2", + "quote", + "syn 2.0.50", ] [[package]] @@ -1684,7 +1712,7 @@ dependencies = [ "derivation-path", "ed25519-dalek", "hmac 0.12.1", - "sha2 0.10.6", + "sha2 0.10.8", ] [[package]] @@ -1694,16 +1722,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f0042ff8246a363dbe77d2ceedb073339e85a804b9a47636c6e016a9a32c05f" dependencies = [ "enum-ordinalize", - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "syn 1.0.109", ] [[package]] name = "either" -version = "1.8.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" [[package]] name = "encode_unicode" @@ -1735,9 +1763,9 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eecf8589574ce9b895052fa12d69af7a233f99e6107f5cb8dd1044f2a17bfdcb" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", - "syn 2.0.28", + "proc-macro2", + "quote", + "syn 2.0.50", ] [[package]] @@ -1746,11 +1774,11 @@ version = "3.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bf1fa3f06bbff1ea5b1a9c7b14aa992a39657db60a2759457328d7e058f49ee" dependencies = [ - "num-bigint 0.4.3", + "num-bigint 0.4.4", "num-traits", - "proc-macro2 1.0.66", - "quote 1.0.32", - "syn 2.0.28", + "proc-macro2", + "quote", + "syn 2.0.50", ] [[package]] @@ -1760,9 +1788,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f33313078bb8d4d05a2733a94ac4c2d8a0df9a2b84424ebf4f33bfc224a890e" dependencies = [ "once_cell", - "proc-macro2 1.0.66", - "quote 1.0.32", - "syn 2.0.28", + "proc-macro2", + "quote", + "syn 2.0.50", ] [[package]] @@ -1786,23 +1814,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ - "cc", "libc", + "windows-sys 0.52.0", ] [[package]] @@ -1871,7 +1888,7 @@ dependencies = [ "arrayref", "async-trait", "bincode", - "borsh 0.9.3", + "borsh 0.10.3", "cfg-if", "ethnum", "evm-loader-macro", @@ -1886,8 +1903,8 @@ dependencies = [ "serde_bytes", "serde_json", "solana-program", - "spl-associated-token-account 1.1.3", - "spl-token 3.5.0", + "spl-associated-token-account", + "spl-token", "static_assertions", "thiserror", "tokio", @@ -1899,8 +1916,8 @@ version = "1.0.0" dependencies = [ "bs58", "itertools 0.11.0", - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "serde", "syn 1.0.109", "toml 0.8.0", @@ -1908,12 +1925,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "1.9.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "feature-probe" @@ -1987,13 +2001,22 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] +[[package]] +name = "fs-err" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" +dependencies = [ + "autocfg", +] + [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -2060,9 +2083,9 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", - "syn 2.0.28", + "proc-macro2", + "quote", + "syn 2.0.50", ] [[package]] @@ -2137,9 +2160,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.9" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "js-sys", @@ -2148,6 +2171,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + [[package]] name = "git2" version = "0.17.2" @@ -2241,14 +2270,14 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash 0.8.3", + "ahash 0.8.5", ] [[package]] name = "hashbrown" -version = "0.14.0" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[package]] name = "headers" @@ -2298,15 +2327,6 @@ dependencies = [ "libc", ] -[[package]] -name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - [[package]] name = "hermit-abi" version = "0.3.1" @@ -2443,9 +2463,9 @@ dependencies = [ "futures-util", "http", "hyper", - "rustls 0.21.7", + "rustls", "tokio", - "tokio-rustls 0.24.1", + "tokio-rustls", ] [[package]] @@ -2493,9 +2513,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -2503,9 +2523,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -2560,8 +2580,8 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -2584,20 +2604,20 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.0" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" dependencies = [ "equivalent", - "hashbrown 0.14.0", + "hashbrown 0.14.3", "serde", ] [[package]] name = "indicatif" -version = "0.17.6" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b297dc40733f23a0e52728a58fa9489a5b7638a324932de16b41adc3ef80730" +checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" dependencies = [ "console", "instant", @@ -2615,17 +2635,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "io-lifetimes" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" -dependencies = [ - "hermit-abi 0.3.1", - "libc", - "windows-sys 0.48.0", -] - [[package]] name = "ipnet" version = "2.7.2" @@ -2712,9 +2721,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libgit2-sys" @@ -2788,6 +2797,18 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "light-poseidon" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c9a85a9752c549ceb7578064b4ed891179d20acd85f27318573b64d2d7ee7ee" +dependencies = [ + "ark-bn254", + "ark-ff", + "num-bigint 0.4.4", + "thiserror", +] + [[package]] name = "link-cplusplus" version = "1.0.8" @@ -2805,9 +2826,9 @@ checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286" [[package]] name = "linux-raw-sys" -version = "0.3.3" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b085a4f2cde5781fc4b1717f2e86c62f5cda49de7ba99a7c2eae02b61c9064c" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "local-channel" @@ -2838,12 +2859,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "lru" @@ -2900,16 +2918,16 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f1b8c13cb1f814b634a96b2c725449fe7ed464a7b8781de8688be5ffbd3f305" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "syn 1.0.109", ] [[package]] name = "memchr" -version = "2.5.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "memmap2" @@ -3008,81 +3026,24 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a7d5f7076603ebc68de2dc6a650ec331a062a13abaa346975be747bbfa4b789" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "syn 1.0.109", ] -[[package]] -name = "mpl-token-auth-rules" -version = "1.4.3-beta.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81a34d740606a10a9dac7507d0c9025d72e0ce311c68ae85b6634982cf69a9c6" -dependencies = [ - "borsh 0.9.3", - "bytemuck", - "mpl-token-metadata-context-derive 0.2.1", - "num-derive 0.3.3", - "num-traits", - "rmp-serde", - "serde", - "shank", - "solana-program", - "solana-zk-token-sdk", - "thiserror", -] - [[package]] name = "mpl-token-metadata" -version = "1.13.2" +version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "654976568c99887549e1291e7b7e55ae31a70732e56ebb25cb1cdfc08c018333" +checksum = "b4b2de608098eb2ef2a5392069dea83084967e25a4d69d0380a6bb02454fc0fe" dependencies = [ - "arrayref", - "borsh 0.9.3", - "mpl-token-auth-rules", - "mpl-token-metadata-context-derive 0.3.0", - "mpl-utils", + "borsh 0.10.3", "num-derive 0.3.3", "num-traits", - "shank", "solana-program", - "spl-associated-token-account 2.2.0", - "spl-token 4.0.0", "thiserror", ] -[[package]] -name = "mpl-token-metadata-context-derive" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12989bc45715b0ee91944855130131479f9c772e198a910c3eb0ea327d5bffc3" -dependencies = [ - "quote 1.0.32", - "syn 1.0.109", -] - -[[package]] -name = "mpl-token-metadata-context-derive" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a739019e11d93661a64ef5fe108ab17c79b35961e944442ff6efdd460ad01a" -dependencies = [ - "quote 1.0.32", - "syn 1.0.109", -] - -[[package]] -name = "mpl-utils" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f2e4f92aec317d5853c0cc4c03c55f5178511c45bb3dbb441aea63117bf3dc9" -dependencies = [ - "arrayref", - "solana-program", - "spl-token-2022 0.6.1", -] - [[package]] name = "native-tls" version = "0.2.11" @@ -3177,8 +3138,8 @@ dependencies = [ "solana-program-test", "solana-sdk", "solana-transaction-status", - "spl-associated-token-account 1.1.3", - "spl-token 3.5.0", + "spl-associated-token-account", + "spl-token", "thiserror", "tokio", "tracing", @@ -3187,16 +3148,15 @@ dependencies = [ [[package]] name = "nix" -version = "0.26.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" dependencies = [ "bitflags 1.3.2", "cfg-if", "libc", "memoffset 0.7.1", "pin-utils", - "static_assertions", ] [[package]] @@ -3257,9 +3217,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" dependencies = [ "autocfg", "num-integer", @@ -3282,8 +3242,8 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -3293,9 +3253,9 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfb77679af88f8b125209d354a202862602672222e7f2313fdd6dc349bad4712" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", - "syn 2.0.28", + "proc-macro2", + "quote", + "syn 2.0.50", ] [[package]] @@ -3333,32 +3293,23 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", ] [[package]] name = "num_cpus" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi 0.3.1", "libc", ] -[[package]] -name = "num_enum" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" -dependencies = [ - "num_enum_derive 0.5.11", -] - [[package]] name = "num_enum" version = "0.6.1" @@ -3377,18 +3328,6 @@ dependencies = [ "num_enum_derive 0.7.1", ] -[[package]] -name = "num_enum_derive" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro2 1.0.66", - "quote 1.0.32", - "syn 1.0.109", -] - [[package]] name = "num_enum_derive" version = "0.6.1" @@ -3396,9 +3335,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" dependencies = [ "proc-macro-crate 1.3.1", - "proc-macro2 1.0.66", - "quote 1.0.32", - "syn 2.0.28", + "proc-macro2", + "quote", + "syn 2.0.50", ] [[package]] @@ -3408,9 +3347,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c11e44798ad209ccdd91fc192f0526a369a01234f7373e1b141c96d7cee4f0e" dependencies = [ "proc-macro-crate 1.3.1", - "proc-macro2 1.0.66", - "quote 1.0.32", - "syn 2.0.28", + "proc-macro2", + "quote", + "syn 2.0.50", ] [[package]] @@ -3419,6 +3358,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + [[package]] name = "oid-registry" version = "0.6.1" @@ -3430,9 +3378,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.1" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opaque-debug" @@ -3461,9 +3409,9 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", - "syn 2.0.28", + "proc-macro2", + "quote", + "syn 2.0.50", ] [[package]] @@ -3527,8 +3475,8 @@ checksum = "5f7d21ccd03305a674437ee1248f3ab5d4b1db095cf1caf49f1713ddf61956b7" dependencies = [ "Inflector", "proc-macro-error", - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -3559,8 +3507,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a296c3079b5fefbc499e1de58dc26c09b1b9a5952d26694ee89f04a43ebbb3e" dependencies = [ "proc-macro-crate 1.3.1", - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -3622,9 +3570,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "percentage" @@ -3650,9 +3598,9 @@ version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", - "syn 2.0.28", + "proc-macro2", + "quote", + "syn 2.0.50", ] [[package]] @@ -3769,8 +3717,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "syn 1.0.109", "version_check", ] @@ -3781,25 +3729,16 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "version_check", ] [[package]] name = "proc-macro2" -version = "0.4.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -dependencies = [ - "unicode-xid 0.1.0", -] - -[[package]] -name = "proc-macro2" -version = "1.0.66" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] @@ -3813,72 +3752,72 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "qualifier_attr" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.50", +] + [[package]] name = "quinn" -version = "0.9.4" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e8b432585672228923edbbf64b8b12c14e1112f62e88737655b4a083dbcd78e" +checksum = "8cc2c5017e4b43d5995dcea317bc46c1e09404c0a9664d2908f7f02dfe943d75" dependencies = [ "bytes", "pin-project-lite", "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.20.8", + "rustls", "thiserror", "tokio", "tracing", - "webpki", ] [[package]] name = "quinn-proto" -version = "0.9.6" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b0b33c13a79f669c85defaf4c275dc86a0c0372807d0ca3d78e0bb87274863" +checksum = "141bf7dfde2fbc246bfd3fe12f2455aa24b0fbd9af535d8c86c7bd1381ff2b1a" dependencies = [ "bytes", "rand 0.8.5", "ring", "rustc-hash", - "rustls 0.20.8", + "rustls", "rustls-native-certs", "slab", "thiserror", "tinyvec", "tracing", - "webpki", ] [[package]] name = "quinn-udp" -version = "0.3.2" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "641538578b21f5e5c8ea733b736895576d0fe329bb883b937db6f4d163dbaaf4" +checksum = "055b4e778e8feb9f93c4e439f71dc2156ef13360b432b799e179a8c4cdf0b1d7" dependencies = [ + "bytes", "libc", - "quinn-proto", - "socket2 0.4.9", + "socket2 0.5.4", "tracing", - "windows-sys 0.42.0", -] - -[[package]] -name = "quote" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" -dependencies = [ - "proc-macro2 0.4.30", + "windows-sys 0.48.0", ] [[package]] name = "quote" -version = "1.0.32" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ - "proc-macro2 1.0.66", + "proc-macro2", ] [[package]] @@ -3974,7 +3913,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.9", + "getrandom 0.2.12", ] [[package]] @@ -4025,7 +3964,7 @@ checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" dependencies = [ "pem", "ring", - "time 0.3.20", + "time", "yasna", ] @@ -4062,21 +4001,21 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom 0.2.9", + "getrandom 0.2.12", "redox_syscall 0.2.16", "thiserror", ] [[package]] name = "regex" -version = "1.9.4" +version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.7", - "regex-syntax 0.7.5", + "regex-automata 0.4.5", + "regex-syntax 0.8.2", ] [[package]] @@ -4090,13 +4029,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.7" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" +checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.5", + "regex-syntax 0.8.2", ] [[package]] @@ -4107,9 +4046,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.5" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" @@ -4137,14 +4076,14 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls 0.21.7", + "rustls", "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", "tokio", "tokio-native-tls", - "tokio-rustls 0.24.1", + "tokio-rustls", "tokio-util 0.7.7", "tower-service", "url", @@ -4189,28 +4128,6 @@ dependencies = [ "rustc-hex", ] -[[package]] -name = "rmp" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44519172358fd6d58656c86ab8e7fbc9e1490c3e8f14d35ed78ca0dd07403c9f" -dependencies = [ - "byteorder", - "num-traits", - "paste", -] - -[[package]] -name = "rmp-serde" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5b13be192e0220b8afb7222aa5813cb62cc269ebb5cac346ca6487681d2913e" -dependencies = [ - "byteorder", - "rmp", - "serde", -] - [[package]] name = "rpassword" version = "7.2.0" @@ -4270,28 +4187,15 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.13" +version = "0.38.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f79bef90eb6d984c72722595b5b1348ab39275a5e5123faca6863bf07d75a4e0" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.0", "errno", - "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys 0.48.0", -] - -[[package]] -name = "rustls" -version = "0.20.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" -dependencies = [ - "log", - "ring", - "sct", - "webpki", + "windows-sys 0.52.0", ] [[package]] @@ -4339,9 +4243,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" @@ -4369,9 +4273,9 @@ dependencies = [ [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "scratch" @@ -4394,8 +4298,8 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bdbda6ac5cd1321e724fa9cee216f3a61885889b896f073b8f82322789c5250e" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -4416,8 +4320,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b5e421024b5e5edfbaa8e60ecf90bda9dbffc602dbb230e6028763f85f0c68c" dependencies = [ "heck 0.3.3", - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -4464,18 +4368,18 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.17" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.186" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f5db24220c009de9bd45e69fb2938f4b6d2df856aa9304ce377b3180f83b7c1" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] @@ -4491,13 +4395,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.186" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad697f7e0b65af4983a4ce8f56ed5b357e8d3c36651bf6a7e13639c17b8e670" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", - "syn 2.0.28", + "proc-macro2", + "quote", + "syn 2.0.50", ] [[package]] @@ -4506,8 +4410,8 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -4517,7 +4421,7 @@ version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ - "indexmap 2.0.0", + "indexmap 2.2.3", "itoa", "ryu", "serde", @@ -4564,11 +4468,11 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.0.0", + "indexmap 2.2.3", "serde", "serde_json", "serde_with_macros 3.3.0", - "time 0.3.20", + "time", ] [[package]] @@ -4578,9 +4482,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" dependencies = [ "darling", - "proc-macro2 1.0.66", - "quote 1.0.32", - "syn 2.0.28", + "proc-macro2", + "quote", + "syn 2.0.50", ] [[package]] @@ -4590,9 +4494,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e6be15c453eb305019bfa438b1593c731f36a289a7853f7707ee29e870b3b3c" dependencies = [ "darling", - "proc-macro2 1.0.66", - "quote 1.0.32", - "syn 2.0.28", + "proc-macro2", + "quote", + "syn 2.0.50", ] [[package]] @@ -4601,7 +4505,7 @@ version = "0.9.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a49e178e4452f45cb61d0cd8cebc1b0fafd3e41929e996cef79aa3aca91f574" dependencies = [ - "indexmap 2.0.0", + "indexmap 2.2.3", "itoa", "ryu", "serde", @@ -4621,17 +4525,6 @@ dependencies = [ "opaque-debug", ] -[[package]] -name = "sha-1" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.7", -] - [[package]] name = "sha1" version = "0.10.6" @@ -4658,9 +4551,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -4690,44 +4583,10 @@ dependencies = [ ] [[package]] -name = "shank" -version = "0.0.11" +name = "sharded-slab" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b63e565b5e95ad88ab38f312e89444c749360641c509ef2de0093b49f55974a5" -dependencies = [ - "shank_macro", -] - -[[package]] -name = "shank_macro" -version = "0.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63927d22a1e8b74bda98cc6e151fcdf178b7abb0dc6c4f81e0bbf5ffe2fc4ec8" -dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", - "shank_macro_impl", - "syn 1.0.109", -] - -[[package]] -name = "shank_macro_impl" -version = "0.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ce03403df682f80f4dc1efafa87a4d0cb89b03726d0565e6364bdca5b9a441" -dependencies = [ - "anyhow", - "proc-macro2 1.0.66", - "quote 1.0.32", - "serde", - "syn 1.0.109", -] - -[[package]] -name = "sharded-slab" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" dependencies = [ "lazy_static", ] @@ -4753,6 +4612,12 @@ version = "1.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + [[package]] name = "sized-chunks" version = "0.6.5" @@ -4810,14 +4675,14 @@ dependencies = [ "httparse", "log", "rand 0.8.5", - "sha-1 0.9.8", + "sha-1", ] [[package]] name = "solana-account-decoder" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "815b7eeb8cfc0cc27c3500658845bc0adbfb51a9212814af522f4912e1bdab2e" +checksum = "1328bff423d12d3e79c28fb6d2445e78a81b94fa0e6a00f55c232e6880e99fc7" dependencies = [ "Inflector", "base64 0.21.4", @@ -4828,21 +4693,80 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "solana-address-lookup-table-program", "solana-config-program", "solana-sdk", - "spl-token 4.0.0", - "spl-token-2022 0.9.0", + "spl-token", + "spl-token-2022", + "spl-token-group-interface", "spl-token-metadata-interface", "thiserror", "zstd 0.11.2+zstd.1.5.2", ] +[[package]] +name = "solana-accounts-db" +version = "1.17.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8e294c2550606565f377ddbd6eb73a18de8ef7275959c8f97d65dd36af4388c" +dependencies = [ + "arrayref", + "bincode", + "blake3", + "bv", + "bytemuck", + "byteorder", + "bzip2", + "crossbeam-channel", + "dashmap", + "flate2", + "fnv", + "fs-err", + "im", + "index_list", + "itertools 0.10.5", + "lazy_static", + "log", + "lz4", + "memmap2", + "modular-bitfield", + "num-derive 0.3.3", + "num-traits", + "num_cpus", + "num_enum 0.6.1", + "ouroboros", + "percentage", + "qualifier_attr", + "rand 0.8.5", + "rayon", + "regex", + "rustc_version", + "serde", + "serde_derive", + "solana-bucket-map", + "solana-config-program", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-measure", + "solana-metrics", + "solana-program-runtime", + "solana-rayon-threadlimit", + "solana-sdk", + "solana-stake-program", + "solana-system-program", + "solana-vote-program", + "static_assertions", + "strum", + "strum_macros", + "tar", + "tempfile", + "thiserror", +] + [[package]] name = "solana-address-lookup-table-program" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9137f2199f70e082f15f91076f31fa6e67d98d40168de759feab12c6b60542a8" +checksum = "667b651b78252d3e9122619bf5ef253b2d6d7b8b75aabacf3e0d156455b6b600" dependencies = [ "bincode", "bytemuck", @@ -4861,9 +4785,9 @@ dependencies = [ [[package]] name = "solana-banks-client" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "785bca4464357f3d7aad38b3f57b1dcec5fc47f7eb3e0c1ffba907ce15aae66c" +checksum = "eca976070af24713a15bac9e7ecaf7a2a0644e956c69c3eef30f12ab9a158f1c" dependencies = [ "borsh 0.10.3", "futures", @@ -4878,9 +4802,9 @@ dependencies = [ [[package]] name = "solana-banks-interface" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb13f6fff944f56df1c5b4bb708676efb856991bc368c969c436cc444e6f5e83" +checksum = "c352764389315b0470fb3fae72cdc52dc32493448ecf851ac7d18973764911cf" dependencies = [ "serde", "solana-sdk", @@ -4889,13 +4813,14 @@ dependencies = [ [[package]] name = "solana-banks-server" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "893926dda1a8d1594b55b753298df54fb9ed9ed1e802cac69ad3a225b7cdc63e" +checksum = "d1a3e65b1afc76e8c3b14d5123d0d079ab4ac67c055b66bc81f06ef4ed17b066" dependencies = [ "bincode", "crossbeam-channel", "futures", + "solana-accounts-db", "solana-banks-interface", "solana-client", "solana-runtime", @@ -4908,15 +4833,15 @@ dependencies = [ [[package]] name = "solana-bpf-loader-program" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb0ed3691420f8ca6c7d58eb1335ecb0b73b1b6188039b7b631bcd0253b24377" +checksum = "febc4e59de7367286d7a03591131158d28ab4d9aba78c235a28b9c221103709f" dependencies = [ "bincode", "byteorder", "libsecp256k1", "log", - "rand 0.7.3", + "scopeguard", "solana-measure", "solana-program-runtime", "solana-sdk", @@ -4927,16 +4852,17 @@ dependencies = [ [[package]] name = "solana-bucket-map" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b64e2a282391cffdd2985971abf571922fd58db5f2743014f8a0428f719af2" +checksum = "c5256f726ec34d70b5edf00fd053584328e224641ca61ae3936125f86dd65fdf" dependencies = [ "bv", + "bytemuck", "log", "memmap2", "modular-bitfield", "num_enum 0.6.1", - "rand 0.7.3", + "rand 0.8.5", "solana-measure", "solana-sdk", "tempfile", @@ -4944,14 +4870,13 @@ dependencies = [ [[package]] name = "solana-clap-utils" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a99a1aa397ec62a9b10f2f072fb95d78c6f4303bbca11d6af5f3f198e3d62e8" +checksum = "a2907b1af2a9490d7d3e5da72700190a1a10b05910c5c1d713e8ba3bf405b9c8" dependencies = [ "chrono", "clap 2.34.0", "rpassword", - "solana-perf", "solana-remote-wallet", "solana-sdk", "thiserror", @@ -4962,9 +4887,9 @@ dependencies = [ [[package]] name = "solana-cli" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "789d04c0c7ca0e7a023153416ddda71fc506077b976d2c262990a99a703e4db7" +checksum = "4bac779927ba228c54bc02a3f74e7348a6105f8cae011a80b1b5eb9cf0eb243b" dependencies = [ "bincode", "bs58", @@ -4985,7 +4910,6 @@ dependencies = [ "serde_derive", "serde_json", "solana-account-decoder", - "solana-address-lookup-table-program", "solana-bpf-loader-program", "solana-clap-utils", "solana-cli-config", @@ -4993,6 +4917,7 @@ dependencies = [ "solana-client", "solana-config-program", "solana-faucet", + "solana-loader-v4-program", "solana-logger", "solana-program-runtime", "solana-pubsub-client", @@ -5006,16 +4931,16 @@ dependencies = [ "solana-version", "solana-vote-program", "solana_rbpf", - "spl-memo 4.0.0", + "spl-memo", "thiserror", "tiny-bip39", ] [[package]] name = "solana-cli-config" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "864dce71e749d7a523eca56f8ee22c35fe8dae4c182c50a4a9e7acd49313ac48" +checksum = "e384865c29d86e3dd31c1858a886c8a071db3086488451af0f1bd5fff599f2c2" dependencies = [ "dirs-next", "lazy_static", @@ -5029,9 +4954,9 @@ dependencies = [ [[package]] name = "solana-cli-output" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d6338b80376eb99f4dbffed10a5f2efea2894704106f1a9c09891fab924770b" +checksum = "af26eb67b7b84df298861d463bd0db5d22bd637d888f5e9ab3f896f327469a81" dependencies = [ "Inflector", "base64 0.21.4", @@ -5051,24 +4976,24 @@ dependencies = [ "solana-sdk", "solana-transaction-status", "solana-vote-program", - "spl-memo 4.0.0", + "spl-memo", ] [[package]] name = "solana-client" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dd1d1b50f6937ec5b7b05faa171956dc052ad593d058de5046e325cc0ec4c23" +checksum = "33383b3ff0588d373040e6a35731bdd1d096c02decac856e4b998e91d716a87c" dependencies = [ "async-trait", "bincode", + "dashmap", "futures", "futures-util", - "indexmap 1.9.3", + "indexmap 2.2.3", "indicatif", "log", "quinn", - "rand 0.7.3", "rayon", "solana-connection-cache", "solana-measure", @@ -5089,9 +5014,9 @@ dependencies = [ [[package]] name = "solana-compute-budget-program" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "674cbca707a6a38dc860cef40b988debb24e0347a04cd123bd2b05cb6f75eed4" +checksum = "7e8707415788e82144ff5636fd7e3f2f548ca9fd6586d98d74c1f409f03bec84" dependencies = [ "solana-program-runtime", "solana-sdk", @@ -5099,9 +5024,9 @@ dependencies = [ [[package]] name = "solana-config-program" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7448528e2fd237e7d7ca93d4d8541a8a9f346b9f947405799d9a6dd5c22aa41c" +checksum = "b6ad48b3a77b3100b9bc8d4232d12701ebb01cc66b618967c0ec0e6383c685c2" dependencies = [ "bincode", "chrono", @@ -5113,16 +5038,17 @@ dependencies = [ [[package]] name = "solana-connection-cache" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a51fe3a80fc59a93392a103e6ab492305a6ac614abee70cde6e34fe74fc55dd" +checksum = "bdb5a74a77ee5009f0c21dcb2e020148b19dbae04d34f1660d182951f8c8fb50" dependencies = [ "async-trait", "bincode", + "crossbeam-channel", "futures-util", - "indexmap 1.9.3", + "indexmap 2.2.3", "log", - "rand 0.7.3", + "rand 0.8.5", "rayon", "rcgen", "solana-measure", @@ -5132,11 +5058,35 @@ dependencies = [ "tokio", ] +[[package]] +name = "solana-cost-model" +version = "1.17.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89a07b79a5cbc2f85a7213263c6be1d3684edd3a20419f3a2499cee7d354280b" +dependencies = [ + "lazy_static", + "log", + "rustc_version", + "solana-address-lookup-table-program", + "solana-bpf-loader-program", + "solana-compute-budget-program", + "solana-config-program", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-loader-v4-program", + "solana-metrics", + "solana-program-runtime", + "solana-sdk", + "solana-stake-program", + "solana-system-program", + "solana-vote-program", +] + [[package]] name = "solana-faucet" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69ac334bdd52ef3207d00bb2bc1a035b7161a3a06d20ecf110bd4e5cca26069" +checksum = "eaa67719562286bb6b8ceb2e53461c29e162e8f3c933cbe21bde23235894b567" dependencies = [ "bincode", "byteorder", @@ -5151,18 +5101,18 @@ dependencies = [ "solana-metrics", "solana-sdk", "solana-version", - "spl-memo 4.0.0", + "spl-memo", "thiserror", "tokio", ] [[package]] name = "solana-frozen-abi" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee8e68a37635d475c40f026bfbc39df3298ce91ec0f4db848979b1dbcd9bc675" +checksum = "d6d876fb3f4c87f27db285da29aaeedf487af543b46502578eb05d196351089a" dependencies = [ - "ahash 0.8.3", + "ahash 0.8.5", "blake3", "block-buffer 0.10.4", "bs58", @@ -5171,19 +5121,16 @@ dependencies = [ "cc", "either", "generic-array", - "getrandom 0.1.16", "im", "lazy_static", "log", "memmap2", - "once_cell", - "rand_core 0.6.4", "rustc_version", "serde", "serde_bytes", "serde_derive", "serde_json", - "sha2 0.10.6", + "sha2 0.10.8", "solana-frozen-abi-macro", "subtle", "thiserror", @@ -5191,24 +5138,23 @@ dependencies = [ [[package]] name = "solana-frozen-abi-macro" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07ea45edfe53a4d95f18bd627f1b60e200611a436afd0c58c9c529c085af8965" +checksum = "1a27e2a4b7a77da60cbafb304bb2baa9bace62d598613e33b7c57884b885b88f" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "rustc_version", - "syn 2.0.28", + "syn 2.0.50", ] [[package]] name = "solana-loader-v4-program" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4091f5bc56ecd65473ad5ae4f0bae43a5ea26b916a824eaf74909ed0b0154a7d" +checksum = "eac0cbe022710e9a2dff7e4d9b4c80d8fc2a192f33b0eaf6011bd577a2552416" dependencies = [ "log", - "rand 0.7.3", "solana-measure", "solana-program-runtime", "solana-sdk", @@ -5217,9 +5163,9 @@ dependencies = [ [[package]] name = "solana-logger" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9db83d89279b0620958ae1278fd52f340c68be79980a5f6ebfb3d4e4623d7241" +checksum = "73dfd133ceea9cf5680ec12ba57a7799de8485ed98872c6119f14d16763c6e79" dependencies = [ "env_logger", "lazy_static", @@ -5228,9 +5174,9 @@ dependencies = [ [[package]] name = "solana-measure" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f6745b818b9d2d88b0011ac5532e3dcd4cde0bd1613464ee1bcb98db423ab97" +checksum = "9bd22e62fed123d8fb69acc20cc432697e44adc72dddfd02e7508f7f9cab7f26" dependencies = [ "log", "solana-sdk", @@ -5238,9 +5184,9 @@ dependencies = [ [[package]] name = "solana-metrics" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5b3782e709a4546a77354e6b0fbc176a34f19b420e65c0d9c9c48f93459fbab" +checksum = "611d1984046d267513a15fd23f735710e1b251bc94bd2f8571c042c943d1da4d" dependencies = [ "crossbeam-channel", "gethostname", @@ -5248,23 +5194,24 @@ dependencies = [ "log", "reqwest", "solana-sdk", + "thiserror", ] [[package]] name = "solana-net-utils" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ea302ba1a7186826fecace83da4adce9b288e97ea370999a9aee2bfc71129b" +checksum = "46abbfacb7dd8a0b1881c43653aed39727a99c950dcb643295ccc85e793d7aa4" dependencies = [ "bincode", "clap 3.2.23", "crossbeam-channel", "log", - "nix 0.26.2", - "rand 0.7.3", + "nix 0.26.4", + "rand 0.8.5", "serde", "serde_derive", - "socket2 0.4.9", + "socket2 0.5.4", "solana-logger", "solana-sdk", "solana-version", @@ -5274,25 +5221,27 @@ dependencies = [ [[package]] name = "solana-perf" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42a5d5de014354c112349667c51f80ce01bca0c6b0bfa027cbc069e972c1c0c7" +checksum = "1051b18175b0981fabbb5c533c21b1c4d78a93cde65511069df4a07163f68aa3" dependencies = [ - "ahash 0.8.3", + "ahash 0.8.5", "bincode", "bv", "caps", "curve25519-dalek", - "dlopen", - "dlopen_derive", + "dlopen2", "fnv", "lazy_static", "libc", "log", - "nix 0.26.2", - "rand 0.7.3", + "nix 0.26.4", + "rand 0.8.5", "rayon", + "rustc_version", "serde", + "solana-frozen-abi", + "solana-frozen-abi-macro", "solana-metrics", "solana-rayon-threadlimit", "solana-sdk", @@ -5301,18 +5250,17 @@ dependencies = [ [[package]] name = "solana-program" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2560d24192b60301c1219c054a34bcd9d9723bb64ec9b5b987882d86c32868e6" +checksum = "7bf510602760dc760fb8b6475b3d51c7a6ba0b4e13ee074e96c4811f411b9582" dependencies = [ "ark-bn254", "ark-ec", "ark-ff", "ark-serialize", - "array-bytes", "base64 0.21.4", "bincode", - "bitflags 1.3.2", + "bitflags 2.4.0", "blake3", "borsh 0.10.3", "borsh 0.9.3", @@ -5323,27 +5271,27 @@ dependencies = [ "console_error_panic_hook", "console_log", "curve25519-dalek", - "getrandom 0.2.9", + "getrandom 0.2.12", "itertools 0.10.5", "js-sys", "lazy_static", "libc", "libsecp256k1", + "light-poseidon", "log", "memoffset 0.9.0", - "num-bigint 0.4.3", + "num-bigint 0.4.4", "num-derive 0.3.3", "num-traits", "parking_lot", - "rand 0.7.3", - "rand_chacha 0.2.2", + "rand 0.8.5", "rustc_version", "rustversion", "serde", "serde_bytes", "serde_derive", "serde_json", - "sha2 0.10.6", + "sha2 0.10.8", "sha3 0.10.7", "solana-frozen-abi", "solana-frozen-abi-macro", @@ -5356,9 +5304,9 @@ dependencies = [ [[package]] name = "solana-program-runtime" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1726697292d3f551898537f921749352e965510a9cfe7e7b2ff7f1a0fcc6e1db" +checksum = "872b506fec2ed7f1c5239f6b22a3a823679cdf9dab54b17d04bec24493861c4f" dependencies = [ "base64 0.21.4", "bincode", @@ -5370,7 +5318,7 @@ dependencies = [ "num-derive 0.3.3", "num-traits", "percentage", - "rand 0.7.3", + "rand 0.8.5", "rustc_version", "serde", "solana-frozen-abi", @@ -5384,9 +5332,9 @@ dependencies = [ [[package]] name = "solana-program-test" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66d071392c72f4e12527fa5e13e9ab9bd23a785eda1331a597277ee8f8c0800" +checksum = "96260a3e1f0c6cbcbb24a7aa7dbce880d762dffd19c629fb3ea5518797a38286" dependencies = [ "assert_matches", "async-trait", @@ -5396,6 +5344,7 @@ dependencies = [ "crossbeam-channel", "log", "serde", + "solana-accounts-db", "solana-banks-client", "solana-banks-interface", "solana-banks-server", @@ -5405,15 +5354,17 @@ dependencies = [ "solana-runtime", "solana-sdk", "solana-vote-program", + "solana_rbpf", + "test-case", "thiserror", "tokio", ] [[package]] name = "solana-pubsub-client" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f134152897fe6d3fad3da9945ae452dfc6c2d71465ddce1ad8a423d54ad38bee" +checksum = "af99e8f781c460e51198ec75842feb45bb68832f215b5bc091ca15e869474604" dependencies = [ "crossbeam-channel", "futures-util", @@ -5436,9 +5387,9 @@ dependencies = [ [[package]] name = "solana-quic-client" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "409c0182a32bb11acdf84c96361cff4628e93e7e8b293a8cc43e5ef354ffa46a" +checksum = "fd30628a2d4bf2c8a058b6cd9e8e7c9547d341507c5ef8a3ed242692aa3f80e8" dependencies = [ "async-mutex", "async-trait", @@ -5448,9 +5399,8 @@ dependencies = [ "log", "quinn", "quinn-proto", - "quinn-udp", "rcgen", - "rustls 0.20.8", + "rustls", "solana-connection-cache", "solana-measure", "solana-metrics", @@ -5464,9 +5414,9 @@ dependencies = [ [[package]] name = "solana-rayon-threadlimit" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce5c2d7f4e92580e6dd18877f0cd5f152e662dbda9c2eed69d29ae9a6f6e5d0" +checksum = "6d2146d364a57123db3712bb5a67957cded933bed5e6b768ef79745bb13790cf" dependencies = [ "lazy_static", "num_cpus", @@ -5474,9 +5424,9 @@ dependencies = [ [[package]] name = "solana-remote-wallet" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a9e49486e3f31009cfd24869de318e0fac261257f0e87e6f692e0bbf6a053b6" +checksum = "e4335d48797fa2a03f1308c5ed55c2f8eaf8d3e16226ce3b9f4fb3ae19e02a0d" dependencies = [ "console", "dialoguer", @@ -5494,9 +5444,9 @@ dependencies = [ [[package]] name = "solana-rpc-client" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "336cdd2dbb4dcfdb7c905eb45fdd32de30f594b12f00d894160a8e4d12fc76a3" +checksum = "e2192eed56e9829591a425ac1150352346ad0036333f02ec58befcad4dd62ef2" dependencies = [ "async-trait", "base64 0.21.4", @@ -5520,9 +5470,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-api" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0cc64f5092d9c3e0bbfbd459689ffc17617b9f52773ffb7e26a2483a33d5ace" +checksum = "148e4878747e42cceaa84baba799d9b8317619dbb84710c938c71ed950f78d08" dependencies = [ "base64 0.21.4", "bs58", @@ -5536,15 +5486,15 @@ dependencies = [ "solana-sdk", "solana-transaction-status", "solana-version", - "spl-token-2022 0.9.0", + "spl-token-2022", "thiserror", ] [[package]] name = "solana-rpc-client-nonce-utils" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c54440695e2a3b14749b52f2021172aeb2387f8bd95f4e0cc2f97e5d27b5ea4" +checksum = "ca8e2522d0cbc503fbef9bb8dff78aef870f97d3d6d6a619fd5723502c01ddae" dependencies = [ "clap 2.34.0", "solana-clap-utils", @@ -5555,9 +5505,9 @@ dependencies = [ [[package]] name = "solana-runtime" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63578440eb0526fc3b3155be56c33dec115d8739e0964ec563a8ae8c80b4ffd2" +checksum = "58e34d07dd0f14a8168df48f9286b3a5ac4ae361b90a62a6bc7ce907ab93b288" dependencies = [ "arrayref", "base64 0.21.4", @@ -5572,6 +5522,7 @@ dependencies = [ "dir-diff", "flate2", "fnv", + "fs-err", "im", "index_list", "itertools 0.10.5", @@ -5585,21 +5536,24 @@ dependencies = [ "num-traits", "num_cpus", "num_enum 0.6.1", - "once_cell", "ouroboros", "percentage", - "rand 0.7.3", + "qualifier_attr", + "rand 0.8.5", "rayon", "regex", "rustc_version", "serde", "serde_derive", "serde_json", + "siphasher", + "solana-accounts-db", "solana-address-lookup-table-program", "solana-bpf-loader-program", "solana-bucket-map", "solana-compute-budget-program", "solana-config-program", + "solana-cost-model", "solana-frozen-abi", "solana-frozen-abi-macro", "solana-loader-v4-program", @@ -5612,6 +5566,7 @@ dependencies = [ "solana-stake-program", "solana-system-program", "solana-version", + "solana-vote", "solana-vote-program", "solana-zk-token-proof-program", "solana-zk-token-sdk", @@ -5627,14 +5582,14 @@ dependencies = [ [[package]] name = "solana-sdk" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fc9581f8345a67da71386274084d9a2e35f25689871ad644f5992c786df7c7" +checksum = "804dc98b9e5bfde2ca20675f6fc75cabbc520766bda369e253dd0a56a1228106" dependencies = [ "assert_matches", "base64 0.21.4", "bincode", - "bitflags 1.3.2", + "bitflags 2.4.0", "borsh 0.10.3", "bs58", "bytemuck", @@ -5657,8 +5612,9 @@ dependencies = [ "num_enum 0.6.1", "pbkdf2 0.11.0", "qstring", + "qualifier_attr", "rand 0.7.3", - "rand_chacha 0.2.2", + "rand 0.8.5", "rustc_version", "rustversion", "serde", @@ -5666,7 +5622,7 @@ dependencies = [ "serde_derive", "serde_json", "serde_with 2.3.3", - "sha2 0.10.6", + "sha2 0.10.8", "sha3 0.10.7", "solana-frozen-abi", "solana-frozen-abi-macro", @@ -5680,22 +5636,28 @@ dependencies = [ [[package]] name = "solana-sdk-macro" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d749979b74d6ca1d8b0f1da1d0333332cfac425a34d71ed1149cccc322e0533" +checksum = "5243f26d84a7c81472482dc1fafad97d531ba81d3c086b0a201d36ead9c73472" dependencies = [ "bs58", - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "rustversion", - "syn 2.0.28", + "syn 2.0.50", ] +[[package]] +name = "solana-security-txt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" + [[package]] name = "solana-send-transaction-service" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9dad2cb6f9462e7e1c9900df76b9ad601b199aab3d26855d28bf8494698def3" +checksum = "301c844f470bcf187019321def9e78be775c9d60b978cc42f1fb9b3a3a55089c" dependencies = [ "crossbeam-channel", "log", @@ -5709,9 +5671,9 @@ dependencies = [ [[package]] name = "solana-stake-program" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ec54610fafa934717e90e8ab0774867b054d4c3852b5ca24d5947edf14a61e1" +checksum = "4bea6bc0d5b5e03ed55b9a55efbe1ed31a30dd13afbc54e42beb0d59cbbf97f7" dependencies = [ "bincode", "log", @@ -5724,29 +5686,28 @@ dependencies = [ [[package]] name = "solana-streamer" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a848b9b56af99988e6273ccf79f2bd816633dc3da9ea0eb4488a5b0f8ec820" +checksum = "6e54f2e4f990c4af272649ed8de1aac16e4a86cff4781c6ba8ab2bde97f555a9" dependencies = [ "async-channel", "bytes", "crossbeam-channel", "futures-util", "histogram", - "indexmap 1.9.3", + "indexmap 2.2.3", "itertools 0.10.5", "libc", "log", - "nix 0.26.2", + "nix 0.26.4", "pem", "percentage", "pkcs8", "quinn", "quinn-proto", - "quinn-udp", - "rand 0.7.3", + "rand 0.8.5", "rcgen", - "rustls 0.20.8", + "rustls", "solana-metrics", "solana-perf", "solana-sdk", @@ -5757,9 +5718,9 @@ dependencies = [ [[package]] name = "solana-system-program" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a427a441f95ee0b9d8e2065a2978d86142c6fa40cbdccd1de724f77b6cc885af" +checksum = "969d0f17f952d4637fd378d3851ffc725affa933578342d60c1c63a5e39aa09e" dependencies = [ "bincode", "log", @@ -5771,9 +5732,9 @@ dependencies = [ [[package]] name = "solana-thin-client" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5db5ba7eddcc0cefc3c5c116387097cb81bb13d7598fbdb3b40c5a964105e879" +checksum = "82f608ca246c269826c6c9e656b516cea7c4cadaaa93bc618fc2853dff5c9b2d" dependencies = [ "bincode", "log", @@ -5786,17 +5747,16 @@ dependencies = [ [[package]] name = "solana-tpu-client" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bdf56494fd1b509c5428f969a10e4e0865b3eaf40aac1640c8f72dac3112b89" +checksum = "ce2edc9eda28483d3df9f81a0df9dfdaaa901e8e1dc67cca08347a20c4d6bb9d" dependencies = [ "async-trait", "bincode", "futures-util", - "indexmap 1.9.3", + "indexmap 2.2.3", "indicatif", "log", - "rand 0.7.3", "rayon", "solana-connection-cache", "solana-measure", @@ -5811,9 +5771,9 @@ dependencies = [ [[package]] name = "solana-transaction-status" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d3c52eaa1977b0121a099243de4b5b44de936e67869d3298400fb6e974a2f7b" +checksum = "24e030da0ce03190dcc88976beb88b7c4171df743ace669a7b0c17a74f3b7308" dependencies = [ "Inflector", "base64 0.21.4", @@ -5826,20 +5786,19 @@ dependencies = [ "serde_derive", "serde_json", "solana-account-decoder", - "solana-address-lookup-table-program", "solana-sdk", - "spl-associated-token-account 2.2.0", - "spl-memo 4.0.0", - "spl-token 4.0.0", - "spl-token-2022 0.9.0", + "spl-associated-token-account", + "spl-memo", + "spl-token", + "spl-token-2022", "thiserror", ] [[package]] name = "solana-udp-client" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1225fb057b8b5e5aa5b0ee01b974e6ef2c6f01727dfd217c23b89b6547a8b17b" +checksum = "8120e28208a12f7a4429c9c03f4bac15bed89ecb91a37008e686597dfd88ae6a" dependencies = [ "async-trait", "solana-connection-cache", @@ -5852,9 +5811,9 @@ dependencies = [ [[package]] name = "solana-version" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f7b09ffc8f5446bee6ee1ab4ce4c98504d23222313de1d0ed762f736a3ffe3" +checksum = "6294848afd9ff8c36296f41633a59b45145ebe4c235013377b78f63267146034" dependencies = [ "log", "rustc_version", @@ -5866,11 +5825,30 @@ dependencies = [ "solana-sdk", ] +[[package]] +name = "solana-vote" +version = "1.17.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee90f71f4a6257aaf06e0cd5cc35873602a6d5f82408d537f0bf609c8cd877c0" +dependencies = [ + "crossbeam-channel", + "itertools 0.10.5", + "log", + "rustc_version", + "serde", + "serde_derive", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-sdk", + "solana-vote-program", + "thiserror", +] + [[package]] name = "solana-vote-program" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2be239ebe1d73af268ce9ba5111ce9595a430aa98576105e87b00e92a5ef2a0b" +checksum = "04b5b6063d5bd743b9bd62db49ce4a3c0a5aee4f4b995572f8ceb3426dcd9576" dependencies = [ "bincode", "log", @@ -5890,12 +5868,11 @@ dependencies = [ [[package]] name = "solana-zk-token-proof-program" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a813c2c577b9eb24b62d7149d1e5340425f55650f3ff6a01eb2ded828a95774" +checksum = "eee2446fba39f1effca8ba2bf74be1bb767f2649fd5b09aa62b143721ccb87a4" dependencies = [ "bytemuck", - "getrandom 0.1.16", "num-derive 0.3.3", "num-traits", "solana-program-runtime", @@ -5905,9 +5882,9 @@ dependencies = [ [[package]] name = "solana-zk-token-sdk" -version = "1.16.23" +version = "1.17.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4b0547480462cfec9dddaa8adcf2fa7c8b022021738bf71c790c0c7be54a34" +checksum = "dfa5d13db62ccc05172c0b95b384a3bdbfb724e72b3f90b4b8c673ac72efc2cf" dependencies = [ "aes-gcm-siv", "base64 0.21.4", @@ -5934,9 +5911,9 @@ dependencies = [ [[package]] name = "solana_rbpf" -version = "0.6.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17d4ba1e58947346e360fabde0697029d36ba83c42f669199b16a8931313cf29" +checksum = "3d457cc2ba742c120492a64b7fa60e22c575e891f6b55039f4d736568fb112a3" dependencies = [ "byteorder", "combine", @@ -5969,33 +5946,17 @@ dependencies = [ [[package]] name = "spl-associated-token-account" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978dba3bcbe88d0c2c58366c254d9ea41c5f73357e72fc0bdee4d6b5fc99c8f4" -dependencies = [ - "assert_matches", - "borsh 0.9.3", - "num-derive 0.3.3", - "num-traits", - "solana-program", - "spl-token 3.5.0", - "spl-token-2022 0.6.1", - "thiserror", -] - -[[package]] -name = "spl-associated-token-account" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "385e31c29981488f2820b2022d8e731aae3b02e6e18e2fd854e4c9a94dc44fc3" +checksum = "992d9c64c2564cc8f63a4b508bf3ebcdf2254b0429b13cd1d31adb6162432a5f" dependencies = [ "assert_matches", "borsh 0.10.3", "num-derive 0.4.1", "num-traits", "solana-program", - "spl-token 4.0.0", - "spl-token-2022 0.9.0", + "spl-token", + "spl-token-2022", "thiserror", ] @@ -6016,9 +5977,9 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fadbefec4f3c678215ca72bd71862697bb06b41fd77c0088902dd3203354387b" dependencies = [ - "quote 1.0.32", + "quote", "spl-discriminator-syn", - "syn 2.0.28", + "syn 2.0.50", ] [[package]] @@ -6027,22 +5988,13 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e5f2044ca42c8938d54d1255ce599c79a1ffd86b677dfab695caa20f9ffc3f2" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", - "sha2 0.10.6", - "syn 2.0.28", + "proc-macro2", + "quote", + "sha2 0.10.8", + "syn 2.0.50", "thiserror", ] -[[package]] -name = "spl-memo" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd0dc6f70db6bacea7ff25870b016a65ba1d1b6013536f08e4fd79a8f9005325" -dependencies = [ - "solana-program", -] - [[package]] name = "spl-memo" version = "4.0.0" @@ -6084,17 +6036,17 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5269c8e868da17b6552ef35a51355a017bd8e0eae269c201fef830d35fa52c" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", - "sha2 0.10.6", - "syn 2.0.28", + "proc-macro2", + "quote", + "sha2 0.10.8", + "syn 2.0.50", ] [[package]] name = "spl-tlv-account-resolution" -version = "0.4.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "062e148d3eab7b165582757453632ffeef490c02c86a48bfdb4988f63eefb3b9" +checksum = "56f335787add7fa711819f9e7c573f8145a5358a709446fe2d24bf2a88117c90" dependencies = [ "bytemuck", "solana-program", @@ -6104,21 +6056,6 @@ dependencies = [ "spl-type-length-value", ] -[[package]] -name = "spl-token" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e85e168a785e82564160dcb87b2a8e04cee9bfd1f4d488c729d53d6a4bd300d" -dependencies = [ - "arrayref", - "bytemuck", - "num-derive 0.3.3", - "num-traits", - "num_enum 0.5.11", - "solana-program", - "thiserror", -] - [[package]] name = "spl-token" version = "4.0.0" @@ -6136,42 +6073,39 @@ dependencies = [ [[package]] name = "spl-token-2022" -version = "0.6.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0043b590232c400bad5ee9eb983ced003d15163c4c5d56b090ac6d9a57457b47" +checksum = "d697fac19fd74ff472dfcc13f0b442dd71403178ce1de7b5d16f83a33561c059" dependencies = [ "arrayref", "bytemuck", - "num-derive 0.3.3", + "num-derive 0.4.1", "num-traits", - "num_enum 0.5.11", + "num_enum 0.7.1", "solana-program", + "solana-security-txt", "solana-zk-token-sdk", - "spl-memo 3.0.1", - "spl-token 3.5.0", + "spl-memo", + "spl-pod", + "spl-token", + "spl-token-group-interface", + "spl-token-metadata-interface", + "spl-transfer-hook-interface", + "spl-type-length-value", "thiserror", ] [[package]] -name = "spl-token-2022" -version = "0.9.0" +name = "spl-token-group-interface" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4abf34a65ba420584a0c35f3903f8d727d1f13ababbdc3f714c6b065a686e86" +checksum = "b889509d49fa74a4a033ca5dae6c2307e9e918122d97e58562f5c4ffa795c75d" dependencies = [ - "arrayref", "bytemuck", - "num-derive 0.4.1", - "num-traits", - "num_enum 0.7.1", "solana-program", - "solana-zk-token-sdk", - "spl-memo 4.0.0", + "spl-discriminator", "spl-pod", - "spl-token 4.0.0", - "spl-token-metadata-interface", - "spl-transfer-hook-interface", - "spl-type-length-value", - "thiserror", + "spl-program-error", ] [[package]] @@ -6190,9 +6124,9 @@ dependencies = [ [[package]] name = "spl-transfer-hook-interface" -version = "0.3.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "051d31803f873cabe71aec3c1b849f35248beae5d19a347d93a5c9cccc5d5a9b" +checksum = "7aabdb7c471566f6ddcee724beb8618449ea24b399e58d464d6b5bc7db550259" dependencies = [ "arrayref", "bytemuck", @@ -6251,8 +6185,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "rustversion", "syn 1.0.109", ] @@ -6269,36 +6203,25 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" -[[package]] -name = "syn" -version = "0.15.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" -dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", - "unicode-xid 0.1.0", -] - [[package]] name = "syn" version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.28" +version = "2.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" +checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "unicode-ident", ] @@ -6308,10 +6231,10 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "syn 1.0.109", - "unicode-xid 0.2.4", + "unicode-xid", ] [[package]] @@ -6361,22 +6284,21 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee42b4e559f17bce0385ebf511a7beb67d5cc33c12c96b7f4e9789919d9c10f" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "syn 1.0.109", ] [[package]] name = "tempfile" -version = "3.5.0" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" dependencies = [ "cfg-if", "fastrand", - "redox_syscall 0.3.5", "rustix", - "windows-sys 0.45.0", + "windows-sys 0.52.0", ] [[package]] @@ -6388,6 +6310,39 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "test-case" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb2550dd13afcd286853192af8601920d959b14c401fcece38071d53bf0768a8" +dependencies = [ + "test-case-macros", +] + +[[package]] +name = "test-case-core" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adcb7fd841cd518e279be3d5a3eb0636409487998a4aff22f3de87b81e88384f" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "syn 2.0.50", +] + +[[package]] +name = "test-case-macros" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.50", + "test-case-core", +] + [[package]] name = "textwrap" version = "0.11.0" @@ -6405,22 +6360,22 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", - "syn 2.0.28", + "proc-macro2", + "quote", + "syn 2.0.50", ] [[package]] @@ -6439,17 +6394,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "time" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" -dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", -] - [[package]] name = "time" version = "0.3.20" @@ -6522,11 +6466,12 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.27.0" +version = "1.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001" +checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" dependencies = [ "autocfg", + "backtrace", "bytes", "libc", "mio", @@ -6536,18 +6481,18 @@ dependencies = [ "signal-hook-registry", "socket2 0.4.9", "tokio-macros", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a573bdc87985e9d6ddeed1b3d864e8a302c847e40d647746df2f1de209d1ce" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", - "syn 2.0.28", + "proc-macro2", + "quote", + "syn 2.0.50", ] [[package]] @@ -6560,24 +6505,13 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-rustls" -version = "0.23.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" -dependencies = [ - "rustls 0.20.8", - "tokio", - "webpki", -] - [[package]] name = "tokio-rustls" version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls 0.21.7", + "rustls", "tokio", ] @@ -6599,9 +6533,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.12" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" dependencies = [ "futures-core", "pin-project-lite", @@ -6610,18 +6544,17 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.17.2" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f714dd15bead90401d77e04243611caec13726c2408afd5b31901dfcdcb3b181" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" dependencies = [ "futures-util", "log", - "rustls 0.20.8", + "rustls", "tokio", - "tokio-rustls 0.23.4", + "tokio-rustls", "tungstenite", - "webpki", - "webpki-roots 0.22.6", + "webpki-roots 0.25.2", ] [[package]] @@ -6701,7 +6634,7 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ff63e60a958cefbb518ae1fd6566af80d9d4be430a33f3723dfc47d1d411d95" dependencies = [ - "indexmap 2.0.0", + "indexmap 2.2.3", "serde", "serde_spanned", "toml_datetime", @@ -6754,7 +6687,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09d48f71a791638519505cefafe162606f706c25592e4bde4d97600c0195312e" dependencies = [ "crossbeam-channel", - "time 0.3.20", + "time", "tracing-subscriber", ] @@ -6764,8 +6697,8 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -6829,24 +6762,23 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "tungstenite" -version = "0.17.3" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e27992fd6a8c29ee7eef28fc78349aa244134e10ad447ce3b9f0ac0ed0fa4ce0" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" dependencies = [ - "base64 0.13.1", "byteorder", "bytes", + "data-encoding", "http", "httparse", "log", "rand 0.8.5", - "rustls 0.20.8", - "sha-1 0.10.1", + "rustls", + "sha1", "thiserror", "url", "utf-8", - "webpki", - "webpki-roots 0.22.6", + "webpki-roots 0.24.0", ] [[package]] @@ -6900,12 +6832,6 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" - [[package]] name = "unicode-xid" version = "0.2.4" @@ -6955,12 +6881,12 @@ dependencies = [ [[package]] name = "url" -version = "2.3.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", - "idna 0.3.0", + "idna 0.5.0", "percent-encoding", ] @@ -6976,7 +6902,7 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" dependencies = [ - "getrandom 0.2.9", + "getrandom 0.2.12", ] [[package]] @@ -7035,12 +6961,6 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -7066,9 +6986,9 @@ dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2 1.0.66", - "quote 1.0.32", - "syn 2.0.28", + "proc-macro2", + "quote", + "syn 2.0.50", "wasm-bindgen-shared", ] @@ -7090,7 +7010,7 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ - "quote 1.0.32", + "quote", "wasm-bindgen-macro-support", ] @@ -7100,9 +7020,9 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", - "syn 2.0.28", + "proc-macro2", + "quote", + "syn 2.0.50", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -7171,23 +7091,13 @@ dependencies = [ "url", ] -[[package]] -name = "webpki" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "webpki-roots" -version = "0.22.6" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" +checksum = "b291546d5d9d1eab74f069c77749f2cb8504a12caa20f0f2de93ddbf6f411888" dependencies = [ - "webpki", + "rustls-webpki", ] [[package]] @@ -7269,6 +7179,15 @@ dependencies = [ "windows-targets 0.48.0", ] +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.3", +] + [[package]] name = "windows-targets" version = "0.42.2" @@ -7299,6 +7218,21 @@ dependencies = [ "windows_x86_64_msvc 0.48.0", ] +[[package]] +name = "windows-targets" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f" +dependencies = [ + "windows_aarch64_gnullvm 0.52.3", + "windows_aarch64_msvc 0.52.3", + "windows_i686_gnu 0.52.3", + "windows_i686_msvc 0.52.3", + "windows_x86_64_gnu 0.52.3", + "windows_x86_64_gnullvm 0.52.3", + "windows_x86_64_msvc 0.52.3", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" @@ -7311,6 +7245,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -7323,6 +7263,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f" + [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -7335,6 +7281,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +[[package]] +name = "windows_i686_gnu" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb" + [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -7347,6 +7299,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +[[package]] +name = "windows_i686_msvc" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -7359,6 +7317,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -7371,6 +7335,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -7383,6 +7353,12 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6" + [[package]] name = "winnow" version = "0.4.1" @@ -7435,7 +7411,7 @@ dependencies = [ "oid-registry", "rusticata-macros", "thiserror", - "time 0.3.20", + "time", ] [[package]] @@ -7468,7 +7444,27 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" dependencies = [ - "time 0.3.20", + "time", +] + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.50", ] [[package]] @@ -7486,9 +7482,9 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", - "syn 2.0.28", + "proc-macro2", + "quote", + "syn 2.0.50", ] [[package]] diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 417f7ceba..5ea81cedd 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -8,8 +8,8 @@ edition = "2021" [dependencies] clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } -solana-sdk = "=1.16.23" -solana-client = "=1.16.23" +solana-sdk = "=1.17.23" +solana-client = "=1.17.23" serde = "1.0.186" serde_json = { version = "1.0.107", features = ["preserve_order"] } ethnum = { version = "1.4", default-features = false, features = ["serde"] } diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index 593c1b94d..d19b12bd0 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -8,10 +8,10 @@ edition = "2021" [dependencies] clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } -solana-sdk = "=1.16.23" -solana-client = "=1.16.23" -solana-clap-utils = "=1.16.23" -solana-cli-config = "=1.16.23" +solana-sdk = "=1.17.23" +solana-client = "=1.17.23" +solana-clap-utils = "=1.17.23" +solana-cli-config = "=1.17.23" hex = "0.4.2" serde = "1.0.186" serde_json = { version = "1.0.107", features = ["preserve_order"] } diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index df35d7614..f567077a9 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -10,15 +10,15 @@ thiserror = "1.0" anyhow = "1.0" bincode = "1.3.1" evm-loader = { path = "../program", default-features = false, features = ["log", "async-trait"] } -solana-sdk = "=1.16.23" -solana-client = "=1.16.23" -solana-clap-utils = "=1.16.23" -solana-cli-config = "=1.16.23" -solana-cli = "=1.16.23" -solana-transaction-status = "=1.16.23" -solana-program-test = "=1.16.23" -spl-token = { version = "~3.5", default-features = false, features = ["no-entrypoint"] } -spl-associated-token-account = { version = "~1.1", default-features = false, features = ["no-entrypoint"] } +solana-sdk = "=1.17.23" +solana-client = "=1.17.23" +solana-clap-utils = "=1.17.23" +solana-cli-config = "=1.17.23" +solana-cli = "=1.17.23" +solana-transaction-status = "=1.17.23" +solana-program-test = "=1.17.23" +spl-token = { version = "~4.0", default-features = false, features = ["no-entrypoint"] } +spl-associated-token-account = { version = "~2.3", default-features = false, features = ["no-entrypoint"] } bs58 = "0.4.0" base64 = "0.21" hex = { version = "0.4", features = ["serde"] } diff --git a/evm_loader/lib/src/commands/get_config.rs b/evm_loader/lib/src/commands/get_config.rs index 3934ce22b..f8e404823 100644 --- a/evm_loader/lib/src/commands/get_config.rs +++ b/evm_loader/lib/src/commands/get_config.rs @@ -68,11 +68,11 @@ impl CallDbClient { } if let Ok(UpgradeableLoaderState::Program { - programdata_address, + programdata_address: address, }) = account.state() { - let Some(programdata_account) = self.get_account(&programdata_address).await?.value else { - return Err(NeonError::AssociatedPdaNotFound(programdata_address, program_id)); + let Some(programdata_account) = self.get_account(&address).await?.value else { + return Err(NeonError::AssociatedPdaNotFound(address, program_id)); }; let offset = UpgradeableLoaderState::size_of_programdata_metadata(); diff --git a/evm_loader/lib/src/commands/get_holder.rs b/evm_loader/lib/src/commands/get_holder.rs index aa1cddb25..c58adb69f 100644 --- a/evm_loader/lib/src/commands/get_holder.rs +++ b/evm_loader/lib/src/commands/get_holder.rs @@ -124,7 +124,7 @@ pub async fn execute( ) -> NeonResult { let response = rpc.get_account(&address).await?; let Some(mut account) = response.value else { - return Ok(GetHolderResponse::empty()) + return Ok(GetHolderResponse::empty()); }; let info = account_info(&address, &mut account); diff --git a/evm_loader/lib/src/types/tracer_ch_common.rs b/evm_loader/lib/src/types/tracer_ch_common.rs index d61897d25..ad251156c 100644 --- a/evm_loader/lib/src/types/tracer_ch_common.rs +++ b/evm_loader/lib/src/types/tracer_ch_common.rs @@ -191,7 +191,7 @@ impl RevisionMap { return None; } - let value = self.map.range(..=slot).rev().next(); + let value = self.map.range(..=slot).next_back(); value.map(|(_, v)| v.clone()) } diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 2cb4e8486..a82b8f557 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -37,17 +37,17 @@ default = ["custom-heap"] [dependencies] linked_list_allocator = { version = "0.10", default-features = false } evm-loader-macro = { path = "../program-macro" } -solana-program = { version = "=1.16.23", default-features = false } -spl-token = { version = "~3.5", default-features = false, features = ["no-entrypoint"] } -spl-associated-token-account = { version = "~1.1", default-features = false, features = ["no-entrypoint"] } -mpl-token-metadata = { version = "1.13.2", default-features = false, features = ["no-entrypoint"] } +solana-program = { version = "=1.17.23", default-features = false } +spl-token = { version = "~4.0", default-features = false, features = ["no-entrypoint"] } +spl-associated-token-account = { version = "~2.3", default-features = false, features = ["no-entrypoint"] } +mpl-token-metadata = { version = "~4.1", default-features = false } thiserror = "1.0" arrayref = "0.3.6" hex = "0.4.2" ripemd = "0.1" rlp = "0.5" static_assertions = "1" -borsh = "0.9" +borsh = "0.10" bincode = "1" serde_bytes = "0.11.12" serde = { version = "1.0.186", default-features = false, features = ["derive", "rc"] } diff --git a/evm_loader/program/src/account/ether_storage.rs b/evm_loader/program/src/account/ether_storage.rs index 1e6b1dc97..e8300aaf0 100644 --- a/evm_loader/program/src/account/ether_storage.rs +++ b/evm_loader/program/src/account/ether_storage.rs @@ -167,7 +167,7 @@ impl<'a> StorageCell<'a> { #[must_use] pub fn get(&self, subindex: u8) -> [u8; 32] { - for cell in self.cells().iter() { + for cell in &*self.cells() { if cell.subindex != subindex { continue; } @@ -181,7 +181,7 @@ impl<'a> StorageCell<'a> { pub fn update(&mut self, subindex: u8, value: &[u8; 32]) -> Result<()> { // todo: if value is zero - destroy cell - for cell in self.cells_mut().iter_mut() { + for cell in &mut *self.cells_mut() { if cell.subindex != subindex { continue; } diff --git a/evm_loader/program/src/account/holder.rs b/evm_loader/program/src/account/holder.rs index 2d015555d..2a9e30a55 100644 --- a/evm_loader/program/src/account/holder.rs +++ b/evm_loader/program/src/account/holder.rs @@ -116,7 +116,7 @@ impl<'a> Holder<'a> { { let mut buffer = self.buffer_mut(); let Some(buffer) = buffer.get_mut(begin..end) else { - return Err(Error::HolderInsufficientSize(buffer.len(), end)) + return Err(Error::HolderInsufficientSize(buffer.len(), end)); }; buffer.copy_from_slice(bytes); diff --git a/evm_loader/program/src/account/mod.rs b/evm_loader/program/src/account/mod.rs index 0be5568cd..e1a566f47 100644 --- a/evm_loader/program/src/account/mod.rs +++ b/evm_loader/program/src/account/mod.rs @@ -238,9 +238,10 @@ impl<'a> AccountsDB<'a> { #[must_use] pub fn get(&self, pubkey: &Pubkey) -> &AccountInfo<'a> { - let Ok(index) = self.sorted_accounts.binary_search_by_key(&pubkey, |a| a.key) else { - panic!("address {pubkey} must be present in the transaction"); - }; + let index = self + .sorted_accounts + .binary_search_by_key(&pubkey, |a| a.key) + .unwrap_or_else(|_| panic!("address {pubkey} must be present in the transaction")); // We just got an 'index' from the binary_search over this vector. unsafe { self.sorted_accounts.get_unchecked(index) } diff --git a/evm_loader/program/src/error.rs b/evm_loader/program/src/error.rs index fdf64bccb..c0afb84f7 100644 --- a/evm_loader/program/src/error.rs +++ b/evm_loader/program/src/error.rs @@ -34,6 +34,9 @@ pub enum Error { #[error("Bincode error: {0}")] BincodeError(#[from] bincode::Error), + #[error("IO error: {0}")] + BorshError(#[from] std::io::Error), + #[error("FromHexError error: {0}")] FromHexError(#[from] hex::FromHexError), diff --git a/evm_loader/program/src/evm/opcode.rs b/evm_loader/program/src/evm/opcode.rs index 38941e9eb..2206cf82f 100644 --- a/evm_loader/program/src/evm/opcode.rs +++ b/evm_loader/program/src/evm/opcode.rs @@ -1,3 +1,5 @@ +#![allow(clippy::needless_pass_by_ref_mut)] + /// use ethnum::{I256, U256}; use maybe_async::maybe_async; diff --git a/evm_loader/program/src/evm/precompile/ecrecover.rs b/evm_loader/program/src/evm/precompile/ecrecover.rs index 425d074b0..2f8140325 100644 --- a/evm_loader/program/src/evm/precompile/ecrecover.rs +++ b/evm_loader/program/src/evm/precompile/ecrecover.rs @@ -26,7 +26,9 @@ pub fn ecrecover(input: &[u8]) -> Vec { let recovery_id = v.as_u8() - 27; - let Ok(public_key) = secp256k1_recover(&msg[..], recovery_id, &sig[..]) else { return vec![] }; + let Ok(public_key) = secp256k1_recover(&msg[..], recovery_id, &sig[..]) else { + return vec![]; + }; let mut address = keccak::hash(&public_key.to_bytes()).to_bytes(); address[0..12].fill(0); diff --git a/evm_loader/program/src/executor/precompile_extension/metaplex.rs b/evm_loader/program/src/executor/precompile_extension/metaplex.rs index be7ed8194..48fe2fd51 100644 --- a/evm_loader/program/src/executor/precompile_extension/metaplex.rs +++ b/evm_loader/program/src/executor/precompile_extension/metaplex.rs @@ -3,9 +3,12 @@ use std::convert::{Into, TryInto}; use ethnum::U256; use maybe_async::maybe_async; -use mpl_token_metadata::state::{ - Creator, Metadata, TokenMetadataAccount, TokenStandard, CREATE_FEE, MAX_MASTER_EDITION_LEN, - MAX_METADATA_LEN, +use mpl_token_metadata::{ + accounts::{MasterEdition, Metadata}, + instructions::{CreateMasterEditionV3Builder, CreateMetadataAccountV3Builder}, + programs::MPL_TOKEN_METADATA_ID, + types::{Creator, DataV2, TokenStandard}, + MAX_CREATOR_LEN, MAX_CREATOR_LIMIT, MAX_NAME_LENGTH, MAX_SYMBOL_LENGTH, MAX_URI_LENGTH, }; use solana_program::pubkey::Pubkey; @@ -17,6 +20,37 @@ use crate::{ types::Address, }; +// TODO: Use solana-program-test in the emulator to calculate fee +// instead of relying on the hardcoded constants +const CREATE_FEE: u64 = 10_000_000; + +const MAX_DATA_SIZE: usize = 4 + + MAX_NAME_LENGTH + + 4 + + MAX_SYMBOL_LENGTH + + 4 + + MAX_URI_LENGTH + + 2 + + 1 + + 4 + + MAX_CREATOR_LIMIT * MAX_CREATOR_LEN; + +const MAX_METADATA_LEN: usize = 1 // key + + 32 // update auth pubkey + + 32 // mint pubkey + + MAX_DATA_SIZE + + 1 // primary sale + + 1 // mutable + + 9 // nonce (pretty sure this only needs to be 2) + + 2 // token standard + + 34 // collection + + 18 // uses + + 10 // collection details + + 33 // programmable config + + 75; // Padding + +pub const MAX_MASTER_EDITION_LEN: usize = 1 + 9 + 8 + 264; + // "[0xc5, 0x73, 0x50, 0xc6]": "createMetadata(bytes32,string,string,string)" // "[0x4a, 0xe8, 0xb6, 0x6b]": "createMasterEdition(bytes32,uint64)" // "[0xf7, 0xb6, 0x37, 0xbb]": "isInitialized(bytes32)" @@ -161,37 +195,36 @@ impl ExecutorState<'_, B> { vec![bump_seed], ]; - let (metadata_pubkey, _) = mpl_token_metadata::pda::find_metadata_account(&mint); - - let instruction = mpl_token_metadata::instruction::create_metadata_accounts_v3( - mpl_token_metadata::ID, - metadata_pubkey, - mint, - signer_pubkey, - self.backend.operator(), - signer_pubkey, - name, - symbol, - uri, - Some(vec![ - Creator { - address: *self.backend.program_id(), - verified: false, - share: 0, - }, - Creator { - address: signer_pubkey, - verified: true, - share: 100, - }, - ]), - 0, // Seller Fee - true, // Update Authority == Mint Authority - false, // Is Mutable - None, // Collection - None, // Uses - None, // Collection Details - ); + let (metadata_pubkey, _) = Metadata::find_pda(&mint); + + let instruction = CreateMetadataAccountV3Builder::new() + .metadata(metadata_pubkey) + .mint(mint) + .mint_authority(signer_pubkey) + .update_authority(signer_pubkey, true) + .payer(self.backend.operator()) + .is_mutable(true) + .data(DataV2 { + name, + symbol, + uri, + seller_fee_basis_points: 0, + creators: Some(vec![ + Creator { + address: *self.backend.program_id(), + verified: false, + share: 0, + }, + Creator { + address: signer_pubkey, + verified: true, + share: 100, + }, + ]), + collection: None, + uses: None, + }) + .instruction(); let fee = self.backend.rent().minimum_balance(MAX_METADATA_LEN) + CREATE_FEE; self.queue_external_instruction(instruction, seeds, fee); @@ -214,19 +247,23 @@ impl ExecutorState<'_, B> { vec![bump_seed], ]; - let (metadata_pubkey, _) = mpl_token_metadata::pda::find_metadata_account(&mint); - let (edition_pubkey, _) = mpl_token_metadata::pda::find_master_edition_account(&mint); - - let instruction = mpl_token_metadata::instruction::create_master_edition_v3( - mpl_token_metadata::ID, - edition_pubkey, - mint, - signer_pubkey, - signer_pubkey, - metadata_pubkey, - self.backend.operator(), - max_supply, - ); + let (metadata_pubkey, _) = Metadata::find_pda(&mint); + let (edition_pubkey, _) = MasterEdition::find_pda(&mint); + + let mut instruction_builder = CreateMasterEditionV3Builder::new(); + instruction_builder + .metadata(metadata_pubkey) + .edition(edition_pubkey) + .mint(mint) + .mint_authority(signer_pubkey) + .update_authority(signer_pubkey) + .payer(self.backend.operator()); + + if let Some(max_supply) = max_supply { + instruction_builder.max_supply(max_supply); + } + + let instruction = instruction_builder.instruction(); let fee = self.backend.rent().minimum_balance(MAX_MASTER_EDITION_LEN) + CREATE_FEE; self.queue_external_instruction(instruction, seeds, fee); @@ -263,7 +300,7 @@ impl ExecutorState<'_, B> { let uri = self .metadata(context, mint) .await? - .map_or_else(String::new, |m| m.data.uri); + .map_or_else(String::new, |m| m.uri); Ok(to_solidity_string(uri.trim_end_matches('\0'))) } @@ -273,7 +310,7 @@ impl ExecutorState<'_, B> { let token_name = self .metadata(context, mint) .await? - .map_or_else(String::new, |m| m.data.name); + .map_or_else(String::new, |m| m.name); Ok(to_solidity_string(token_name.trim_end_matches('\0'))) } @@ -283,7 +320,7 @@ impl ExecutorState<'_, B> { let symbol = self .metadata(context, mint) .await? - .map_or_else(String::new, |m| m.data.symbol); + .map_or_else(String::new, |m| m.symbol); Ok(to_solidity_string(symbol.trim_end_matches('\0'))) } @@ -294,11 +331,11 @@ impl ExecutorState<'_, B> { _context: &crate::evm::Context, mint: Pubkey, ) -> Result> { - let (metadata_pubkey, _) = mpl_token_metadata::pda::find_metadata_account(&mint); + let (metadata_pubkey, _) = Metadata::find_pda(&mint); let metadata_account = self.external_account(metadata_pubkey).await?; let result = { - if mpl_token_metadata::check_id(&metadata_account.owner) { + if MPL_TOKEN_METADATA_ID == metadata_account.owner { let metadata = Metadata::safe_deserialize(&metadata_account.data); metadata.ok() } else { diff --git a/evm_loader/program/src/executor/state.rs b/evm_loader/program/src/executor/state.rs index 6c25f57c3..c9e09ebbd 100644 --- a/evm_loader/program/src/executor/state.rs +++ b/evm_loader/program/src/executor/state.rs @@ -3,6 +3,7 @@ use std::collections::BTreeMap; use ethnum::{AsU256, U256}; use maybe_async::maybe_async; +use mpl_token_metadata::programs::MPL_TOKEN_METADATA_ID; use solana_program::instruction::Instruction; use solana_program::pubkey::Pubkey; use solana_program::rent::Rent; @@ -159,7 +160,7 @@ impl<'a, B: AccountStorage> ExecutorState<'a, B> { self.rent(), )?; } - program_id if mpl_token_metadata::check_id(program_id) => { + program_id if &MPL_TOKEN_METADATA_ID == program_id => { crate::external_programs::metaplex::emulate( data, meta, diff --git a/evm_loader/program/src/external_programs/metaplex.rs b/evm_loader/program/src/external_programs/metaplex.rs index a9fe278b8..08b681294 100644 --- a/evm_loader/program/src/external_programs/metaplex.rs +++ b/evm_loader/program/src/external_programs/metaplex.rs @@ -1,49 +1,48 @@ +use crate::error::Result; use borsh::{BorshDeserialize, BorshSerialize}; -use mpl_token_metadata::assertions::collection::assert_collection_update_is_valid; -use mpl_token_metadata::assertions::uses::assert_valid_use; -use mpl_token_metadata::utils::{assert_data_valid, assert_initialized, puff_out_data_fields}; -use solana_program::account_info::IntoAccountInfo; +use mpl_token_metadata::{ + accounts::{MasterEdition, Metadata}, + instructions::{CreateMasterEditionV3InstructionArgs, CreateMetadataAccountV3InstructionArgs}, + programs::MPL_TOKEN_METADATA_ID, + types::{Key, TokenStandard}, +}; use solana_program::instruction::AccountMeta; use solana_program::program_option::COption; use solana_program::rent::Rent; -use spl_token::state::Mint; +use solana_program::{account_info::IntoAccountInfo, program_pack::Pack}; use std::collections::BTreeMap; use crate::executor::OwnedAccountInfo; -use mpl_token_metadata::instruction::{ - CreateMasterEditionArgs, CreateMetadataAccountArgsV3, MetadataInstruction, -}; -use mpl_token_metadata::state::{ - Key, MasterEditionV2, Metadata, TokenMetadataAccount, TokenStandard, MAX_MASTER_EDITION_LEN, - MAX_METADATA_LEN, -}; -use solana_program::{ - entrypoint::ProgramResult, program_error::ProgramError, program_pack::Pack, pubkey::Pubkey, -}; +use solana_program::pubkey::Pubkey; pub fn emulate( instruction: &[u8], meta: &[AccountMeta], accounts: &mut BTreeMap, rent: &Rent, -) -> ProgramResult { - match MetadataInstruction::try_from_slice(instruction)? { - MetadataInstruction::CreateMetadataAccountV3(args) => { - create_metadata_accounts_v3(meta, accounts, &args, rent) +) -> Result<()> { + let discriminator = instruction[0]; + let data = &instruction[1..]; + + match discriminator { + 33 => { + let args = CreateMetadataAccountV3InstructionArgs::try_from_slice(data)?; + create_metadata_accounts_v3(meta, accounts, args, rent) } - MetadataInstruction::CreateMasterEditionV3(args) => { - create_master_edition_v3(meta, accounts, &args, rent) + 17 => { + let args = CreateMasterEditionV3InstructionArgs::try_from_slice(data)?; + create_master_edition_v3(meta, accounts, args.max_supply, rent) } - _ => Err!(ProgramError::InvalidInstructionData; "Unknown Metaplex instruction"), + _ => Err("Unknown Metaplex instruction".into()), } } fn create_metadata_accounts_v3( meta: &[AccountMeta], accounts: &mut BTreeMap, - args: &CreateMetadataAccountArgsV3, + args: CreateMetadataAccountV3InstructionArgs, rent: &Rent, -) -> ProgramResult { +) -> Result<()> { let metadata_account_key = &meta[0].pubkey; let mint_key = &meta[1].pubkey; // let _mint_authority_key = &meta[2].pubkey; @@ -52,68 +51,40 @@ fn create_metadata_accounts_v3( // let _system_account_key = &meta[5].pubkey; // let _rent_key = &meta[6].pubkey; - let mut metadata: Metadata = { - let metadata_account = accounts.get_mut(metadata_account_key).unwrap(); - metadata_account.data.resize(MAX_METADATA_LEN, 0); - metadata_account.owner = mpl_token_metadata::ID; - metadata_account.lamports = metadata_account - .lamports - .max(rent.minimum_balance(MAX_METADATA_LEN)); - - let metadata_account_info = metadata_account.into_account_info(); - Metadata::from_account_info(&metadata_account_info)? - }; - - let mint: Mint = { + let mint = { let mint_info = accounts.get_mut(mint_key).unwrap().into_account_info(); - assert_initialized(&mint_info)? + crate::account::token::Mint::from_account(&mint_info)?.into_data() }; - let compatible_data = args.data.to_v1(); - assert_data_valid( - &compatible_data, - update_authority_key, - &metadata, - false, - meta[4].is_signer, - )?; - - metadata.mint = *mint_key; - metadata.key = Key::MetadataV1; - metadata.data = compatible_data; - metadata.is_mutable = args.is_mutable; - metadata.update_authority = *update_authority_key; - - assert_valid_use(&args.data.uses, &None)?; - metadata.uses = args.data.uses.clone(); - - assert_collection_update_is_valid(false, &None, &args.data.collection)?; - metadata.collection = args.data.collection.clone(); - metadata.collection_details = None; - - let token_standard = if mint.decimals == 0 { - TokenStandard::FungibleAsset - } else { - TokenStandard::Fungible + let (_, edition_bump_seed) = MasterEdition::find_pda(mint_key); + + let metadata = Metadata { + key: Key::MetadataV1, + update_authority: *update_authority_key, + mint: *mint_key, + name: args.data.name, + symbol: args.data.symbol, + uri: args.data.uri, + seller_fee_basis_points: args.data.seller_fee_basis_points, + creators: args.data.creators, + primary_sale_happened: false, + is_mutable: args.is_mutable, + edition_nonce: Some(edition_bump_seed), + token_standard: if mint.decimals == 0 { + Some(TokenStandard::FungibleAsset) + } else { + Some(TokenStandard::Fungible) + }, + collection: args.data.collection, + uses: args.data.uses, + collection_details: args.collection_details, + programmable_config: None, }; - metadata.token_standard = Some(token_standard); - puff_out_data_fields(&mut metadata); - - let edition_seeds = &[ - mpl_token_metadata::state::PREFIX.as_bytes(), - mpl_token_metadata::ID.as_ref(), - metadata.mint.as_ref(), - mpl_token_metadata::state::EDITION.as_bytes(), - ]; - let (_, edition_bump_seed) = - Pubkey::find_program_address(edition_seeds, &mpl_token_metadata::ID); - metadata.edition_nonce = Some(edition_bump_seed); - - { - let metadata_account = accounts.get_mut(metadata_account_key).unwrap(); - metadata.serialize(&mut metadata_account.data.as_mut_slice())?; - } + let metadata_account = accounts.get_mut(metadata_account_key).unwrap(); + metadata_account.owner = MPL_TOKEN_METADATA_ID; + metadata_account.data = metadata.try_to_vec()?; + metadata_account.lamports = rent.minimum_balance(metadata_account.data.len()); Ok(()) } @@ -121,9 +92,9 @@ fn create_metadata_accounts_v3( fn create_master_edition_v3( meta: &[AccountMeta], accounts: &mut BTreeMap, - args: &CreateMasterEditionArgs, + max_supply: Option, rent: &Rent, -) -> ProgramResult { +) -> Result<()> { let edition_account_key = &meta[0].pubkey; let mint_key = &meta[1].pubkey; // let update_authority_key = &meta[2].pubkey; @@ -135,53 +106,48 @@ fn create_master_edition_v3( // let _rent_key = &meta[8].pubkey; let mut metadata: Metadata = { - let metadata_info = accounts - .get_mut(metadata_account_key) - .unwrap() - .into_account_info(); - Metadata::from_account_info(&metadata_info)? + let metadata_account = accounts.get_mut(metadata_account_key).unwrap(); + Metadata::from_bytes(&metadata_account.data)? }; - let mut mint: Mint = { + let mut mint = { let mint_info = accounts.get_mut(mint_key).unwrap().into_account_info(); - assert_initialized(&mint_info)? + crate::account::token::Mint::from_account(&mint_info)?.into_data() }; if &metadata.mint != mint_key { - return Err!(ProgramError::InvalidArgument; "Metaplex: Invalid token mint"); + return Err("Metaplex: Invalid token mint".into()); } if mint.decimals != 0 { - return Err!(ProgramError::InvalidArgument; "Metaplex: mint decimals != 0"); + return Err("Metaplex: mint decimals != 0".into()); } if mint.supply != 1 { - return Err!(ProgramError::InvalidArgument; "Metaplex: mint supply != 1"); + return Err("Metaplex: mint supply != 1".into()); } + let edition = MasterEdition { + key: Key::MasterEditionV2, + supply: 0, + max_supply, + }; + + // Master Edition Account { let edition_account = accounts.get_mut(edition_account_key).unwrap(); - edition_account.data.resize(MAX_MASTER_EDITION_LEN, 0); - edition_account.owner = mpl_token_metadata::ID; - edition_account.lamports = edition_account - .lamports - .max(rent.minimum_balance(MAX_MASTER_EDITION_LEN)); - - let edition = MasterEditionV2 { - key: Key::MasterEditionV2, - supply: 0, - max_supply: args.max_supply, - }; - edition.serialize(&mut edition_account.data.as_mut_slice())?; + edition_account.owner = MPL_TOKEN_METADATA_ID; + edition_account.data = edition.try_to_vec()?; + edition_account.lamports = rent.minimum_balance(edition_account.data.len()); } - + // Metadata Account { let metadata_account = accounts.get_mut(metadata_account_key).unwrap(); metadata.token_standard = Some(TokenStandard::NonFungible); metadata.serialize(&mut metadata_account.data.as_mut_slice())?; } - + // Mint Account { mint.mint_authority = COption::Some(*edition_account_key); if mint.freeze_authority.is_some() { diff --git a/evm_loader/program/src/instruction/config_get_property_by_name.rs b/evm_loader/program/src/instruction/config_get_property_by_name.rs index e4397b2e9..fdd09d4ac 100644 --- a/evm_loader/program/src/instruction/config_get_property_by_name.rs +++ b/evm_loader/program/src/instruction/config_get_property_by_name.rs @@ -1,5 +1,6 @@ use solana_program::{account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey}; +use crate::config::PARAMETERS; use crate::error::Result; pub fn process<'a>( @@ -11,11 +12,11 @@ pub fn process<'a>( let requested_property = std::str::from_utf8(instruction)?; - let Ok(index) = crate::config::PARAMETERS.binary_search_by(|p| p.0.cmp(requested_property)) else { + let Ok(index) = PARAMETERS.binary_search_by(|p| p.0.cmp(requested_property)) else { return Err(ProgramError::InvalidArgument.into()); }; - let (name, value) = crate::config::PARAMETERS[index]; + let (name, value) = PARAMETERS[index]; assert_eq!(requested_property, name); solana_program::program::set_return_data(value.as_bytes()); diff --git a/evm_loader/program/src/instruction/neon_tokens_deposit.rs b/evm_loader/program/src/instruction/neon_tokens_deposit.rs index bfab10115..dd524b66c 100644 --- a/evm_loader/program/src/instruction/neon_tokens_deposit.rs +++ b/evm_loader/program/src/instruction/neon_tokens_deposit.rs @@ -5,7 +5,7 @@ use solana_program::{account_info::AccountInfo, pubkey::Pubkey, rent::Rent, sysv use spl_associated_token_account::get_associated_token_address; use crate::account::{program, token, AccountsDB, BalanceAccount, Operator, ACCOUNT_SEED_VERSION}; -use crate::config::DEFAULT_CHAIN_ID; +use crate::config::{CHAIN_ID_LIST, DEFAULT_CHAIN_ID}; use crate::error::{Error, Result}; use crate::types::Address; @@ -77,11 +77,11 @@ fn validate( return Err(Error::AccountInvalidKey(contract_account, expected_pubkey)); } - let Ok(chain_id_index) = crate::config::CHAIN_ID_LIST.binary_search_by_key(&chain_id, |c| c.0) else { + let Ok(chain_id_index) = CHAIN_ID_LIST.binary_search_by_key(&chain_id, |c| c.0) else { return Err(Error::InvalidChainId(chain_id)); }; - let expected_mint = crate::config::CHAIN_ID_LIST[chain_id_index].2; + let expected_mint = CHAIN_ID_LIST[chain_id_index].2; if mint != expected_mint { return Err(Error::AccountInvalidKey(mint, expected_mint)); } diff --git a/evm_loader/program/src/types/transaction.rs b/evm_loader/program/src/types/transaction.rs index c3d82173e..0e5bba532 100644 --- a/evm_loader/program/src/types/transaction.rs +++ b/evm_loader/program/src/types/transaction.rs @@ -221,7 +221,7 @@ impl rlp::Decodable for AccessListTx { let rlp_access_list = rlp.at(7)?; let mut access_list = vec![]; - for entry in rlp_access_list.iter() { + for entry in &rlp_access_list { // Check if entry is a list if entry.is_list() { // Parse address from first element @@ -230,7 +230,7 @@ impl rlp::Decodable for AccessListTx { // Get storage keys from second element let mut storage_keys: Vec = vec![]; - for key in entry.at(1)?.iter() { + for key in &entry.at(1)? { storage_keys.push(key.as_val()?); } diff --git a/rust-toolchain.toml b/rust-toolchain.toml index f2415f831..50fa4928b 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.69.0" +channel = "1.73" From 699c6aec58a60e589e52796e65cafaa370a8b64d Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Tue, 27 Feb 2024 17:23:19 +0300 Subject: [PATCH 095/318] Remove GetLargestAccounts RPC request (#271) --- ci/deploy-evm.sh | 1 + ci/docker-compose-ci.yml | 6 +- ci/docker-compose-test.yml | 6 +- ci/solana-run-neon.sh | 1 + evm_loader/api/src/api_server/state.rs | 10 +-- evm_loader/api/src/main.rs | 5 +- evm_loader/cli/src/config.rs | 12 ++- evm_loader/cli/src/main.rs | 9 ++- evm_loader/cli/src/program_options.rs | 10 +++ evm_loader/lib/src/commands/get_config.rs | 63 +++++++--------- evm_loader/lib/src/config.rs | 88 +++++----------------- evm_loader/lib/src/errors.rs | 3 + evm_loader/lib/src/rpc/validator_client.rs | 41 +++++++--- 13 files changed, 116 insertions(+), 139 deletions(-) diff --git a/ci/deploy-evm.sh b/ci/deploy-evm.sh index 64c5efe59..e51015ddc 100755 --- a/ci/deploy-evm.sh +++ b/ci/deploy-evm.sh @@ -29,4 +29,5 @@ fi echo "Deployed finished from " $(solana address) " with " $(solana balance) neon-cli --url $SOLANA_URL --evm_loader $EVM_LOADER \ --keypair evm_loader-keypair.json \ + --solana_key_for_config BMp6gEnveANdvSvspESJUrNczuHz1GF5UQKjVLCkAZih \ --loglevel debug init-environment --send-trx --keys-dir keys/ diff --git a/ci/docker-compose-ci.yml b/ci/docker-compose-ci.yml index a43a98a1b..a6351e0be 100644 --- a/ci/docker-compose-ci.yml +++ b/ci/docker-compose-ci.yml @@ -31,12 +31,10 @@ services: NEON_API_LISTENER_ADDR: 0.0.0.0:8085 SOLANA_URL: http://solana:8899 EVM_LOADER: 53DfF883gyixYNXnM7s5xhdeyV8mVk9T4i2hGV9vG9io - NEON_TOKEN_MINT: HPsV9Deocecw3GeZv1FkAPNCBRfuVyfw9MMwjwRe1xaU - NEON_CHAIN_ID: 111 + # operator-keypairs/id.json + SOLANA_KEY_FOR_CONFIG: BMp6gEnveANdvSvspESJUrNczuHz1GF5UQKjVLCkAZih COMMITMENT: confirmed NEON_DB_CLICKHOUSE_URLS: "http://45.250.253.36:8123;http://45.250.253.38:8123" - KEYPAIR: /opt/operator-keypairs/id.json - FEEPAIR: /opt/operator-keypairs/id.json image: ${EVM_LOADER_IMAGE} ports: - "8085" diff --git a/ci/docker-compose-test.yml b/ci/docker-compose-test.yml index 405eea9d1..3577e8fc5 100644 --- a/ci/docker-compose-test.yml +++ b/ci/docker-compose-test.yml @@ -34,12 +34,10 @@ services: NEON_API_LISTENER_ADDR: 0.0.0.0:8085 SOLANA_URL: http://solana:8899 EVM_LOADER: 53DfF883gyixYNXnM7s5xhdeyV8mVk9T4i2hGV9vG9io - NEON_TOKEN_MINT: HPsV9Deocecw3GeZv1FkAPNCBRfuVyfw9MMwjwRe1xaU - NEON_CHAIN_ID: 111 + # operator-keypairs/id.json + SOLANA_KEY_FOR_CONFIG: BMp6gEnveANdvSvspESJUrNczuHz1GF5UQKjVLCkAZih COMMITMENT: confirmed NEON_DB_CLICKHOUSE_URLS: "http://45.250.253.36:8123;http://45.250.253.38:8123" - KEYPAIR: /opt/operator-keypairs/id.json - FEEPAIR: /opt/operator-keypairs/id.json image: ${EVM_LOADER_IMAGE} ports: - "8085:8085" diff --git a/ci/solana-run-neon.sh b/ci/solana-run-neon.sh index 0deda3f77..496970eba 100755 --- a/ci/solana-run-neon.sh +++ b/ci/solana-run-neon.sh @@ -42,6 +42,7 @@ solana-test-validator "${VALIDATOR_ARGS[@]}" > /dev/null & neon-cli --url http://localhost:8899 --evm_loader $EVM_LOADER \ --commitment confirmed \ --keypair ${EVM_LOADER_AUTHORITY_KEYPAIR} \ + --solana_key_for_config BMp6gEnveANdvSvspESJUrNczuHz1GF5UQKjVLCkAZih \ --loglevel trace init-environment --send-trx --keys-dir /opt/keys tail +1f test-ledger/validator.log diff --git a/evm_loader/api/src/api_server/state.rs b/evm_loader/api/src/api_server/state.rs index efd5ab362..3a9ae8523 100644 --- a/evm_loader/api/src/api_server/state.rs +++ b/evm_loader/api/src/api_server/state.rs @@ -1,4 +1,4 @@ -use crate::Config; +use neon_lib::config::APIOptions; use neon_lib::rpc::{CallDbClient, CloneRpcClient, RpcEnum}; use neon_lib::types::TracerDb; use neon_lib::NeonError; @@ -6,14 +6,14 @@ use neon_lib::NeonError; pub struct State { pub tracer_db: TracerDb, pub rpc_client: CloneRpcClient, - pub config: Config, + pub config: APIOptions, } impl State { - pub fn new(config: Config) -> Self { + pub fn new(config: APIOptions) -> Self { Self { - tracer_db: TracerDb::new(config.db_config.as_ref().expect("db-config not found")), - rpc_client: config.build_clone_solana_rpc_client(), + tracer_db: TracerDb::new(&config.db_config), + rpc_client: CloneRpcClient::new_from_api_config(&config), config, } } diff --git a/evm_loader/api/src/main.rs b/evm_loader/api/src/main.rs index 682058be9..e52524e72 100644 --- a/evm_loader/api/src/main.rs +++ b/evm_loader/api/src/main.rs @@ -52,10 +52,7 @@ async fn main() -> NeonApiResult<()> { info!("{}", get_build_info()); let api_config = config::load_api_config_from_enviroment(); - - let config = config::create_from_api_config(&api_config)?; - - let state: NeonApiState = Data::new(api_server::state::State::new(config)); + let state: NeonApiState = Data::new(api_server::state::State::new(api_config)); let listener_addr = options .value_of("host") diff --git a/evm_loader/cli/src/config.rs b/evm_loader/cli/src/config.rs index 5ed698eb0..2db2704a7 100644 --- a/evm_loader/cli/src/config.rs +++ b/evm_loader/cli/src/config.rs @@ -5,7 +5,7 @@ use solana_clap_utils::{ input_parsers::pubkey_of, input_validators::normalize_to_url_if_moniker, keypair::keypair_from_path, }; -use solana_sdk::commitment_config::CommitmentConfig; +use solana_sdk::{commitment_config::CommitmentConfig, signature::Keypair, signer::Signer}; use std::str::FromStr; /// # Panics @@ -45,12 +45,22 @@ pub fn create(options: &ArgMatches) -> Result { ) .ok(); + let key_for_config = if let Some(key_for_config) = pubkey_of(options, "solana_key_for_config") { + key_for_config + } else { + fee_payer + .as_ref() + .map(Keypair::pubkey) + .ok_or(NeonError::SolanaKeyForConfigNotSpecified)? + }; + let db_config = options .value_of("db_config") .map(|path| solana_cli_config::load_config_file(path).expect("load db-config error")); Ok(Config { evm_loader, + key_for_config, fee_payer, commitment, solana_cli_config, diff --git a/evm_loader/cli/src/main.rs b/evm_loader/cli/src/main.rs index 3f3210849..c134bfd53 100644 --- a/evm_loader/cli/src/main.rs +++ b/evm_loader/cli/src/main.rs @@ -12,6 +12,7 @@ use neon_lib::{ cancel_trx, collect_treasury, emulate, get_balance, get_config, get_contract, get_holder, get_neon_elf, get_storage_at, init_environment, trace, }, + rpc::CloneRpcClient, types::{BalanceAddress, EmulateRequest}, Config, }; @@ -90,7 +91,7 @@ async fn run(options: &ArgMatches<'_>) -> NeonCliResult { .map(|result| json!(result)) } ("cancel-trx", Some(params)) => { - let rpc_client = config.build_clone_solana_rpc_client(); + let rpc_client = CloneRpcClient::new_from_config(config); let signer = build_signer(config)?; let storage_account = @@ -108,7 +109,7 @@ async fn run(options: &ArgMatches<'_>) -> NeonCliResult { .map(|result| json!(result)) } ("collect-treasury", Some(_)) => { - let rpc_client = config.build_clone_solana_rpc_client(); + let rpc_client = CloneRpcClient::new_from_config(config); let signer = build_signer(config)?; collect_treasury::execute(config, &rpc_client, &*signer) @@ -116,7 +117,7 @@ async fn run(options: &ArgMatches<'_>) -> NeonCliResult { .map(|result| json!(result)) } ("init-environment", Some(params)) => { - let rpc_client = config.build_clone_solana_rpc_client(); + let rpc_client = CloneRpcClient::new_from_config(config); let signer = build_signer(config)?; let file = params.value_of("file"); @@ -172,7 +173,7 @@ async fn build_rpc(options: &ArgMatches<'_>, config: &Config) -> Result() -> ArgMatches<'a> { .validator(is_valid_pubkey) .help("Pubkey for evm_loader contract") ) + .arg( + Arg::with_name("solana_key_for_config") + .long("solana_key_for_config") + .value_name("SOLANA_KEY_FOR_CONFIG") + .takes_value(true) + .global(true) + .required(false) + .validator(is_valid_pubkey) + .help("Operator pubkey, used for config simulation") + ) .arg( Arg::with_name("commitment") .long("commitment") diff --git a/evm_loader/lib/src/commands/get_config.rs b/evm_loader/lib/src/commands/get_config.rs index f8e404823..a2e87ee6d 100644 --- a/evm_loader/lib/src/commands/get_config.rs +++ b/evm_loader/lib/src/commands/get_config.rs @@ -2,7 +2,6 @@ use async_trait::async_trait; use base64::Engine; use enum_dispatch::enum_dispatch; use std::collections::BTreeMap; -use std::str::FromStr; use serde::{Deserialize, Serialize}; use solana_program_test::{ProgramTest, ProgramTestContext}; @@ -22,8 +21,7 @@ use crate::{rpc::Rpc, NeonError, NeonResult}; use crate::rpc::{CallDbClient, CloneRpcClient}; use serde_with::{serde_as, DisplayFromStr}; -use solana_client::client_error::Result as ClientResult; -use solana_client::rpc_config::{RpcLargestAccountsConfig, RpcSimulateTransactionConfig}; +use solana_client::rpc_config::RpcSimulateTransactionConfig; use tokio::sync::{Mutex, MutexGuard, OnceCell}; #[derive(Debug, Serialize)] @@ -117,8 +115,14 @@ fn set_program_account( } pub enum ConfigSimulator<'r> { - CloneRpcClient(Pubkey, &'r CloneRpcClient), - ProgramTestContext(Pubkey, MutexGuard<'static, ProgramTestContext>), + CloneRpcClient { + program_id: Pubkey, + rpc: &'r CloneRpcClient, + }, + ProgramTestContext { + program_id: Pubkey, + program_test: MutexGuard<'static, ProgramTestContext>, + }, } #[async_trait(?Send)] @@ -130,7 +134,10 @@ pub trait BuildConfigSimulator { #[async_trait(?Send)] impl BuildConfigSimulator for CloneRpcClient { async fn build_config_simulator(&self, program_id: Pubkey) -> NeonResult { - Ok(ConfigSimulator::CloneRpcClient(program_id, self)) + Ok(ConfigSimulator::CloneRpcClient { + program_id, + rpc: self, + }) } } @@ -139,15 +146,15 @@ impl BuildConfigSimulator for CallDbClient { async fn build_config_simulator(&self, program_id: Pubkey) -> NeonResult { let program_data = self.read_program_data_from_account(program_id).await?; - let mut program_test_context = program_test_context().await; + let mut program_test = program_test_context().await; - set_program_account(&mut program_test_context, program_id, program_data); - program_test_context.get_new_latest_blockhash().await?; + set_program_account(&mut program_test, program_id, program_data); + program_test.get_new_latest_blockhash().await?; - Ok(ConfigSimulator::ProgramTestContext( + Ok(ConfigSimulator::ProgramTestContext { program_id, - program_test_context, - )) + program_test, + }) } } @@ -156,8 +163,7 @@ impl CloneRpcClient { &self, instruction: Instruction, ) -> NeonResult> { - let tx = - Transaction::new_with_payer(&[instruction], Some(&self.get_account_with_sol().await?)); + let tx = Transaction::new_with_payer(&[instruction], Some(&self.key_for_config)); let result = self .simulate_transaction_with_config( @@ -216,8 +222,8 @@ impl SolanaInstructionSimulator for ProgramTestContext { impl ConfigSimulator<'_> { fn program_id(&self) -> Pubkey { match self { - ConfigSimulator::CloneRpcClient(program_id, _) => *program_id, - ConfigSimulator::ProgramTestContext(program_id, _) => *program_id, + ConfigSimulator::CloneRpcClient { program_id, .. } => *program_id, + ConfigSimulator::ProgramTestContext { program_id, .. } => *program_id, } } @@ -257,15 +263,11 @@ impl ConfigSimulator<'_> { instruction: Instruction, ) -> NeonResult> { match self { - ConfigSimulator::CloneRpcClient(_, clone_rpc_client) => { - clone_rpc_client - .simulate_solana_instruction(instruction) - .await + ConfigSimulator::CloneRpcClient { rpc, .. } => { + rpc.simulate_solana_instruction(instruction).await } - ConfigSimulator::ProgramTestContext(_, program_test_context) => { - program_test_context - .simulate_solana_instruction(instruction) - .await + ConfigSimulator::ProgramTestContext { program_test, .. } => { + program_test.simulate_solana_instruction(instruction).await } } } @@ -369,19 +371,6 @@ pub async fn read_default_chain_id( Ok(default_chain.id) } -impl CloneRpcClient { - async fn get_account_with_sol(&self) -> ClientResult { - let r = self - .get_largest_accounts_with_config(RpcLargestAccountsConfig { - commitment: Some(self.commitment()), - filter: None, - }) - .await?; // TODO https://neonlabs.atlassian.net/browse/NDEV-2462 replace with more efficient RPC call - - Ok(Pubkey::from_str(&r.value[0].address).unwrap()) - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/evm_loader/lib/src/config.rs b/evm_loader/lib/src/config.rs index ae1c5fa72..499262899 100644 --- a/evm_loader/lib/src/config.rs +++ b/evm_loader/lib/src/config.rs @@ -1,18 +1,13 @@ use std::{env, str::FromStr}; -use crate::rpc::CloneRpcClient; -use crate::{types::ChDbConfig, NeonError}; +use crate::types::ChDbConfig; use serde::{Deserialize, Serialize}; -use solana_clap_utils::{ - input_validators::normalize_to_url_if_moniker, keypair::keypair_from_path, -}; -use solana_cli_config::Config as SolanaConfig; -use solana_client::nonblocking::rpc_client::RpcClient; use solana_sdk::{commitment_config::CommitmentConfig, pubkey::Pubkey, signature::Keypair}; #[derive(Debug)] pub struct Config { pub evm_loader: Pubkey, + pub key_for_config: Pubkey, pub fee_payer: Option, pub commitment: CommitmentConfig, pub solana_cli_config: solana_cli_config::Config, @@ -21,67 +16,13 @@ pub struct Config { pub keypair_path: String, } -impl Config { - pub fn build_solana_rpc_client(&self) -> RpcClient { - RpcClient::new_with_commitment(self.json_rpc_url.clone(), self.commitment) - } - - pub fn build_clone_solana_rpc_client(&self) -> CloneRpcClient { - CloneRpcClient::new(self.build_solana_rpc_client()) - } -} - -/// # Errors -pub fn create_from_api_config(api_config: &APIOptions) -> Result { - let solana_cli_config: SolanaConfig = - if let Some(path) = api_config.solana_cli_config_path.clone() { - solana_cli_config::Config::load(path.as_str()).unwrap_or_default() - } else { - solana_cli_config::Config::default() - }; - - let commitment = CommitmentConfig::from_str(&api_config.commitment) - .unwrap_or_else(|_| CommitmentConfig::confirmed()); - - let json_rpc_url = normalize_to_url_if_moniker(api_config.json_rpc_url.clone()); - - let evm_loader: Pubkey = if let Ok(val) = Pubkey::from_str(&api_config.evm_loader) { - val - } else { - return Err(NeonError::EvmLoaderNotSpecified); - }; - - let keypair_path: String = api_config.keypair.clone(); - - let fee_payer = keypair_from_path( - &Default::default(), - &api_config.fee_payer, - "fee_payer", - true, - ) - .ok(); - - let db_config: Option = Option::from(api_config.db_config.clone()); - - Ok(Config { - evm_loader, - fee_payer, - commitment, - solana_cli_config, - db_config, - json_rpc_url, - keypair_path, - }) -} - #[derive(Debug, Deserialize, Serialize)] pub struct APIOptions { pub solana_cli_config_path: Option, - pub commitment: String, + pub commitment: CommitmentConfig, pub json_rpc_url: String, - pub evm_loader: String, - pub keypair: String, - pub fee_payer: String, + pub evm_loader: Pubkey, + pub key_for_config: Pubkey, pub db_config: ChDbConfig, } @@ -93,15 +34,21 @@ pub fn load_api_config_from_enviroment() -> APIOptions { let commitment = env::var("COMMITMENT") .map(|v| v.to_lowercase()) - .expect("commitment variable must be set"); + .ok() + .and_then(|s| CommitmentConfig::from_str(&s).ok()) + .unwrap_or(CommitmentConfig::confirmed()); let json_rpc_url = env::var("SOLANA_URL").expect("solana url variable must be set"); - let evm_loader = env::var("EVM_LOADER").expect("evm loader variable must be set"); - - let keypair = env::var("KEYPAIR").expect("keypair must variable be set"); + let evm_loader = env::var("EVM_LOADER") + .ok() + .and_then(|v| Pubkey::from_str(&v).ok()) + .expect("EVM_LOADER variable must be a valid pubkey"); - let fee_payer = env::var("FEEPAIR").expect("fee pair variable must be set"); + let key_for_config = env::var("SOLANA_KEY_FOR_CONFIG") + .ok() + .and_then(|v| Pubkey::from_str(&v).ok()) + .expect("SOLANA_KEY_FOR_CONFIG variable must be a valid pubkey"); let db_config = load_db_config_from_enviroment(); @@ -110,8 +57,7 @@ pub fn load_api_config_from_enviroment() -> APIOptions { commitment, json_rpc_url, evm_loader, - keypair, - fee_payer, + key_for_config, db_config, } } diff --git a/evm_loader/lib/src/errors.rs b/evm_loader/lib/src/errors.rs index 3d21114c1..a7cf3e0be 100644 --- a/evm_loader/lib/src/errors.rs +++ b/evm_loader/lib/src/errors.rs @@ -112,6 +112,8 @@ pub enum NeonError { FromUtf8Error(#[from] FromUtf8Error), #[error("TryFromSlice Error. {0}")] TryFromSliceError(#[from] TryFromSliceError), + #[error("Solana pubkey for config must be specified.")] + SolanaKeyForConfigNotSpecified, } impl NeonError { @@ -153,6 +155,7 @@ impl NeonError { NeonError::BincodeError(_) => 257, NeonError::FromUtf8Error(_) => 258, NeonError::TryFromSliceError(_) => 259, + NeonError::SolanaKeyForConfigNotSpecified => 260, } } } diff --git a/evm_loader/lib/src/rpc/validator_client.rs b/evm_loader/lib/src/rpc/validator_client.rs index a940230ed..0c84e743a 100644 --- a/evm_loader/lib/src/rpc/validator_client.rs +++ b/evm_loader/lib/src/rpc/validator_client.rs @@ -1,3 +1,5 @@ +use crate::{config::APIOptions, Config}; + use super::Rpc; use async_trait::async_trait; use solana_client::{ @@ -14,11 +16,32 @@ use std::ops::Deref; use std::sync::Arc; #[derive(Clone)] -pub struct CloneRpcClient(Arc); +pub struct CloneRpcClient { + pub rpc: Arc, + pub key_for_config: Pubkey, +} impl CloneRpcClient { - pub fn new(rpc_client: RpcClient) -> Self { - Self(Arc::new(rpc_client)) + pub fn new_from_config(config: &Config) -> Self { + let url = config.json_rpc_url.clone(); + let commitment = config.commitment; + + let rpc_client = RpcClient::new_with_commitment(url, commitment); + Self { + rpc: Arc::new(rpc_client), + key_for_config: config.key_for_config, + } + } + + pub fn new_from_api_config(config: &APIOptions) -> Self { + let url = config.json_rpc_url.clone(); + let commitment = config.commitment; + + let rpc_client = RpcClient::new_with_commitment(url, commitment); + Self { + rpc: Arc::new(rpc_client), + key_for_config: config.key_for_config, + } } } @@ -26,14 +49,14 @@ impl Deref for CloneRpcClient { type Target = RpcClient; fn deref(&self) -> &Self::Target { - &self.0 + &self.rpc } } #[async_trait(?Send)] impl Rpc for CloneRpcClient { async fn get_account(&self, key: &Pubkey) -> RpcResult> { - self.0 + self.rpc .get_account_with_commitment(key, self.commitment()) .await } @@ -43,7 +66,7 @@ impl Rpc for CloneRpcClient { key: &Pubkey, commitment: CommitmentConfig, ) -> RpcResult> { - self.0.get_account_with_commitment(key, commitment).await + self.rpc.get_account_with_commitment(key, commitment).await } async fn get_multiple_accounts( @@ -52,7 +75,7 @@ impl Rpc for CloneRpcClient { ) -> ClientResult>> { let mut result: Vec> = Vec::new(); for chunk in pubkeys.chunks(100) { - let mut accounts = self.0.get_multiple_accounts(chunk).await?; + let mut accounts = self.rpc.get_multiple_accounts(chunk).await?; result.append(&mut accounts); } @@ -60,10 +83,10 @@ impl Rpc for CloneRpcClient { } async fn get_block_time(&self, slot: Slot) -> ClientResult { - self.0.get_block_time(slot).await + self.rpc.get_block_time(slot).await } async fn get_slot(&self) -> ClientResult { - self.0.get_slot().await + self.rpc.get_slot().await } } From af703de76b9f8e22bc55e06e6fc40a97964556fa Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 1 Mar 2024 12:14:05 +0200 Subject: [PATCH 096/318] Add additional check for data out of bounds in get_elf_parameter (#289) --- evm_loader/lib/src/commands/get_neon_elf.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/evm_loader/lib/src/commands/get_neon_elf.rs b/evm_loader/lib/src/commands/get_neon_elf.rs index 5e88bcaaa..4f81c634d 100644 --- a/evm_loader/lib/src/commands/get_neon_elf.rs +++ b/evm_loader/lib/src/commands/get_neon_elf.rs @@ -85,6 +85,16 @@ pub fn read_elf_parameters(_config: &Config, program_data: &[u8]) -> GetNeonElfR pub fn get_elf_parameter(data: &[u8], elf_parameter: &str) -> Result { let offset = UpgradeableLoaderState::size_of_programdata_metadata(); + + // Check if the offset is within the bounds of `data` + if data.len() <= offset { + let error_msg = format!( + "Offset beyond data bounds. Data len: {}, offset: {offset}, data bytes: {data:?}", + data.len(), + ); + return Err(anyhow::anyhow!(error_msg)); + } + let program_data = &data[offset..]; let elf = goblin::elf::Elf::parse(program_data).context("Unable to parse ELF file")?; From 7e2976c6e33a10b13a43a601cef36e3c123b736a Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Thu, 29 Feb 2024 17:06:41 +0300 Subject: [PATCH 097/318] Do not increment the revision on native balance change --- .../program/src/account_storage/apply.rs | 5 ---- evm_loader/program/src/executor/cache.rs | 23 ++++++++++++++++++- evm_loader/program/src/executor/state.rs | 6 +++-- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/evm_loader/program/src/account_storage/apply.rs b/evm_loader/program/src/account_storage/apply.rs index ea7e50cd6..d42f71d23 100644 --- a/evm_loader/program/src/account_storage/apply.rs +++ b/evm_loader/program/src/account_storage/apply.rs @@ -83,9 +83,6 @@ impl<'a> ProgramAccountStorage<'a> { let mut source = self.balance_account(source, chain_id)?; let mut target = self.create_balance_account(target, chain_id)?; source.transfer(&mut target, value)?; - - modified_accounts.insert(*source.pubkey()); - modified_accounts.insert(*target.pubkey()); } Action::Burn { source, @@ -94,8 +91,6 @@ impl<'a> ProgramAccountStorage<'a> { } => { let mut account = self.create_balance_account(source, chain_id)?; account.burn(value)?; - - modified_accounts.insert(*account.pubkey()); } Action::EvmSetStorage { address, diff --git a/evm_loader/program/src/executor/cache.rs b/evm_loader/program/src/executor/cache.rs index 0c3c51b6e..ecf338c44 100644 --- a/evm_loader/program/src/executor/cache.rs +++ b/evm_loader/program/src/executor/cache.rs @@ -5,7 +5,7 @@ use maybe_async::maybe_async; use serde::{Deserialize, Serialize}; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; -use crate::account_storage::AccountStorage; +use crate::{account_storage::AccountStorage, types::Address}; #[derive(Clone, Serialize, Deserialize)] pub struct OwnedAccountInfo { @@ -60,6 +60,7 @@ impl<'a> solana_program::account_info::IntoAccountInfo<'a> for &'a mut OwnedAcco #[derive(Serialize, Deserialize)] pub struct Cache { pub solana_accounts: BTreeMap, + pub native_balances: BTreeMap<(Address, u64), U256>, #[serde(with = "ethnum::serde::bytes::le")] pub block_number: U256, #[serde(with = "ethnum::serde::bytes::le")] @@ -84,3 +85,23 @@ pub async fn cache_get_or_insert_account( Entry::Occupied(entry) => entry.get().clone(), } } + +#[maybe_async] +#[allow(clippy::await_holding_refcell_ref)] // We don't use this RefCell in other execution context +pub async fn cache_get_or_insert_balance( + cache: &RefCell, + key: (Address, u64), + backend: &B, +) -> U256 { + use std::collections::btree_map::Entry; + + let mut cache = cache.borrow_mut(); + + match cache.native_balances.entry(key) { + Entry::Vacant(entry) => { + let balance = backend.balance(key.0, key.1).await; + *entry.insert(balance) + } + Entry::Occupied(entry) => *entry.get(), + } +} diff --git a/evm_loader/program/src/executor/state.rs b/evm_loader/program/src/executor/state.rs index c9e09ebbd..2f0601445 100644 --- a/evm_loader/program/src/executor/state.rs +++ b/evm_loader/program/src/executor/state.rs @@ -15,7 +15,7 @@ use crate::evm::{Context, ExitStatus}; use crate::types::Address; use super::action::Action; -use super::cache::{cache_get_or_insert_account, Cache}; +use super::cache::{cache_get_or_insert_account, cache_get_or_insert_balance, Cache}; use super::OwnedAccountInfo; /// Represents the state of executor abstracted away from a self.backend. @@ -53,6 +53,7 @@ impl<'a, B: AccountStorage> ExecutorState<'a, B> { pub fn new(backend: &'a B) -> Self { let cache = Cache { solana_accounts: BTreeMap::new(), + native_balances: BTreeMap::new(), block_number: backend.block_number(), block_timestamp: backend.block_timestamp(), }; @@ -208,7 +209,8 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { } async fn balance(&self, from_address: Address, from_chain_id: u64) -> Result { - let mut balance = self.backend.balance(from_address, from_chain_id).await; + let cache_key = (from_address, from_chain_id); + let mut balance = cache_get_or_insert_balance(&self.cache, cache_key, self.backend).await; for action in &self.actions { match action { From f312c941dcf7a44a71d224c3ef97d6006a067d04 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Thu, 29 Feb 2024 17:16:47 +0300 Subject: [PATCH 098/318] New accounts migration system --- evm_loader/lib/src/account_storage.rs | 62 ++++---- evm_loader/lib/src/account_update.rs | 48 ------- evm_loader/lib/src/commands/get_balance.rs | 7 +- evm_loader/lib/src/commands/get_contract.rs | 4 +- evm_loader/lib/src/lib.rs | 1 - .../program/src/account/ether_balance.rs | 51 +++---- .../program/src/account/ether_contract.rs | 133 ++++++++++++++---- .../program/src/account/ether_storage.rs | 88 ++++++++++-- evm_loader/program/src/account/holder.rs | 12 +- evm_loader/program/src/account/legacy/mod.rs | 43 +++--- .../program/src/account/legacy/update.rs | 37 ----- evm_loader/program/src/account/mod.rs | 126 ++++++++++++----- evm_loader/program/src/account/state.rs | 38 +++-- .../program/src/account/state_finalized.rs | 31 +++- .../program/src/account_storage/apply.rs | 34 ++--- 15 files changed, 400 insertions(+), 315 deletions(-) delete mode 100644 evm_loader/lib/src/account_update.rs delete mode 100644 evm_loader/program/src/account/legacy/update.rs diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index 9720c6bb1..432361b38 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -1,10 +1,9 @@ use async_trait::async_trait; use evm_loader::account::legacy::{ - LegacyEtherData, LegacyStorageData, ACCOUNT_PREFIX_LEN_BEFORE_REVISION, - TAG_ACCOUNT_BALANCE_BEFORE_REVISION, TAG_ACCOUNT_CONTRACT_BEFORE_REVISION, - TAG_ACCOUNT_CONTRACT_DEPRECATED, TAG_STORAGE_CELL_BEFORE_REVISION, TAG_STORAGE_CELL_DEPRECATED, + LegacyEtherData, LegacyStorageData, TAG_ACCOUNT_CONTRACT_DEPRECATED, + TAG_STORAGE_CELL_DEPRECATED, }; -use evm_loader::account::{ACCOUNT_PREFIX_LEN, TAG_ACCOUNT_CONTRACT, TAG_STORAGE_CELL}; +use evm_loader::account::{TAG_ACCOUNT_CONTRACT, TAG_STORAGE_CELL}; use evm_loader::account_storage::find_slot_hash; use evm_loader::types::Address; use solana_sdk::rent::Rent; @@ -13,7 +12,6 @@ use solana_sdk::sysvar::slot_hashes; use std::collections::HashSet; use std::{cell::RefCell, collections::HashMap, convert::TryInto, rc::Rc}; -use crate::account_update::update_account; use crate::NeonResult; use crate::{rpc::Rpc, NeonError}; use ethnum::U256; @@ -177,11 +175,7 @@ impl EmulatorAccountStorage<'_, T> { is_writable: bool, ) -> NeonResult<(Pubkey, Option, Option)> { let (pubkey, _) = address.find_balance_address(self.program_id(), chain_id); - let mut account = self.use_account(pubkey, is_writable).await?; - - if let Some(account) = &mut account { - update_account(&self.program_id, &pubkey, account)?; - } + let account = self.use_account(pubkey, is_writable).await?; let legacy_account = if account.is_none() && (chain_id == self.default_chain_id()) { let (legacy_pubkey, _) = address.find_solana_address(self.program_id()); @@ -199,11 +193,7 @@ impl EmulatorAccountStorage<'_, T> { is_writable: bool, ) -> NeonResult<(Pubkey, Option)> { let (pubkey, _) = address.find_solana_address(self.program_id()); - let mut account = self.use_account(pubkey, is_writable).await?; - - if let Some(account) = &mut account { - update_account(&self.program_id, &pubkey, account)?; - } + let account = self.use_account(pubkey, is_writable).await?; Ok((pubkey, account)) } @@ -217,14 +207,10 @@ impl EmulatorAccountStorage<'_, T> { let (base, _) = address.find_solana_address(self.program_id()); let cell_address = StorageCellAddress::new(self.program_id(), &base, &index); - let mut account = self + let account = self .use_account(*cell_address.pubkey(), is_writable) .await?; - if let Some(account) = &mut account { - update_account(&self.program_id, cell_address.pubkey(), account)?; - } - Ok((*cell_address.pubkey(), account)) } @@ -384,26 +370,28 @@ impl EmulatorAccountStorage<'_, T> { } } - if matches!( - tag, - TAG_ACCOUNT_BALANCE_BEFORE_REVISION - | TAG_ACCOUNT_CONTRACT_BEFORE_REVISION - | TAG_STORAGE_CELL_BEFORE_REVISION - ) { - const PREFIX_BEFORE: usize = ACCOUNT_PREFIX_LEN_BEFORE_REVISION; - const PREFIX_AFTER: usize = ACCOUNT_PREFIX_LEN; - const EXPANSION_LEN: usize = PREFIX_AFTER - PREFIX_BEFORE; + if !account.is_writable { + continue; + } - account.is_writable = true; - account.is_legacy = true; + let required_header_realloc = match tag { + TAG_ACCOUNT_CONTRACT => { + let contract = ContractAccount::from_account(self.program_id(), info)?; + contract.required_header_realloc() + } + TAG_STORAGE_CELL => { + let cell = StorageCell::from_account(self.program_id(), info)?; + cell.required_header_realloc() + } + _ => 0, + }; - let lamports = self - .rent - .minimum_balance(EXPANSION_LEN) - .saturating_sub(self.rent.minimum_balance(0)); + let header_realloc_lamports = self + .rent + .minimum_balance(required_header_realloc) + .saturating_sub(self.rent.minimum_balance(0)); - self.gas = self.gas.saturating_add(lamports); - } + self.gas = self.gas.saturating_add(header_realloc_lamports); } for a in additional_balances { diff --git a/evm_loader/lib/src/account_update.rs b/evm_loader/lib/src/account_update.rs deleted file mode 100644 index a51dda7b2..000000000 --- a/evm_loader/lib/src/account_update.rs +++ /dev/null @@ -1,48 +0,0 @@ -use evm_loader::account::{ - legacy::{ - ACCOUNT_PREFIX_LEN_BEFORE_REVISION, TAG_ACCOUNT_BALANCE_BEFORE_REVISION, - TAG_ACCOUNT_CONTRACT_BEFORE_REVISION, TAG_STORAGE_CELL_BEFORE_REVISION, - }, - ACCOUNT_PREFIX_LEN, TAG_ACCOUNT_BALANCE, TAG_ACCOUNT_CONTRACT, TAG_STORAGE_CELL, -}; -use solana_sdk::{account::Account, pubkey::Pubkey}; - -use crate::{account_storage::account_info, NeonResult}; - -fn from_before_revision(account: &mut Account, new_tag: u8) { - const PREFIX_BEFORE: usize = ACCOUNT_PREFIX_LEN_BEFORE_REVISION; - const PREFIX_AFTER: usize = ACCOUNT_PREFIX_LEN; - - let data: &mut Vec = &mut account.data; - - assert!(data.len() > PREFIX_BEFORE); - let data_len = data.len() - PREFIX_BEFORE; - - let required_len = data.len() + PREFIX_AFTER - PREFIX_BEFORE; - data.resize(required_len, 0); - - data.copy_within(PREFIX_BEFORE..(PREFIX_BEFORE + data_len), PREFIX_AFTER); - data[0] = new_tag; -} - -pub fn update_account(program_id: &Pubkey, key: &Pubkey, account: &mut Account) -> NeonResult<()> { - let tag = { - let info = account_info(key, account); - evm_loader::account::tag(program_id, &info)? - }; - - match tag { - TAG_ACCOUNT_BALANCE_BEFORE_REVISION => { - from_before_revision(account, TAG_ACCOUNT_BALANCE); - } - TAG_ACCOUNT_CONTRACT_BEFORE_REVISION => { - from_before_revision(account, TAG_ACCOUNT_CONTRACT); - } - TAG_STORAGE_CELL_BEFORE_REVISION => { - from_before_revision(account, TAG_STORAGE_CELL); - } - _ => {} - } - - Ok(()) -} diff --git a/evm_loader/lib/src/commands/get_balance.rs b/evm_loader/lib/src/commands/get_balance.rs index 4879dd1c9..e9d6561a9 100644 --- a/evm_loader/lib/src/commands/get_balance.rs +++ b/evm_loader/lib/src/commands/get_balance.rs @@ -4,10 +4,7 @@ use evm_loader::account::BalanceAccount; use serde::{Deserialize, Serialize}; use solana_sdk::{account::Account, pubkey::Pubkey}; -use crate::{ - account_storage::account_info, account_update::update_account, rpc::Rpc, types::BalanceAddress, - NeonResult, -}; +use crate::{account_storage::account_info, rpc::Rpc, types::BalanceAddress, NeonResult}; use serde_with::{serde_as, DisplayFromStr}; @@ -51,8 +48,6 @@ fn read_account( ) -> NeonResult { let solana_address = address.find_pubkey(program_id); - update_account(program_id, &solana_address, &mut account)?; - let account_info = account_info(&solana_address, &mut account); let balance_account = BalanceAccount::from_account(program_id, account_info)?; diff --git a/evm_loader/lib/src/commands/get_contract.rs b/evm_loader/lib/src/commands/get_contract.rs index 938a1a4c6..6f1a3d324 100644 --- a/evm_loader/lib/src/commands/get_contract.rs +++ b/evm_loader/lib/src/commands/get_contract.rs @@ -5,7 +5,7 @@ use evm_loader::{ use serde::{Deserialize, Serialize}; use solana_sdk::{account::Account, pubkey::Pubkey}; -use crate::{account_storage::account_info, account_update::update_account, rpc::Rpc, NeonResult}; +use crate::{account_storage::account_info, rpc::Rpc, NeonResult}; use serde_with::{hex::Hex, serde_as, DisplayFromStr}; @@ -51,8 +51,6 @@ fn read_account( return Ok(GetContractResponse::empty(solana_address)); }; - update_account(program_id, &solana_address, &mut account)?; - let account_info = account_info(&solana_address, &mut account); let (chain_id, code) = if let Ok(contract) = ContractAccount::from_account(program_id, account_info.clone()) { diff --git a/evm_loader/lib/src/lib.rs b/evm_loader/lib/src/lib.rs index 512257992..d50c2f17b 100644 --- a/evm_loader/lib/src/lib.rs +++ b/evm_loader/lib/src/lib.rs @@ -1,5 +1,4 @@ pub mod account_storage; -pub mod account_update; pub mod build_info; pub mod build_info_common; pub mod commands; diff --git a/evm_loader/program/src/account/ether_balance.rs b/evm_loader/program/src/account/ether_balance.rs index dd316d95e..b2959bef4 100644 --- a/evm_loader/program/src/account/ether_balance.rs +++ b/evm_loader/program/src/account/ether_balance.rs @@ -1,7 +1,4 @@ -use std::{ - cell::{Ref, RefMut}, - mem::size_of, -}; +use std::mem::size_of; use crate::{ account::{TAG_ACCOUNT_CONTRACT, TAG_EMPTY}, @@ -13,7 +10,9 @@ use crate::{ use ethnum::U256; use solana_program::{account_info::AccountInfo, pubkey::Pubkey, rent::Rent, system_program}; -use super::{AccountsDB, ACCOUNT_PREFIX_LEN, ACCOUNT_SEED_VERSION, TAG_ACCOUNT_BALANCE}; +use super::{ + AccountHeader, AccountsDB, ACCOUNT_PREFIX_LEN, ACCOUNT_SEED_VERSION, TAG_ACCOUNT_BALANCE, +}; #[repr(C, packed)] pub struct Header { @@ -22,13 +21,14 @@ pub struct Header { pub trx_count: u64, pub balance: U256, } +impl AccountHeader for Header { + const VERSION: u8 = 0; +} pub struct BalanceAccount<'a> { account: AccountInfo<'a>, } -const HEADER_OFFSET: usize = ACCOUNT_PREFIX_LEN; - impl<'a> BalanceAccount<'a> { #[must_use] pub fn required_account_size() -> usize { @@ -97,17 +97,16 @@ impl<'a> BalanceAccount<'a> { rent, )?; - super::set_tag(&crate::ID, &account, TAG_ACCOUNT_BALANCE)?; - let mut balance_account = Self { account }; + super::set_tag(&crate::ID, &account, TAG_ACCOUNT_BALANCE, Header::VERSION)?; { - let mut header = balance_account.header_mut(); + let mut header = super::header_mut::
(&account); header.address = address; header.chain_id = chain_id; header.trx_count = 0; header.balance = U256::ZERO; } - Ok(balance_account) + Ok(Self { account }) } #[must_use] @@ -115,34 +114,27 @@ impl<'a> BalanceAccount<'a> { self.account.key } - #[inline] - fn header(&self) -> Ref
{ - super::section(&self.account, HEADER_OFFSET) - } - - #[inline] - fn header_mut(&mut self) -> RefMut
{ - super::section_mut(&self.account, HEADER_OFFSET) - } - #[must_use] pub fn address(&self) -> Address { - self.header().address + let header = super::header::
(&self.account); + header.address } #[must_use] pub fn chain_id(&self) -> u64 { - self.header().chain_id + let header = super::header::
(&self.account); + header.chain_id } #[must_use] pub fn nonce(&self) -> u64 { - self.header().trx_count + let header = super::header::
(&self.account); + header.trx_count } #[must_use] pub fn exists(&self) -> bool { - let header = self.header(); + let header = super::header::
(&self.account); ({ header.trx_count } > 0) || ({ header.balance } > 0) } @@ -152,7 +144,7 @@ impl<'a> BalanceAccount<'a> { } pub fn increment_nonce_by(&mut self, value: u64) -> Result<()> { - let mut header = self.header_mut(); + let mut header = super::header_mut::
(&self.account); header.trx_count = header .trx_count @@ -164,7 +156,8 @@ impl<'a> BalanceAccount<'a> { #[must_use] pub fn balance(&self) -> U256 { - self.header().balance + let header = super::header::
(&self.account); + header.balance } pub fn transfer(&mut self, target: &mut BalanceAccount, value: U256) -> Result<()> { @@ -179,7 +172,7 @@ impl<'a> BalanceAccount<'a> { } pub fn burn(&mut self, value: U256) -> Result<()> { - let mut header = self.header_mut(); + let mut header = super::header_mut::
(&self.account); header.balance = header .balance @@ -194,7 +187,7 @@ impl<'a> BalanceAccount<'a> { } pub fn mint(&mut self, value: U256) -> Result<()> { - let mut header = self.header_mut(); + let mut header = super::header_mut::
(&self.account); header.balance = header .balance diff --git a/evm_loader/program/src/account/ether_contract.rs b/evm_loader/program/src/account/ether_contract.rs index 64c30a91b..04241e018 100644 --- a/evm_loader/program/src/account/ether_contract.rs +++ b/evm_loader/program/src/account/ether_contract.rs @@ -15,7 +15,9 @@ use std::{ use crate::config::STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT; -use super::{AccountsDB, ACCOUNT_PREFIX_LEN, ACCOUNT_SEED_VERSION, TAG_ACCOUNT_CONTRACT}; +use super::{ + AccountHeader, AccountsDB, ACCOUNT_PREFIX_LEN, ACCOUNT_SEED_VERSION, TAG_ACCOUNT_CONTRACT, +}; #[derive(Eq, PartialEq)] pub enum AllocateResult { @@ -24,12 +26,30 @@ pub enum AllocateResult { } #[repr(C, packed)] -pub struct Header { +pub struct HeaderV0 { pub address: Address, pub chain_id: u64, pub generation: u32, } +impl AccountHeader for HeaderV0 { + const VERSION: u8 = 0; +} + +#[repr(C, packed)] +pub struct HeaderWithRevision { + pub v0: HeaderV0, + pub revision: u32, +} + +impl AccountHeader for HeaderWithRevision { + const VERSION: u8 = 2; +} + +// Set the last version of the Header struct here +// and change the `header_size` and `header_upgrade` functions +pub type Header = HeaderWithRevision; + pub type Storage = [[u8; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT]; pub type Code = [u8]; @@ -37,16 +57,18 @@ pub struct ContractAccount<'a> { account: AccountInfo<'a>, } -const HEADER_OFFSET: usize = ACCOUNT_PREFIX_LEN; -const STORAGE_OFFSET: usize = HEADER_OFFSET + size_of::
(); -const CODE_OFFSET: usize = STORAGE_OFFSET + size_of::(); - impl<'a> ContractAccount<'a> { #[must_use] pub fn required_account_size(code: &[u8]) -> usize { ACCOUNT_PREFIX_LEN + size_of::
() + size_of::() + code.len() } + #[must_use] + pub fn required_header_realloc(&self) -> usize { + let allocated_header_size = self.header_size(); + size_of::
().saturating_sub(allocated_header_size) + } + pub fn from_account(program_id: &Pubkey, account: AccountInfo<'a>) -> Result { super::validate_tag(program_id, &account, TAG_ACCOUNT_CONTRACT)?; @@ -118,14 +140,15 @@ impl<'a> ContractAccount<'a> { let account = accounts.get(&pubkey).clone(); super::validate_tag(&crate::ID, &account, TAG_EMPTY)?; - super::set_tag(&crate::ID, &account, TAG_ACCOUNT_CONTRACT)?; + super::set_tag(&crate::ID, &account, TAG_ACCOUNT_CONTRACT, Header::VERSION)?; - let mut contract = Self::from_account(&crate::ID, account)?; + let mut contract = Self { account }; { - let mut header = contract.header_mut(); - header.address = address; - header.chain_id = chain_id; - header.generation = generation; + let mut header = super::header_mut::
(&contract.account); + header.v0.address = address; + header.v0.chain_id = chain_id; + header.v0.generation = generation; + header.revision = 1; } { let mut contract_code = contract.code_mut(); @@ -140,44 +163,72 @@ impl<'a> ContractAccount<'a> { self.account.key } - #[inline] - #[must_use] - fn header(&self) -> Ref
{ - super::section(&self.account, HEADER_OFFSET) + fn header_size(&self) -> usize { + match super::header_version(&self.account) { + 0 | 1 => size_of::(), + HeaderWithRevision::VERSION => size_of::(), + _ => panic!("Unknown header version"), + } + } + + fn header_upgrade(&mut self, rent: &Rent, db: &AccountsDB<'a>) -> Result<()> { + match super::header_version(&self.account) { + 0 | 1 => { + super::expand_header::(&self.account, rent, db)?; + } + HeaderWithRevision::VERSION => { + super::expand_header::(&self.account, rent, db)?; + } + _ => panic!("Unknown header version"), + } + + Ok(()) } #[inline] #[must_use] - fn header_mut(&mut self) -> RefMut
{ - super::section_mut(&self.account, HEADER_OFFSET) + fn storage_offset(&self) -> usize { + ACCOUNT_PREFIX_LEN + self.header_size() } #[inline] fn storage(&self) -> Ref { - super::section(&self.account, STORAGE_OFFSET) + let offset = self.storage_offset(); + super::section(&self.account, offset) } #[inline] fn storage_mut(&mut self) -> RefMut { - super::section_mut(&self.account, STORAGE_OFFSET) + let offset = self.storage_offset(); + super::section_mut(&self.account, offset) + } + + #[inline] + #[must_use] + fn code_offset(&self) -> usize { + self.storage_offset() + size_of::() } #[inline] #[must_use] pub fn code(&self) -> Ref { + let offset = self.code_offset(); + let data = self.account.data.borrow(); - Ref::map(data, |d| &d[CODE_OFFSET..]) + Ref::map(data, |d| &d[offset..]) } #[inline] - fn code_mut(&self) -> RefMut { + fn code_mut(&mut self) -> RefMut { + let offset = self.code_offset(); + let data = self.account.data.borrow_mut(); - RefMut::map(data, |d| &mut d[CODE_OFFSET..]) + RefMut::map(data, |d| &mut d[offset..]) } #[must_use] pub fn code_buffer(&self) -> crate::evm::Buffer { - let begin = CODE_OFFSET; + let begin = self.code_offset(); let end = begin + self.code_len(); unsafe { crate::evm::Buffer::from_account(&self.account, begin..end) } @@ -185,22 +236,48 @@ impl<'a> ContractAccount<'a> { #[must_use] pub fn code_len(&self) -> usize { - self.account.data_len().saturating_sub(CODE_OFFSET) + let offset = self.code_offset(); + + self.account.data_len().saturating_sub(offset) } #[must_use] pub fn address(&self) -> Address { - self.header().address + let header = super::header::(&self.account); + header.address } #[must_use] pub fn chain_id(&self) -> u64 { - self.header().chain_id + let header = super::header::(&self.account); + header.chain_id } #[must_use] pub fn generation(&self) -> u32 { - self.header().generation + let header = super::header::(&self.account); + header.generation + } + + #[must_use] + pub fn revision(&self) -> u32 { + if super::header_version(&self.account) < HeaderWithRevision::VERSION { + return 0; + } + + let header = super::header::(&self.account); + header.revision + } + + pub fn increment_revision(&mut self, rent: &Rent, db: &AccountsDB<'a>) -> Result<()> { + if super::header_version(&self.account) < HeaderWithRevision::VERSION { + self.header_upgrade(rent, db)?; + } + + let mut header = super::header_mut::(&self.account); + header.revision = header.revision.wrapping_add(1); + + Ok(()) } #[must_use] diff --git a/evm_loader/program/src/account/ether_storage.rs b/evm_loader/program/src/account/ether_storage.rs index e8300aaf0..e05617922 100644 --- a/evm_loader/program/src/account/ether_storage.rs +++ b/evm_loader/program/src/account/ether_storage.rs @@ -1,7 +1,7 @@ use std::cell::{Ref, RefMut}; use std::mem::size_of; -use super::{AccountsDB, ACCOUNT_PREFIX_LEN, TAG_STORAGE_CELL}; +use super::{AccountHeader, AccountsDB, NoHeader, ACCOUNT_PREFIX_LEN, TAG_STORAGE_CELL}; use crate::error::Result; use ethnum::U256; use solana_program::{account_info::AccountInfo, pubkey::Pubkey, rent::Rent}; @@ -78,12 +78,28 @@ pub struct StorageCell<'a> { account: AccountInfo<'a>, } -const CELLS_OFFSET: usize = ACCOUNT_PREFIX_LEN; +#[repr(C, packed)] +pub struct HeaderWithRevision { + revision: u32, +} +impl AccountHeader for HeaderWithRevision { + const VERSION: u8 = 2; +} + +// Set the last version of the Header struct here +// and change the `header_size` and `header_upgrade` functions +pub type Header = HeaderWithRevision; impl<'a> StorageCell<'a> { #[must_use] pub fn required_account_size(cells: usize) -> usize { - ACCOUNT_PREFIX_LEN + cells * size_of::() + ACCOUNT_PREFIX_LEN + size_of::
() + cells * size_of::() + } + + #[must_use] + pub fn required_header_realloc(&self) -> usize { + let allocated_header_size = self.header_size(); + size_of::
().saturating_sub(allocated_header_size) } pub fn from_account(program_id: &Pubkey, account: AccountInfo<'a>) -> Result { @@ -103,7 +119,7 @@ impl<'a> StorageCell<'a> { let cell_account = accounts.get(&address.pubkey); assert!(allocate_cells <= u8::MAX.into()); - let space = ACCOUNT_PREFIX_LEN + (allocate_cells * size_of::()); + let space = Self::required_account_size(allocate_cells); let system = accounts.system(); @@ -118,7 +134,12 @@ impl<'a> StorageCell<'a> { rent, )?; - super::set_tag(&crate::ID, cell_account, TAG_STORAGE_CELL)?; + super::set_tag(&crate::ID, cell_account, TAG_STORAGE_CELL, Header::VERSION)?; + { + let mut header = super::header_mut::
(cell_account); + header.revision = 1; + } + Ok(Self { account: cell_account.clone(), }) @@ -129,10 +150,38 @@ impl<'a> StorageCell<'a> { self.account.key } + fn header_size(&self) -> usize { + match super::header_version(&self.account) { + 0 | 1 => size_of::(), + HeaderWithRevision::VERSION => size_of::(), + _ => panic!("Unknown header version"), + } + } + + fn header_upgrade(&mut self, rent: &Rent, db: &AccountsDB<'a>) -> Result<()> { + match super::header_version(&self.account) { + 0 | 1 => { + super::expand_header::(&self.account, rent, db)?; + } + HeaderWithRevision::VERSION => { + super::expand_header::(&self.account, rent, db)?; + } + _ => panic!("Unknown header version"), + } + + Ok(()) + } + + fn cells_offset(&self) -> usize { + ACCOUNT_PREFIX_LEN + self.header_size() + } + #[must_use] pub fn cells(&self) -> Ref<[Cell]> { + let cells_offset = self.cells_offset(); + let data = self.account.data.borrow(); - let data = Ref::map(data, |d| &d[CELLS_OFFSET..]); + let data = Ref::map(data, |d| &d[cells_offset..]); Ref::map(data, |bytes| { static_assertions::assert_eq_align!(Cell, u8); @@ -149,8 +198,10 @@ impl<'a> StorageCell<'a> { #[must_use] pub fn cells_mut(&mut self) -> RefMut<[Cell]> { + let cells_offset = self.cells_offset(); + let data = self.account.data.borrow_mut(); - let data = RefMut::map(data, |d| &mut d[CELLS_OFFSET..]); + let data = RefMut::map(data, |d| &mut d[cells_offset..]); RefMut::map(data, |bytes| { static_assertions::assert_eq_align!(Cell, u8); @@ -190,7 +241,7 @@ impl<'a> StorageCell<'a> { return Ok(()); } - let new_len = self.account.data_len() + std::mem::size_of::(); // new_len <= 8.25 kb + let new_len = self.account.data_len() + size_of::(); // new_len <= 8.25 kb self.account.realloc(new_len, false)?; let mut cells = self.cells_mut(); @@ -221,4 +272,25 @@ impl<'a> StorageCell<'a> { Ok(()) } + + #[must_use] + pub fn revision(&self) -> u32 { + if super::header_version(&self.account) < HeaderWithRevision::VERSION { + return 0; + } + + let header = super::header::(&self.account); + header.revision + } + + pub fn increment_revision(&mut self, rent: &Rent, accounts: &AccountsDB<'a>) -> Result<()> { + if super::header_version(&self.account) < HeaderWithRevision::VERSION { + self.header_upgrade(rent, accounts)?; + } + + let mut header = super::header_mut::(&self.account); + header.revision = header.revision.wrapping_add(1); + + Ok(()) + } } diff --git a/evm_loader/program/src/account/holder.rs b/evm_loader/program/src/account/holder.rs index 2a9e30a55..6c9d3eace 100644 --- a/evm_loader/program/src/account/holder.rs +++ b/evm_loader/program/src/account/holder.rs @@ -7,7 +7,7 @@ use crate::account::TAG_STATE_FINALIZED; use crate::error::{Error, Result}; use crate::types::Transaction; -use super::{Operator, HOLDER_PREFIX_LEN, TAG_EMPTY, TAG_HOLDER}; +use super::{AccountHeader, Operator, ACCOUNT_PREFIX_LEN, TAG_EMPTY, TAG_HOLDER}; /// Ethereum holder data account #[repr(C, packed)] @@ -17,18 +17,22 @@ pub struct Header { pub transaction_len: usize, } +impl AccountHeader for Header { + const VERSION: u8 = 0; +} + pub struct Holder<'a> { account: AccountInfo<'a>, } -const HEADER_OFFSET: usize = HOLDER_PREFIX_LEN; +const HEADER_OFFSET: usize = ACCOUNT_PREFIX_LEN; const BUFFER_OFFSET: usize = HEADER_OFFSET + size_of::
(); impl<'a> Holder<'a> { pub fn from_account(program_id: &Pubkey, account: AccountInfo<'a>) -> Result { match super::tag(program_id, &account)? { TAG_STATE_FINALIZED => { - super::set_tag(program_id, &account, TAG_HOLDER)?; + super::set_tag(program_id, &account, TAG_HOLDER, Header::VERSION)?; let mut holder = Self { account }; holder.clear(); @@ -56,7 +60,7 @@ impl<'a> Holder<'a> { } super::validate_tag(program_id, &account, TAG_EMPTY)?; - super::set_tag(&crate::ID, &account, TAG_HOLDER)?; + super::set_tag(&crate::ID, &account, TAG_HOLDER, Header::VERSION)?; let mut holder = Self::from_account(program_id, account)?; holder.header_mut().owner = *operator.key; diff --git a/evm_loader/program/src/account/legacy/mod.rs b/evm_loader/program/src/account/legacy/mod.rs index 2a92e275c..ec75d2d6a 100644 --- a/evm_loader/program/src/account/legacy/mod.rs +++ b/evm_loader/program/src/account/legacy/mod.rs @@ -1,7 +1,6 @@ mod legacy_ether; mod legacy_holder; mod legacy_storage_cell; -mod update; pub use legacy_ether::LegacyEtherData; pub use legacy_holder::LegacyFinalizedData; @@ -11,10 +10,12 @@ pub use legacy_storage_cell::LegacyStorageData; use solana_program::system_program; use solana_program::{account_info::AccountInfo, rent::Rent, sysvar::Sysvar}; +use super::AccountHeader; use super::Holder; +use super::HolderHeader; use super::StateFinalizedAccount; -use super::TAG_ACCOUNT_BALANCE; -use super::TAG_ACCOUNT_CONTRACT; +use super::StateFinalizedHeader; +use super::StorageCellHeader; use super::TAG_HOLDER; use super::TAG_STATE_FINALIZED; use super::{AccountsDB, ContractAccount, TAG_STORAGE_CELL}; @@ -32,11 +33,6 @@ pub const TAG_ACCOUNT_CONTRACT_DEPRECATED: u8 = 12; pub const TAG_STORAGE_CELL_DEPRECATED: u8 = 42; // Before account revision (Holder and Finalized remain the same) pub const TAG_STATE_BEFORE_REVISION: u8 = 23; -pub const TAG_ACCOUNT_BALANCE_BEFORE_REVISION: u8 = 60; -pub const TAG_ACCOUNT_CONTRACT_BEFORE_REVISION: u8 = 70; -pub const TAG_STORAGE_CELL_BEFORE_REVISION: u8 = 43; - -pub const ACCOUNT_PREFIX_LEN_BEFORE_REVISION: usize = 2; fn reduce_account_size(account: &AccountInfo, required_len: usize, rent: &Rent) -> Result { assert!(account.data_len() > required_len); @@ -150,10 +146,16 @@ fn update_storage_account_from_v1( // Fill it with new data cell_account.try_borrow_mut_data()?.fill(0); - super::set_tag(&crate::ID, &cell_account, TAG_STORAGE_CELL)?; + super::set_tag( + &crate::ID, + &cell_account, + TAG_STORAGE_CELL, + StorageCellHeader::VERSION, + )?; let mut storage = StorageCell::from_account(&crate::ID, cell_account)?; storage.cells_mut().copy_from_slice(&cells); + storage.increment_revision(rent, db)?; Ok(lamports_collected) } @@ -163,7 +165,7 @@ pub fn update_holder_account(account: &AccountInfo) -> Result { TAG_HOLDER_DEPRECATED => { let legacy_data = LegacyHolderData::from_account(&crate::ID, account)?; - super::set_tag(&crate::ID, account, TAG_HOLDER)?; + super::set_tag(&crate::ID, account, TAG_HOLDER, HolderHeader::VERSION)?; let mut holder = Holder::from_account(&crate::ID, account.clone())?; holder.update(|data| { @@ -177,7 +179,12 @@ pub fn update_holder_account(account: &AccountInfo) -> Result { TAG_STATE_FINALIZED_DEPRECATED => { let legacy_data = LegacyFinalizedData::from_account(&crate::ID, account)?; - super::set_tag(&crate::ID, account, TAG_STATE_FINALIZED)?; + super::set_tag( + &crate::ID, + account, + TAG_STATE_FINALIZED, + StateFinalizedHeader::VERSION, + )?; let mut state = StateFinalizedAccount::from_account(&crate::ID, account.clone())?; state.update(|data| { @@ -198,8 +205,6 @@ pub fn update_legacy_accounts(accounts: &AccountsDB) -> Result { let mut legacy_storage = Vec::with_capacity(accounts.accounts_len()); let rent = Rent::get()?; - let op = accounts.operator(); - let system = accounts.system(); for account in accounts { if !crate::check_id(account.owner) { @@ -221,15 +226,6 @@ pub fn update_legacy_accounts(accounts: &AccountsDB) -> Result { let legacy_data = LegacyStorageData::from_account(&crate::ID, account)?; legacy_storage.push(legacy_data); } - TAG_ACCOUNT_BALANCE_BEFORE_REVISION => { - update::from_before_revision(account, TAG_ACCOUNT_BALANCE, op, system, &rent)?; - } - TAG_ACCOUNT_CONTRACT_BEFORE_REVISION => { - update::from_before_revision(account, TAG_ACCOUNT_CONTRACT, op, system, &rent)?; - } - TAG_STORAGE_CELL_BEFORE_REVISION => { - update::from_before_revision(account, TAG_STORAGE_CELL, op, system, &rent)?; - } _ => {} } } @@ -251,8 +247,5 @@ pub fn is_legacy_tag(tag: u8) -> bool { | TAG_STATE_FINALIZED_DEPRECATED | TAG_STATE_DEPRECATED | TAG_STATE_BEFORE_REVISION - | TAG_ACCOUNT_BALANCE_BEFORE_REVISION - | TAG_ACCOUNT_CONTRACT_BEFORE_REVISION - | TAG_STORAGE_CELL_BEFORE_REVISION ) } diff --git a/evm_loader/program/src/account/legacy/update.rs b/evm_loader/program/src/account/legacy/update.rs deleted file mode 100644 index 27e9ff817..000000000 --- a/evm_loader/program/src/account/legacy/update.rs +++ /dev/null @@ -1,37 +0,0 @@ -use crate::account::legacy::ACCOUNT_PREFIX_LEN_BEFORE_REVISION; -use solana_program::account_info::AccountInfo; -use solana_program::rent::Rent; - -use crate::account::program::System; -use crate::account::Operator; -use crate::account::ACCOUNT_PREFIX_LEN; -use crate::error::Result; - -pub fn from_before_revision<'a>( - account: &AccountInfo<'a>, - new_tag: u8, - operator: &Operator<'a>, - system: &System<'a>, - rent: &Rent, -) -> Result<()> { - const PREFIX_BEFORE: usize = ACCOUNT_PREFIX_LEN_BEFORE_REVISION; - const PREFIX_AFTER: usize = ACCOUNT_PREFIX_LEN; - - assert!(account.data_len() > PREFIX_BEFORE); - let data_len = account.data_len() - PREFIX_BEFORE; - - let required_len = account.data_len() + PREFIX_AFTER - PREFIX_BEFORE; - account.realloc(required_len, false)?; - - let minimum_balance = rent.minimum_balance(required_len); - if account.lamports() < minimum_balance { - let required_lamports = minimum_balance - account.lamports(); - system.transfer(operator, account, required_lamports)?; - } - - let mut account_data = account.try_borrow_mut_data()?; - account_data.copy_within(PREFIX_BEFORE..(PREFIX_BEFORE + data_len), PREFIX_AFTER); - account_data[0] = new_tag; - - Ok(()) -} diff --git a/evm_loader/program/src/account/mod.rs b/evm_loader/program/src/account/mod.rs index e1a566f47..06211ee2c 100644 --- a/evm_loader/program/src/account/mod.rs +++ b/evm_loader/program/src/account/mod.rs @@ -2,18 +2,19 @@ use crate::error::{Error, Result}; use crate::types::Address; use solana_program::account_info::AccountInfo; use solana_program::pubkey::Pubkey; +use solana_program::rent::Rent; use std::cell::{Ref, RefMut}; pub use crate::config::ACCOUNT_SEED_VERSION; pub use ether_balance::{BalanceAccount, Header as BalanceHeader}; pub use ether_contract::{AllocateResult, ContractAccount, Header as ContractHeader}; -pub use ether_storage::{StorageCell, StorageCellAddress}; -pub use holder::Holder; +pub use ether_storage::{Header as StorageCellHeader, StorageCell, StorageCellAddress}; +pub use holder::{Header as HolderHeader, Holder}; pub use incinerator::Incinerator; pub use operator::Operator; pub use state::{AccountsStatus, StateAccount}; -pub use state_finalized::StateFinalizedAccount; +pub use state_finalized::{Header as StateFinalizedHeader, StateFinalizedAccount}; pub use treasury::{MainTreasury, Treasury}; use self::program::System; @@ -36,12 +37,13 @@ pub const TAG_STATE: u8 = 24; pub const TAG_STATE_FINALIZED: u8 = 32; pub const TAG_HOLDER: u8 = 52; -pub const TAG_ACCOUNT_BALANCE: u8 = 61; -pub const TAG_ACCOUNT_CONTRACT: u8 = 71; -pub const TAG_STORAGE_CELL: u8 = 44; +pub const TAG_ACCOUNT_BALANCE: u8 = 60; +pub const TAG_ACCOUNT_CONTRACT: u8 = 70; +pub const TAG_STORAGE_CELL: u8 = 43; -pub const ACCOUNT_PREFIX_LEN: usize = 1/*tag*/ + 4/*revision*/; -pub const HOLDER_PREFIX_LEN: usize = 1/*tag*/ + 1/*reserved*/; +const TAG_OFFSET: usize = 0; +const HEADER_VERSION_OFFSET: usize = 1; +pub const ACCOUNT_PREFIX_LEN: usize = 1/*tag*/ + 1/*header version*/; #[inline] fn section<'r, T>(account: &'r AccountInfo<'_>, offset: usize) -> Ref<'r, T> { @@ -73,6 +75,70 @@ fn section_mut<'r, T>(account: &'r AccountInfo<'_>, offset: usize) -> RefMut<'r, }) } +trait AccountHeader { + const VERSION: u8; +} +struct NoHeader {} +impl AccountHeader for NoHeader { + const VERSION: u8 = 0; +} + +#[inline] +fn header<'r, T: AccountHeader>(account: &'r AccountInfo<'_>) -> Ref<'r, T> { + section(account, ACCOUNT_PREFIX_LEN) +} + +#[inline] +fn header_mut<'r, T: AccountHeader>(account: &'r AccountInfo<'_>) -> RefMut<'r, T> { + section_mut(account, ACCOUNT_PREFIX_LEN) +} + +fn expand_header<'a, From: AccountHeader, To: AccountHeader>( + account: &AccountInfo<'a>, + rent: &Rent, + db: &AccountsDB<'a>, +) -> Result<()> { + let from_len = std::mem::size_of::(); + let to_len = std::mem::size_of::(); + + assert!(to_len >= from_len); + assert!(account.data_len() >= ACCOUNT_PREFIX_LEN + from_len); + + let data_len = account.data_len() - ACCOUNT_PREFIX_LEN - from_len; + let required_len = ACCOUNT_PREFIX_LEN + to_len + data_len; + assert!(required_len >= account.data_len()); + + account.realloc(required_len, false)?; + + let minimum_balance = rent.minimum_balance(required_len); + if account.lamports() < minimum_balance { + let required_lamports = minimum_balance - account.lamports(); + + let system = db.system(); + let operator = db.operator(); + system.transfer(operator, account, required_lamports)?; + } + + { + let mut account_data = account.try_borrow_mut_data()?; + + let begin = ACCOUNT_PREFIX_LEN + from_len; + let end = begin + data_len; + let target = ACCOUNT_PREFIX_LEN + to_len; + account_data.copy_within(begin..end, target); + account_data[begin..target].fill(0); + account_data[HEADER_VERSION_OFFSET] = To::VERSION; + } + + Ok(()) +} + +fn header_version(info: &AccountInfo) -> u8 { + // This is used only inside the module and account validation should be already done + let data = info.data.borrow(); + data[HEADER_VERSION_OFFSET] +} + pub fn tag(program_id: &Pubkey, info: &AccountInfo) -> Result { if info.owner != program_id { return Err(Error::AccountInvalidOwner(*info.key, *program_id)); @@ -83,16 +149,17 @@ pub fn tag(program_id: &Pubkey, info: &AccountInfo) -> Result { return Err(Error::AccountInvalidData(*info.key)); } - Ok(data[0]) + Ok(data[TAG_OFFSET]) } -pub fn set_tag(program_id: &Pubkey, info: &AccountInfo, tag: u8) -> Result<()> { +pub fn set_tag(program_id: &Pubkey, info: &AccountInfo, tag: u8, header_version: u8) -> Result<()> { assert_eq!(info.owner, program_id); let mut data = info.try_borrow_mut_data()?; assert!(data.len() >= ACCOUNT_PREFIX_LEN); - data[0] = tag; + data[TAG_OFFSET] = tag; + data[HEADER_VERSION_OFFSET] = header_version; Ok(()) } @@ -108,34 +175,17 @@ pub fn validate_tag(program_id: &Pubkey, info: &AccountInfo, tag: u8) -> Result< } pub fn revision(program_id: &Pubkey, info: &AccountInfo) -> Result { - if info.owner != program_id { - return Err(Error::AccountInvalidOwner(*info.key, *program_id)); - } - - let data = info.try_borrow_data()?; - if data.len() < ACCOUNT_PREFIX_LEN { - return Err(Error::AccountInvalidData(*info.key)); - } - - let buffer = arrayref::array_ref![data, 1, 4]; - Ok(u32::from_le_bytes(*buffer)) -} - -pub fn increment_revision(program_id: &Pubkey, info: &AccountInfo) -> Result<()> { - if info.owner != program_id { - return Err(Error::AccountInvalidOwner(*info.key, *program_id)); - } - - let mut data = info.try_borrow_mut_data()?; - if data.len() < ACCOUNT_PREFIX_LEN { - return Err(Error::AccountInvalidData(*info.key)); + match tag(program_id, info)? { + TAG_STORAGE_CELL => { + let cell = StorageCell::from_account(program_id, info.clone())?; + Ok(cell.revision()) + } + TAG_ACCOUNT_CONTRACT => { + let contract = ContractAccount::from_account(program_id, info.clone())?; + Ok(contract.revision()) + } + _ => Ok(0), } - - let buffer = arrayref::array_mut_ref![data, 1, 4]; - let revision = u32::from_le_bytes(*buffer); - *buffer = (revision + 1).to_le_bytes(); - - Ok(()) } /// # Safety diff --git a/evm_loader/program/src/account/state.rs b/evm_loader/program/src/account/state.rs index f4e7b147f..0c6184f84 100644 --- a/evm_loader/program/src/account/state.rs +++ b/evm_loader/program/src/account/state.rs @@ -11,8 +11,8 @@ use serde::{Deserialize, Serialize}; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; use super::{ - revision, AccountsDB, BalanceAccount, Holder, StateFinalizedAccount, HOLDER_PREFIX_LEN, - TAG_HOLDER, TAG_STATE, TAG_STATE_FINALIZED, + revision, AccountHeader, AccountsDB, BalanceAccount, Holder, StateFinalizedAccount, + ACCOUNT_PREFIX_LEN, TAG_HOLDER, TAG_STATE, TAG_STATE_FINALIZED, }; #[derive(PartialEq, Eq)] @@ -41,21 +41,28 @@ struct Header { pub evm_machine_len: usize, pub data_len: usize, } +impl AccountHeader for Header { + const VERSION: u8 = 0; +} pub struct StateAccount<'a> { account: AccountInfo<'a>, data: Data, } -const HEADER_OFFSET: usize = HOLDER_PREFIX_LEN; -const BUFFER_OFFSET: usize = HEADER_OFFSET + size_of::
(); +const BUFFER_OFFSET: usize = ACCOUNT_PREFIX_LEN + size_of::
(); impl<'a> StateAccount<'a> { + #[must_use] + pub fn into_account(self) -> AccountInfo<'a> { + self.account + } + pub fn from_account(program_id: &Pubkey, account: AccountInfo<'a>) -> Result { super::validate_tag(program_id, &account, TAG_STATE)?; let (offset, len) = { - let header = super::section::
(&account, HEADER_OFFSET); + let header = super::header::
(&account); let offset = BUFFER_OFFSET + header.evm_state_len + header.evm_machine_len; (offset, header.data_len) }; @@ -91,7 +98,6 @@ impl<'a> StateAccount<'a> { tag => return Err(Error::AccountInvalidTag(*info.key, tag)), }; - // todo: get revision from account let revisions = accounts .into_iter() .map(|account| { @@ -108,10 +114,10 @@ impl<'a> StateAccount<'a> { gas_used: U256::ZERO, }; - super::set_tag(program_id, &info, TAG_STATE)?; + super::set_tag(program_id, &info, TAG_STATE, Header::VERSION)?; { // Set header - let mut header = super::section_mut::
(&info, HEADER_OFFSET); + let mut header = super::header_mut::
(&info); header.evm_state_len = 0; header.evm_machine_len = 0; header.data_len = 0; @@ -151,18 +157,8 @@ impl<'a> StateAccount<'a> { pub fn finalize(self, program_id: &Pubkey) -> Result<()> { debug_print!("Finalize Storage {}", self.account.key); - let owner = self.owner(); - let trx_hash = self.trx().hash(); - // Change tag to finalized - let account = self.account.clone(); - std::mem::drop(self); - - super::set_tag(account.owner, &account, TAG_STATE_FINALIZED)?; - StateFinalizedAccount::from_account(program_id, account)?.update(|f| { - f.owner = owner; - f.transaction_hash = trx_hash; - }); + StateFinalizedAccount::convert_from_state(program_id, self)?; Ok(()) } @@ -174,13 +170,13 @@ impl<'a> StateAccount<'a> { #[inline] #[must_use] fn header(&self) -> Ref
{ - super::section(&self.account, HEADER_OFFSET) + super::header(&self.account) } #[inline] #[must_use] fn header_mut(&mut self) -> RefMut
{ - super::section_mut(&self.account, HEADER_OFFSET) + super::header_mut(&self.account) } #[must_use] diff --git a/evm_loader/program/src/account/state_finalized.rs b/evm_loader/program/src/account/state_finalized.rs index 03e07d43e..1347817f6 100644 --- a/evm_loader/program/src/account/state_finalized.rs +++ b/evm_loader/program/src/account/state_finalized.rs @@ -1,6 +1,6 @@ use std::cell::{Ref, RefMut}; -use super::{Operator, HOLDER_PREFIX_LEN, TAG_STATE_FINALIZED}; +use super::{AccountHeader, Operator, StateAccount, TAG_STATE_FINALIZED}; use crate::{ error::{Error, Result}, types::Transaction, @@ -14,13 +14,34 @@ pub struct Header { pub transaction_hash: [u8; 32], } +impl AccountHeader for Header { + const VERSION: u8 = 0; +} + pub struct StateFinalizedAccount<'a> { account: AccountInfo<'a>, } -const HEADER_OFFSET: usize = HOLDER_PREFIX_LEN; - impl<'a> StateFinalizedAccount<'a> { + pub fn convert_from_state<'s>( + program_id: &Pubkey, + state: StateAccount<'s>, + ) -> Result> { + let owner = state.owner(); + let transaction_hash = state.trx().hash(); + + let account = state.into_account(); + + super::set_tag(program_id, &account, TAG_STATE_FINALIZED, Header::VERSION)?; + { + let mut header = super::header_mut::
(&account); + header.owner = owner; + header.transaction_hash = transaction_hash; + } + + Ok(account) + } + pub fn from_account(program_id: &Pubkey, account: AccountInfo<'a>) -> Result { super::validate_tag(program_id, &account, TAG_STATE_FINALIZED)?; Ok(Self { account }) @@ -29,13 +50,13 @@ impl<'a> StateFinalizedAccount<'a> { #[inline] #[must_use] fn header(&self) -> Ref
{ - super::section(&self.account, HEADER_OFFSET) + super::header(&self.account) } #[inline] #[must_use] fn header_mut(&mut self) -> RefMut
{ - super::section_mut(&self.account, HEADER_OFFSET) + super::header_mut(&self.account) } pub fn update(&mut self, f: F) diff --git a/evm_loader/program/src/account_storage/apply.rs b/evm_loader/program/src/account_storage/apply.rs index d42f71d23..74c26698c 100644 --- a/evm_loader/program/src/account_storage/apply.rs +++ b/evm_loader/program/src/account_storage/apply.rs @@ -1,15 +1,13 @@ -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use ethnum::U256; use solana_program::account_info::AccountInfo; use solana_program::instruction::Instruction; use solana_program::program::{invoke_signed_unchecked, invoke_unchecked}; -use solana_program::pubkey::Pubkey; use solana_program::system_program; -use crate::account::{increment_revision, BalanceAccount}; -use crate::account::{AllocateResult, ContractAccount, StorageCell}; -use crate::account_storage::{AccountStorage, ProgramAccountStorage}; +use crate::account::{AllocateResult, BalanceAccount, ContractAccount, StorageCell}; +use crate::account_storage::ProgramAccountStorage; use crate::config::{ ACCOUNT_SEED_VERSION, PAYMENT_TO_TREASURE, STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT, }; @@ -69,7 +67,6 @@ impl<'a> ProgramAccountStorage<'a> { pub fn apply_state_change(&mut self, actions: Vec) -> Result<()> { debug_print!("Applies begin"); - let mut modified_accounts: HashSet = HashSet::with_capacity(64); let mut storage = HashMap::with_capacity(16); for action in actions { @@ -105,15 +102,13 @@ impl<'a> ProgramAccountStorage<'a> { Action::EvmIncrementNonce { address, chain_id } => { let mut account = self.create_balance_account(address, chain_id)?; account.increment_nonce()?; - - // Nonce increment is not count as account modification } Action::EvmSetCode { address, chain_id, code, } => { - let account = ContractAccount::init( + ContractAccount::init( address, chain_id, 0, @@ -121,8 +116,6 @@ impl<'a> ProgramAccountStorage<'a> { &self.accounts, Some(&self.keys), )?; - - modified_accounts.insert(*account.pubkey()); } Action::EvmSelfDestruct { address: _ } => { // EIP-6780: SELFDESTRUCT only in the same transaction @@ -167,23 +160,14 @@ impl<'a> ProgramAccountStorage<'a> { } } - self.apply_storage(storage, &mut modified_accounts)?; - - for pubkey in modified_accounts { - let account = self.accounts.get(&pubkey); - increment_revision(self.program_id(), account)?; - } + self.apply_storage(storage)?; debug_print!("Applies done"); Ok(()) } - fn apply_storage( - &mut self, - storage: HashMap>, - modified_accounts: &mut HashSet, - ) -> Result<()> { + fn apply_storage(&mut self, storage: HashMap>) -> Result<()> { const STATIC_STORAGE_LIMIT: U256 = U256::new(STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT as u128); for (address, storage) in storage { @@ -214,15 +198,14 @@ impl<'a> ProgramAccountStorage<'a> { } } - if let Some(contract) = contract { - modified_accounts.insert(*contract.pubkey()); + if let Some(mut contract) = contract { + contract.increment_revision(&self.rent, &self.accounts)?; } for (index, values) in infinite_values { let cell_address = self.keys.storage_cell_address(&crate::ID, address, index); let account = self.accounts.get(cell_address.pubkey()); - modified_accounts.insert(*account.key); if system_program::check_id(account.owner) { let (_, bump) = self.keys.contract_with_bump_seed(&crate::ID, address); @@ -245,6 +228,7 @@ impl<'a> ProgramAccountStorage<'a> { } storage.sync_lamports(&self.rent, &self.accounts)?; + storage.increment_revision(&self.rent, &self.accounts)?; }; } } From 616bd86ae27f099ccf74c73d565b37568295cb70 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Tue, 5 Mar 2024 12:21:07 +0200 Subject: [PATCH 099/318] NDEV-2721: Update Solana to v1.17.24 (#293) --- .github/workflows/deploy.py | 4 +- evm_loader/Cargo.lock | 208 +++++++++++++++++----------------- evm_loader/api/Cargo.toml | 4 +- evm_loader/cli/Cargo.toml | 8 +- evm_loader/lib/Cargo.toml | 14 +-- evm_loader/program/Cargo.toml | 2 +- 6 files changed, 120 insertions(+), 120 deletions(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index dbc64bf96..c9f6b7041 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -32,8 +32,8 @@ IMAGE_NAME = os.environ.get("IMAGE_NAME") RUN_LINK_REPO = os.environ.get("RUN_LINK_REPO") DOCKERHUB_ORG_NAME = os.environ.get("DOCKERHUB_ORG_NAME") -SOLANA_NODE_VERSION = 'v1.17.23' -SOLANA_BPF_VERSION = 'v1.17.23' +SOLANA_NODE_VERSION = 'v1.17.24' +SOLANA_BPF_VERSION = 'v1.17.24' VERSION_BRANCH_TEMPLATE = r"[vt]{1}\d{1,2}\.\d{1,2}\.x.*" docker_client = docker.APIClient() diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 850beb597..a0e47b1c3 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -4680,9 +4680,9 @@ dependencies = [ [[package]] name = "solana-account-decoder" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1328bff423d12d3e79c28fb6d2445e78a81b94fa0e6a00f55c232e6880e99fc7" +checksum = "f22a6b3c7e728d335dcfca063e57e1a7c43a5ad2d6889f9b1684b1ab5cc25dd4" dependencies = [ "Inflector", "base64 0.21.4", @@ -4705,9 +4705,9 @@ dependencies = [ [[package]] name = "solana-accounts-db" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e294c2550606565f377ddbd6eb73a18de8ef7275959c8f97d65dd36af4388c" +checksum = "40d27b41953b4df1fc59e4a3f8b9d7a9c1dbe23987c33610a5de13f4e5978c73" dependencies = [ "arrayref", "bincode", @@ -4764,9 +4764,9 @@ dependencies = [ [[package]] name = "solana-address-lookup-table-program" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "667b651b78252d3e9122619bf5ef253b2d6d7b8b75aabacf3e0d156455b6b600" +checksum = "b116b626f50fddaeb00e5f2d59f891b1dc0da6ddde8faea57f068594a289410b" dependencies = [ "bincode", "bytemuck", @@ -4785,9 +4785,9 @@ dependencies = [ [[package]] name = "solana-banks-client" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca976070af24713a15bac9e7ecaf7a2a0644e956c69c3eef30f12ab9a158f1c" +checksum = "999ac7745cb153f1e42be9c13380e2858016160f8cda531d717c953452ddcc57" dependencies = [ "borsh 0.10.3", "futures", @@ -4802,9 +4802,9 @@ dependencies = [ [[package]] name = "solana-banks-interface" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c352764389315b0470fb3fae72cdc52dc32493448ecf851ac7d18973764911cf" +checksum = "6ed3ad0bfdafdc5d59fe27b1bdc4188a8449a2dc0a205b0e50751a05fbeffe41" dependencies = [ "serde", "solana-sdk", @@ -4813,9 +4813,9 @@ dependencies = [ [[package]] name = "solana-banks-server" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1a3e65b1afc76e8c3b14d5123d0d079ab4ac67c055b66bc81f06ef4ed17b066" +checksum = "5094cf57a50a33277cb404f27fdd86b5ce408245f70af2abde41cc4206cc5b7d" dependencies = [ "bincode", "crossbeam-channel", @@ -4833,9 +4833,9 @@ dependencies = [ [[package]] name = "solana-bpf-loader-program" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "febc4e59de7367286d7a03591131158d28ab4d9aba78c235a28b9c221103709f" +checksum = "201a24b71000fdc57f92b78eac49440f51c1f9fa0d9e38c16df0ca4373d188e8" dependencies = [ "bincode", "byteorder", @@ -4852,9 +4852,9 @@ dependencies = [ [[package]] name = "solana-bucket-map" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5256f726ec34d70b5edf00fd053584328e224641ca61ae3936125f86dd65fdf" +checksum = "a747b8bcb0145d8d18bf643c5923db98a68052425f84ef7782555b4faeaf053f" dependencies = [ "bv", "bytemuck", @@ -4870,9 +4870,9 @@ dependencies = [ [[package]] name = "solana-clap-utils" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2907b1af2a9490d7d3e5da72700190a1a10b05910c5c1d713e8ba3bf405b9c8" +checksum = "f0702c8a53c0c86a704ceaaa7a5bbe19d21c217b0b18815f6f629ef1b4a4d428" dependencies = [ "chrono", "clap 2.34.0", @@ -4887,9 +4887,9 @@ dependencies = [ [[package]] name = "solana-cli" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bac779927ba228c54bc02a3f74e7348a6105f8cae011a80b1b5eb9cf0eb243b" +checksum = "c343823d715ee17413e807a4646b061e0f90ced78dfe0d625ce951c34142891a" dependencies = [ "bincode", "bs58", @@ -4938,9 +4938,9 @@ dependencies = [ [[package]] name = "solana-cli-config" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e384865c29d86e3dd31c1858a886c8a071db3086488451af0f1bd5fff599f2c2" +checksum = "9bf0d8122695686e2e42f0daf6d5bd06f3b3e3e29d23fef9ab78ad0b5bc80f64" dependencies = [ "dirs-next", "lazy_static", @@ -4954,9 +4954,9 @@ dependencies = [ [[package]] name = "solana-cli-output" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af26eb67b7b84df298861d463bd0db5d22bd637d888f5e9ab3f896f327469a81" +checksum = "3f2b5acd03e51421cc6531738115ca763b168a8e34dd4442bb683eebff5c4c5a" dependencies = [ "Inflector", "base64 0.21.4", @@ -4981,9 +4981,9 @@ dependencies = [ [[package]] name = "solana-client" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33383b3ff0588d373040e6a35731bdd1d096c02decac856e4b998e91d716a87c" +checksum = "de7cc0c90c0b8ad5033062895682223d203c172d8bcecd3a1f97e91e72c10d11" dependencies = [ "async-trait", "bincode", @@ -5014,9 +5014,9 @@ dependencies = [ [[package]] name = "solana-compute-budget-program" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8707415788e82144ff5636fd7e3f2f548ca9fd6586d98d74c1f409f03bec84" +checksum = "3dbcccdbc33ffd69cb2d53089e142638745a835a2c9debd2640ad251a7d93ca3" dependencies = [ "solana-program-runtime", "solana-sdk", @@ -5024,9 +5024,9 @@ dependencies = [ [[package]] name = "solana-config-program" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6ad48b3a77b3100b9bc8d4232d12701ebb01cc66b618967c0ec0e6383c685c2" +checksum = "dae9df8d8b30eb66dd3b1bc9b634b21e5ac32ac8aea43d8114eea1553944af44" dependencies = [ "bincode", "chrono", @@ -5038,9 +5038,9 @@ dependencies = [ [[package]] name = "solana-connection-cache" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb5a74a77ee5009f0c21dcb2e020148b19dbae04d34f1660d182951f8c8fb50" +checksum = "0cd72e23fb92c6f26d5990d9196dd58be3c4b6453bb86a51bb4612bc5a37370d" dependencies = [ "async-trait", "bincode", @@ -5060,9 +5060,9 @@ dependencies = [ [[package]] name = "solana-cost-model" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89a07b79a5cbc2f85a7213263c6be1d3684edd3a20419f3a2499cee7d354280b" +checksum = "5a70328e6683d4e5fa7fc7ef5e0b1744eeb94591070e54546f7ed6110a8bfc6e" dependencies = [ "lazy_static", "log", @@ -5084,9 +5084,9 @@ dependencies = [ [[package]] name = "solana-faucet" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaa67719562286bb6b8ceb2e53461c29e162e8f3c933cbe21bde23235894b567" +checksum = "cf1a842848786964f5e1a938c0668d152691eb3dd33631cb470115dc66407418" dependencies = [ "bincode", "byteorder", @@ -5108,9 +5108,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6d876fb3f4c87f27db285da29aaeedf487af543b46502578eb05d196351089a" +checksum = "2b29d81ae90aa6acd4e7a3809d4f6516f888c780182819ccc12187cd02e59b94" dependencies = [ "ahash 0.8.5", "blake3", @@ -5138,9 +5138,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi-macro" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a27e2a4b7a77da60cbafb304bb2baa9bace62d598613e33b7c57884b885b88f" +checksum = "f9c4400284bb28fedd23abc0e7008f9ec7db8d20f9b296a438bd08ed417db98e" dependencies = [ "proc-macro2", "quote", @@ -5150,9 +5150,9 @@ dependencies = [ [[package]] name = "solana-loader-v4-program" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac0cbe022710e9a2dff7e4d9b4c80d8fc2a192f33b0eaf6011bd577a2552416" +checksum = "ac967ae044389601bda6a5158c397f6a3bbcbbf558b93e127782c702f0649a89" dependencies = [ "log", "solana-measure", @@ -5163,9 +5163,9 @@ dependencies = [ [[package]] name = "solana-logger" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73dfd133ceea9cf5680ec12ba57a7799de8485ed98872c6119f14d16763c6e79" +checksum = "8c0fbccd60c8332712714468630d51c8668c838459fc5ffecfa615c84248eb82" dependencies = [ "env_logger", "lazy_static", @@ -5174,9 +5174,9 @@ dependencies = [ [[package]] name = "solana-measure" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bd22e62fed123d8fb69acc20cc432697e44adc72dddfd02e7508f7f9cab7f26" +checksum = "79e1efcb7d2d9e4c4cf2f65c15505e1b4967bbfadd2aa004e417488b015be9fc" dependencies = [ "log", "solana-sdk", @@ -5184,9 +5184,9 @@ dependencies = [ [[package]] name = "solana-metrics" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611d1984046d267513a15fd23f735710e1b251bc94bd2f8571c042c943d1da4d" +checksum = "11c7e8d9664ab39890f627abc142d5f0402a16cb3591be4fdd288dbc35bd786c" dependencies = [ "crossbeam-channel", "gethostname", @@ -5199,9 +5199,9 @@ dependencies = [ [[package]] name = "solana-net-utils" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46abbfacb7dd8a0b1881c43653aed39727a99c950dcb643295ccc85e793d7aa4" +checksum = "1a39ec45feab4006a0c6a798642295947632d2b92ac75495c33387014667f9e6" dependencies = [ "bincode", "clap 3.2.23", @@ -5221,9 +5221,9 @@ dependencies = [ [[package]] name = "solana-perf" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1051b18175b0981fabbb5c533c21b1c4d78a93cde65511069df4a07163f68aa3" +checksum = "3950864d7f38cfe7d4c800101b22784c04db29fd9e154f28e983e46cb6d980cb" dependencies = [ "ahash 0.8.5", "bincode", @@ -5250,9 +5250,9 @@ dependencies = [ [[package]] name = "solana-program" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bf510602760dc760fb8b6475b3d51c7a6ba0b4e13ee074e96c4811f411b9582" +checksum = "6e6f6bf27bf9e16803bfe6a2fe01b2431258ec9b4d6ea17b801717480995aaa0" dependencies = [ "ark-bn254", "ark-ec", @@ -5304,9 +5304,9 @@ dependencies = [ [[package]] name = "solana-program-runtime" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "872b506fec2ed7f1c5239f6b22a3a823679cdf9dab54b17d04bec24493861c4f" +checksum = "4a92f2a945295cdc782e5a9223b96982755e32babc6e7992ca3f73ccccd111ce" dependencies = [ "base64 0.21.4", "bincode", @@ -5332,9 +5332,9 @@ dependencies = [ [[package]] name = "solana-program-test" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96260a3e1f0c6cbcbb24a7aa7dbce880d762dffd19c629fb3ea5518797a38286" +checksum = "ee70dfdbb935266d7d85adcf957eec196bd033a7b8fbce16db21611cbf91d582" dependencies = [ "assert_matches", "async-trait", @@ -5362,9 +5362,9 @@ dependencies = [ [[package]] name = "solana-pubsub-client" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af99e8f781c460e51198ec75842feb45bb68832f215b5bc091ca15e869474604" +checksum = "01c9090c2938ee4e02ac09528e2fc03897ef6645310cf8ba340baa8324eb1796" dependencies = [ "crossbeam-channel", "futures-util", @@ -5387,9 +5387,9 @@ dependencies = [ [[package]] name = "solana-quic-client" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd30628a2d4bf2c8a058b6cd9e8e7c9547d341507c5ef8a3ed242692aa3f80e8" +checksum = "25be026b8fe02dbef50af9f0942a306d8b2b536e407c8caf8947ef39e8ca1001" dependencies = [ "async-mutex", "async-trait", @@ -5414,9 +5414,9 @@ dependencies = [ [[package]] name = "solana-rayon-threadlimit" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d2146d364a57123db3712bb5a67957cded933bed5e6b768ef79745bb13790cf" +checksum = "ce88200cc41f31414d149d2c9753512ecf746ac60da1e22631684fdfe99cf5c9" dependencies = [ "lazy_static", "num_cpus", @@ -5424,9 +5424,9 @@ dependencies = [ [[package]] name = "solana-remote-wallet" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4335d48797fa2a03f1308c5ed55c2f8eaf8d3e16226ce3b9f4fb3ae19e02a0d" +checksum = "c5ca14a3dbc4a608698bba5fef23456072cee476592bf00f44dec0bff19417d4" dependencies = [ "console", "dialoguer", @@ -5444,9 +5444,9 @@ dependencies = [ [[package]] name = "solana-rpc-client" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2192eed56e9829591a425ac1150352346ad0036333f02ec58befcad4dd62ef2" +checksum = "45106dab6a4b406ddfd6c0e6f4b4dea2c1cac5d1dbaf11ed644fc102f7293a9b" dependencies = [ "async-trait", "base64 0.21.4", @@ -5470,9 +5470,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-api" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "148e4878747e42cceaa84baba799d9b8317619dbb84710c938c71ed950f78d08" +checksum = "0190bf789cc7a1f3508928f01051381cc15bda16120a2a080ff10aa311388970" dependencies = [ "base64 0.21.4", "bs58", @@ -5492,9 +5492,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-nonce-utils" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8e2522d0cbc503fbef9bb8dff78aef870f97d3d6d6a619fd5723502c01ddae" +checksum = "0959c952240cf1cf07de24c8a40ac8531ba545640558f7634c492ce8cf4a5005" dependencies = [ "clap 2.34.0", "solana-clap-utils", @@ -5505,9 +5505,9 @@ dependencies = [ [[package]] name = "solana-runtime" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58e34d07dd0f14a8168df48f9286b3a5ac4ae361b90a62a6bc7ce907ab93b288" +checksum = "64ca87344dfc2b5e1058b4d528b736076d9b335a1cf69a3de2bb3807f8c72594" dependencies = [ "arrayref", "base64 0.21.4", @@ -5582,9 +5582,9 @@ dependencies = [ [[package]] name = "solana-sdk" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "804dc98b9e5bfde2ca20675f6fc75cabbc520766bda369e253dd0a56a1228106" +checksum = "aa149a29cb505742bca6bce7447d979e746452ec40e9b1eb3e50d51a0f0510cd" dependencies = [ "assert_matches", "base64 0.21.4", @@ -5636,9 +5636,9 @@ dependencies = [ [[package]] name = "solana-sdk-macro" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5243f26d84a7c81472482dc1fafad97d531ba81d3c086b0a201d36ead9c73472" +checksum = "bd8ad88355cf03e34b60ba12f65dffc44054e453aa1113a50169ee42ab6ad7a3" dependencies = [ "bs58", "proc-macro2", @@ -5655,9 +5655,9 @@ checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" [[package]] name = "solana-send-transaction-service" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301c844f470bcf187019321def9e78be775c9d60b978cc42f1fb9b3a3a55089c" +checksum = "97189214ed892e0b1159b066e1a2f69f0414610959e5ac39272dd9c4a4575b6a" dependencies = [ "crossbeam-channel", "log", @@ -5671,9 +5671,9 @@ dependencies = [ [[package]] name = "solana-stake-program" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bea6bc0d5b5e03ed55b9a55efbe1ed31a30dd13afbc54e42beb0d59cbbf97f7" +checksum = "a2f190c96ebe38627c135cf32593c5981faa621fda571372ac44a3e5cb2eaa53" dependencies = [ "bincode", "log", @@ -5686,9 +5686,9 @@ dependencies = [ [[package]] name = "solana-streamer" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e54f2e4f990c4af272649ed8de1aac16e4a86cff4781c6ba8ab2bde97f555a9" +checksum = "8df7b1d9cfdfa37d3940ca6c20fa75e989e12432a430ebcb0e4ab316eb0e437b" dependencies = [ "async-channel", "bytes", @@ -5718,9 +5718,9 @@ dependencies = [ [[package]] name = "solana-system-program" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "969d0f17f952d4637fd378d3851ffc725affa933578342d60c1c63a5e39aa09e" +checksum = "ec764e30a69176a680591f1b4e24af91df7c5a3923804c994bb2f11310264f18" dependencies = [ "bincode", "log", @@ -5732,9 +5732,9 @@ dependencies = [ [[package]] name = "solana-thin-client" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82f608ca246c269826c6c9e656b516cea7c4cadaaa93bc618fc2853dff5c9b2d" +checksum = "00c98d10503361d23f2146a42d87639d7b58081d84b8c3b3cc7958db9434b655" dependencies = [ "bincode", "log", @@ -5747,9 +5747,9 @@ dependencies = [ [[package]] name = "solana-tpu-client" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce2edc9eda28483d3df9f81a0df9dfdaaa901e8e1dc67cca08347a20c4d6bb9d" +checksum = "3e82965ce39184e2618f0c38f5aed625cdaf2aac1d6fe0d665ddcc9771d6313f" dependencies = [ "async-trait", "bincode", @@ -5771,9 +5771,9 @@ dependencies = [ [[package]] name = "solana-transaction-status" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24e030da0ce03190dcc88976beb88b7c4171df743ace669a7b0c17a74f3b7308" +checksum = "2a4107eac6b20f3349c49af21eaca73cd3d92a2c1b03118531349415ab4e7f84" dependencies = [ "Inflector", "base64 0.21.4", @@ -5796,9 +5796,9 @@ dependencies = [ [[package]] name = "solana-udp-client" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8120e28208a12f7a4429c9c03f4bac15bed89ecb91a37008e686597dfd88ae6a" +checksum = "def72d6f0b3d9f67a6a4ad4407abe318e31f816dd76d8bc6c410bacb6de68aad" dependencies = [ "async-trait", "solana-connection-cache", @@ -5811,9 +5811,9 @@ dependencies = [ [[package]] name = "solana-version" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6294848afd9ff8c36296f41633a59b45145ebe4c235013377b78f63267146034" +checksum = "67f6b247004ce32a78a3e441f7d90f07cb4ade51e07ac32bccbb493ab41f6261" dependencies = [ "log", "rustc_version", @@ -5827,9 +5827,9 @@ dependencies = [ [[package]] name = "solana-vote" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee90f71f4a6257aaf06e0cd5cc35873602a6d5f82408d537f0bf609c8cd877c0" +checksum = "d34a426bb298693984bd7e224468d64dc0244906262fd5c623c413bd85775a2f" dependencies = [ "crossbeam-channel", "itertools 0.10.5", @@ -5846,9 +5846,9 @@ dependencies = [ [[package]] name = "solana-vote-program" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04b5b6063d5bd743b9bd62db49ce4a3c0a5aee4f4b995572f8ceb3426dcd9576" +checksum = "2ea6ab44f5f52fba9daa7455686e516c4fde9004503503f6ecbd1975e5875226" dependencies = [ "bincode", "log", @@ -5868,9 +5868,9 @@ dependencies = [ [[package]] name = "solana-zk-token-proof-program" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eee2446fba39f1effca8ba2bf74be1bb767f2649fd5b09aa62b143721ccb87a4" +checksum = "e517ac4c61fb4bee20fb24ac0d0b938be4ef307cc500d4c4c253d241b147d231" dependencies = [ "bytemuck", "num-derive 0.3.3", @@ -5882,9 +5882,9 @@ dependencies = [ [[package]] name = "solana-zk-token-sdk" -version = "1.17.23" +version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfa5d13db62ccc05172c0b95b384a3bdbfb724e72b3f90b4b8c673ac72efc2cf" +checksum = "7845f8390725707661732fb4df99c5c82eb3f7549c187160c317706e839c5702" dependencies = [ "aes-gcm-siv", "base64 0.21.4", diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 5ea81cedd..8050d8070 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -8,8 +8,8 @@ edition = "2021" [dependencies] clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } -solana-sdk = "=1.17.23" -solana-client = "=1.17.23" +solana-sdk = "=1.17.24" +solana-client = "=1.17.24" serde = "1.0.186" serde_json = { version = "1.0.107", features = ["preserve_order"] } ethnum = { version = "1.4", default-features = false, features = ["serde"] } diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index d19b12bd0..0357766c3 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -8,10 +8,10 @@ edition = "2021" [dependencies] clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } -solana-sdk = "=1.17.23" -solana-client = "=1.17.23" -solana-clap-utils = "=1.17.23" -solana-cli-config = "=1.17.23" +solana-sdk = "=1.17.24" +solana-client = "=1.17.24" +solana-clap-utils = "=1.17.24" +solana-cli-config = "=1.17.24" hex = "0.4.2" serde = "1.0.186" serde_json = { version = "1.0.107", features = ["preserve_order"] } diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index f567077a9..b955194a4 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -10,13 +10,13 @@ thiserror = "1.0" anyhow = "1.0" bincode = "1.3.1" evm-loader = { path = "../program", default-features = false, features = ["log", "async-trait"] } -solana-sdk = "=1.17.23" -solana-client = "=1.17.23" -solana-clap-utils = "=1.17.23" -solana-cli-config = "=1.17.23" -solana-cli = "=1.17.23" -solana-transaction-status = "=1.17.23" -solana-program-test = "=1.17.23" +solana-sdk = "=1.17.24" +solana-client = "=1.17.24" +solana-clap-utils = "=1.17.24" +solana-cli-config = "=1.17.24" +solana-cli = "=1.17.24" +solana-transaction-status = "=1.17.24" +solana-program-test = "=1.17.24" spl-token = { version = "~4.0", default-features = false, features = ["no-entrypoint"] } spl-associated-token-account = { version = "~2.3", default-features = false, features = ["no-entrypoint"] } bs58 = "0.4.0" diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index a82b8f557..62f52c3f9 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -37,7 +37,7 @@ default = ["custom-heap"] [dependencies] linked_list_allocator = { version = "0.10", default-features = false } evm-loader-macro = { path = "../program-macro" } -solana-program = { version = "=1.17.23", default-features = false } +solana-program = { version = "=1.17.24", default-features = false } spl-token = { version = "~4.0", default-features = false, features = ["no-entrypoint"] } spl-associated-token-account = { version = "~2.3", default-features = false, features = ["no-entrypoint"] } mpl-token-metadata = { version = "~4.1", default-features = false } From 32f97b91fc30e1f59f79c19d441f412c1d6c99b9 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Tue, 5 Mar 2024 13:55:56 +0300 Subject: [PATCH 100/318] Set version to 1.11.0-dev (#295) --- evm_loader/Cargo.lock | 8 ++++---- evm_loader/api/Cargo.toml | 2 +- evm_loader/cli/Cargo.toml | 2 +- evm_loader/lib/Cargo.toml | 2 +- evm_loader/program/Cargo.toml | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index a0e47b1c3..5d6ba014a 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -1883,7 +1883,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "evm-loader" -version = "1.9.0-dev" +version = "1.11.0-dev" dependencies = [ "arrayref", "async-trait", @@ -3064,7 +3064,7 @@ dependencies = [ [[package]] name = "neon-api" -version = "0.1.0" +version = "1.11.0-dev" dependencies = [ "actix-request-identifier", "actix-web", @@ -3088,7 +3088,7 @@ dependencies = [ [[package]] name = "neon-cli" -version = "1.9.0-dev" +version = "1.11.0-dev" dependencies = [ "build-info", "build-info-build", @@ -3110,7 +3110,7 @@ dependencies = [ [[package]] name = "neon-lib" -version = "0.1.0" +version = "1.11.0-dev" dependencies = [ "anyhow", "async-trait", diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 8050d8070..6f814c9d7 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "neon-api" -version = "0.1.0" +version = "1.11.0-dev" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index 0357766c3..c1f228e35 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "neon-cli" -version = "1.9.0-dev" +version = "1.11.0-dev" authors = ["NeonLabs Maintainers "] edition = "2021" diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index b955194a4..0b81f1d26 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "neon-lib" -version = "0.1.0" +version = "1.11.0-dev" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 62f52c3f9..4818a806d 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "evm-loader" -version = "1.9.0-dev" +version = "1.11.0-dev" description = "Neon EVM loader" authors = ["NeonLabs Maintainers "] edition = "2021" From d3357eccda24b79c463f336fedf5ad13c1dc1057 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Mar 2024 17:26:04 +0200 Subject: [PATCH 101/318] Bump unsafe-libyaml from 0.2.9 to 0.2.10 in /evm_loader (#296) Bumps [unsafe-libyaml](https://github.com/dtolnay/unsafe-libyaml) from 0.2.9 to 0.2.10. - [Release notes](https://github.com/dtolnay/unsafe-libyaml/releases) - [Commits](https://github.com/dtolnay/unsafe-libyaml/compare/0.2.9...0.2.10) --- updated-dependencies: - dependency-name: unsafe-libyaml dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 5d6ba014a..a65ecea1f 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -6859,9 +6859,9 @@ dependencies = [ [[package]] name = "unsafe-libyaml" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa" +checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" [[package]] name = "untrusted" From 629f8d406c4d2248381a00351d0cab5614116216 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Mar 2024 17:50:23 +0200 Subject: [PATCH 102/318] Bump itertools from 0.11.0 to 0.12.1 in /evm_loader (#290) Bumps [itertools](https://github.com/rust-itertools/itertools) from 0.11.0 to 0.12.1. - [Changelog](https://github.com/rust-itertools/itertools/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-itertools/itertools/compare/v0.11.0...v0.12.1) --- updated-dependencies: - dependency-name: itertools dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 6 +++--- evm_loader/program-macro/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index a65ecea1f..b9a8e54e4 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -1915,7 +1915,7 @@ name = "evm-loader-macro" version = "1.0.0" dependencies = [ "bs58", - "itertools 0.11.0", + "itertools 0.12.1", "proc-macro2", "quote", "serde", @@ -2652,9 +2652,9 @@ dependencies = [ [[package]] name = "itertools" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" dependencies = [ "either", ] diff --git a/evm_loader/program-macro/Cargo.toml b/evm_loader/program-macro/Cargo.toml index 2ac895935..5255b1dde 100644 --- a/evm_loader/program-macro/Cargo.toml +++ b/evm_loader/program-macro/Cargo.toml @@ -12,7 +12,7 @@ proc-macro = true syn = "1" proc-macro2 = "1" quote = "1" -itertools = "0.11" +itertools = "0.12" bs58 = "0.4" serde = { version = "1.0", features = [ "derive" ] } toml = "0.8" From a69ace728854042341f94268934175e79af3b06c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Mar 2024 18:14:40 +0200 Subject: [PATCH 103/318] Bump h2 from 0.3.18 to 0.3.24 in /evm_loader (#297) Bumps [h2](https://github.com/hyperium/h2) from 0.3.18 to 0.3.24. - [Release notes](https://github.com/hyperium/h2/releases) - [Changelog](https://github.com/hyperium/h2/blob/v0.3.24/CHANGELOG.md) - [Commits](https://github.com/hyperium/h2/compare/v0.3.18...v0.3.24) --- updated-dependencies: - dependency-name: h2 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index b9a8e54e4..0fe81a0e5 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -2220,9 +2220,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.18" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17f8a914c2987b688368b5138aa05321db91f4090cf26118185672ad588bce21" +checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" dependencies = [ "bytes", "fnv", @@ -2230,7 +2230,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 1.9.3", + "indexmap 2.2.3", "slab", "tokio", "tokio-util 0.7.7", From e576b6300764de61696d4b2531e8ed58229fc124 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Mar 2024 18:37:42 +0200 Subject: [PATCH 104/318] Bump mio from 0.8.6 to 0.8.11 in /evm_loader (#298) Bumps [mio](https://github.com/tokio-rs/mio) from 0.8.6 to 0.8.11. - [Release notes](https://github.com/tokio-rs/mio/releases) - [Changelog](https://github.com/tokio-rs/mio/blob/master/CHANGELOG.md) - [Commits](https://github.com/tokio-rs/mio/compare/v0.8.6...v0.8.11) --- updated-dependencies: - dependency-name: mio dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 0fe81a0e5..585d91d26 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -3000,14 +3000,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.6" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] From be59e512c5c7514715fe178aaebd243877bd599e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Mar 2024 19:04:26 +0200 Subject: [PATCH 105/318] Bump openssl from 0.10.50 to 0.10.64 in /evm_loader (#299) Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.50 to 0.10.64. - [Release notes](https://github.com/sfackler/rust-openssl/releases) - [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.50...openssl-v0.10.64) --- updated-dependencies: - dependency-name: openssl dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 585d91d26..2e5c19ee3 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -3390,11 +3390,11 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.50" +version = "0.10.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e30d8bc91859781f0a943411186324d580f2bbeb71b452fe91ae344806af3f1" +checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.0", "cfg-if", "foreign-types", "libc", @@ -3422,9 +3422,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.85" +version = "0.9.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d3d193fb1488ad46ffe3aaabc912cc931d02ee8518fe2959aea8ef52718b0c0" +checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff" dependencies = [ "cc", "libc", From fda0e113f60a0d02d5b4cc1ce9512eb80bf80923 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Mar 2024 19:33:53 +0200 Subject: [PATCH 106/318] Bump serde_json from 1.0.108 to 1.0.114 in /evm_loader (#303) Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.108 to 1.0.114. - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.108...v1.0.114) --- updated-dependencies: - dependency-name: serde_json dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- evm_loader/api/Cargo.toml | 2 +- evm_loader/cli/Cargo.toml | 2 +- evm_loader/program/Cargo.toml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 2e5c19ee3..2a5f7849e 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -4417,9 +4417,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "indexmap 2.2.3", "itoa", diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 6f814c9d7..07530d875 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -11,7 +11,7 @@ evm-loader = { path = "../program", default-features = false, features = ["log"] solana-sdk = "=1.17.24" solana-client = "=1.17.24" serde = "1.0.186" -serde_json = { version = "1.0.107", features = ["preserve_order"] } +serde_json = { version = "1.0.114", features = ["preserve_order"] } ethnum = { version = "1.4", default-features = false, features = ["serde"] } tokio = { version = "1", features = ["full"] } tracing = "0.1" diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index c1f228e35..28f2d53fd 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -14,7 +14,7 @@ solana-clap-utils = "=1.17.24" solana-cli-config = "=1.17.24" hex = "0.4.2" serde = "1.0.186" -serde_json = { version = "1.0.107", features = ["preserve_order"] } +serde_json = { version = "1.0.114", features = ["preserve_order"] } log = "0.4.17" fern = "0.6" ethnum = { version = "1.4", default-features = false, features = ["serde"] } diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 4818a806d..bd440cc85 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -63,7 +63,7 @@ features = ["is_sync"] [dev-dependencies] tokio = { version = "1.0", features = ["full"] } -serde_json = { version = "1.0.107", features = ["preserve_order"] } +serde_json = { version = "1.0.114", features = ["preserve_order"] } [lib] crate-type = ["cdylib", "lib"] From e46cb7c5716bf8a043f40b9112f01871359d4b76 Mon Sep 17 00:00:00 2001 From: Vladimir Bugaev Date: Thu, 7 Mar 2024 20:25:47 +0700 Subject: [PATCH 107/318] neon core rpc (#215) * neon core rpc * add param to CI * emulate response has been fixed * fix fmt --- .gitignore | 3 +- Dockerfile | 16 +- ci/docker-compose-ci.yml | 33 +- ci/docker-compose-test.yml | 31 ++ evm_loader/Cargo.lock | 334 +++++++++++- evm_loader/Cargo.toml | 5 +- evm_loader/api/src/api_server/mod.rs | 1 - evm_loader/api/src/main.rs | 7 +- evm_loader/lib-interface/.gitignore | 1 + evm_loader/lib-interface/Cargo.lock | 474 ++++++++++++++++++ evm_loader/lib-interface/Cargo.toml | 13 + evm_loader/lib-interface/src/lib.rs | 59 +++ evm_loader/lib-interface/src/types.rs | 12 + evm_loader/lib/Cargo.toml | 10 + evm_loader/lib/src/abi/emulate.rs | 20 + evm_loader/lib/src/abi/get_balance.rs | 17 + evm_loader/lib/src/abi/get_config.rs | 12 + evm_loader/lib/src/abi/get_contract.rs | 17 + evm_loader/lib/src/abi/get_holder.rs | 17 + evm_loader/lib/src/abi/get_storage_at.rs | 17 + evm_loader/lib/src/abi/mod.rs | 137 +++++ .../src/api_server => lib/src/abi}/state.rs | 8 +- evm_loader/lib/src/abi/trace.rs | 19 + evm_loader/lib/src/commands/get_config.rs | 4 +- evm_loader/lib/src/commands/get_holder.rs | 14 +- evm_loader/lib/src/config.rs | 6 +- evm_loader/lib/src/errors.rs | 13 + evm_loader/lib/src/lib.rs | 31 ++ evm_loader/lib/src/types/mod.rs | 24 + evm_loader/rpc-client/Cargo.toml | 19 + evm_loader/rpc-client/src/config.rs | 9 + evm_loader/rpc-client/src/error.rs | 9 + evm_loader/rpc-client/src/http.rs | 110 ++++ evm_loader/rpc-client/src/lib.rs | 40 ++ evm_loader/rpc/.gitignore | 3 + evm_loader/rpc/Cargo.toml | 25 + evm_loader/rpc/build.rs | 3 + evm_loader/rpc/src/build_info.rs | 7 + evm_loader/rpc/src/context.rs | 6 + evm_loader/rpc/src/error.rs | 27 + evm_loader/rpc/src/handlers/emulate.rs | 17 + evm_loader/rpc/src/handlers/get_balance.rs | 17 + evm_loader/rpc/src/handlers/get_config.rs | 8 + evm_loader/rpc/src/handlers/get_contract.rs | 17 + evm_loader/rpc/src/handlers/get_holder.rs | 17 + evm_loader/rpc/src/handlers/get_storage_at.rs | 17 + evm_loader/rpc/src/handlers/info.rs | 7 + evm_loader/rpc/src/handlers/lib_info.rs | 7 + evm_loader/rpc/src/handlers/mod.rs | 82 +++ evm_loader/rpc/src/handlers/trace.rs | 17 + evm_loader/rpc/src/main.rs | 75 +++ evm_loader/rpc/src/options.rs | 26 + evm_loader/rpc/src/rpc.rs | 24 + 53 files changed, 1913 insertions(+), 31 deletions(-) create mode 100644 evm_loader/lib-interface/.gitignore create mode 100644 evm_loader/lib-interface/Cargo.lock create mode 100644 evm_loader/lib-interface/Cargo.toml create mode 100644 evm_loader/lib-interface/src/lib.rs create mode 100644 evm_loader/lib-interface/src/types.rs create mode 100644 evm_loader/lib/src/abi/emulate.rs create mode 100644 evm_loader/lib/src/abi/get_balance.rs create mode 100644 evm_loader/lib/src/abi/get_config.rs create mode 100644 evm_loader/lib/src/abi/get_contract.rs create mode 100644 evm_loader/lib/src/abi/get_holder.rs create mode 100644 evm_loader/lib/src/abi/get_storage_at.rs create mode 100644 evm_loader/lib/src/abi/mod.rs rename evm_loader/{api/src/api_server => lib/src/abi}/state.rs (83%) create mode 100644 evm_loader/lib/src/abi/trace.rs create mode 100644 evm_loader/rpc-client/Cargo.toml create mode 100644 evm_loader/rpc-client/src/config.rs create mode 100644 evm_loader/rpc-client/src/error.rs create mode 100644 evm_loader/rpc-client/src/http.rs create mode 100644 evm_loader/rpc-client/src/lib.rs create mode 100644 evm_loader/rpc/.gitignore create mode 100644 evm_loader/rpc/Cargo.toml create mode 100644 evm_loader/rpc/build.rs create mode 100644 evm_loader/rpc/src/build_info.rs create mode 100644 evm_loader/rpc/src/context.rs create mode 100644 evm_loader/rpc/src/error.rs create mode 100644 evm_loader/rpc/src/handlers/emulate.rs create mode 100644 evm_loader/rpc/src/handlers/get_balance.rs create mode 100644 evm_loader/rpc/src/handlers/get_config.rs create mode 100644 evm_loader/rpc/src/handlers/get_contract.rs create mode 100644 evm_loader/rpc/src/handlers/get_holder.rs create mode 100644 evm_loader/rpc/src/handlers/get_storage_at.rs create mode 100644 evm_loader/rpc/src/handlers/info.rs create mode 100644 evm_loader/rpc/src/handlers/lib_info.rs create mode 100644 evm_loader/rpc/src/handlers/mod.rs create mode 100644 evm_loader/rpc/src/handlers/trace.rs create mode 100644 evm_loader/rpc/src/main.rs create mode 100644 evm_loader/rpc/src/options.rs create mode 100644 evm_loader/rpc/src/rpc.rs diff --git a/.gitignore b/.gitignore index d79576072..cc74be73e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ target .env .vscode +.trunk bin config.json node_modules @@ -14,4 +15,4 @@ hfuzz_workspace *.code-workspace evm_loader/solidity/artifacts evm_loader/solidity/cache -test-ledger \ No newline at end of file +test-ledger diff --git a/Dockerfile b/Dockerfile index 0d44a9d57..636b6c3fb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,13 +19,13 @@ ENV NEON_REVISION=${REVISION} RUN cargo fmt --check && \ cargo clippy --release && \ cargo build --release && \ - cargo build-bpf --features devnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-devnet.so && \ - cargo build-bpf --features testnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-testnet.so && \ - cargo build-bpf --features govertest && cp target/deploy/evm_loader.so target/deploy/evm_loader-govertest.so && \ - cargo build-bpf --features govertest,emergency && cp target/deploy/evm_loader.so target/deploy/evm_loader-govertest-emergency.so && \ - cargo build-bpf --features mainnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-mainnet.so && \ - cargo build-bpf --features mainnet,emergency && cp target/deploy/evm_loader.so target/deploy/evm_loader-mainnet-emergency.so && \ - cargo build-bpf --features ci --dump + cargo build-bpf --manifest-path program/Cargo.toml --features devnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-devnet.so && \ + cargo build-bpf --manifest-path program/Cargo.toml --features testnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-testnet.so && \ + cargo build-bpf --manifest-path program/Cargo.toml --features govertest && cp target/deploy/evm_loader.so target/deploy/evm_loader-govertest.so && \ + cargo build-bpf --manifest-path program/Cargo.toml --features govertest,emergency && cp target/deploy/evm_loader.so target/deploy/evm_loader-govertest-emergency.so && \ + cargo build-bpf --manifest-path program/Cargo.toml --features mainnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-mainnet.so && \ + cargo build-bpf --manifest-path program/Cargo.toml --features mainnet,emergency && cp target/deploy/evm_loader.so target/deploy/evm_loader-mainnet-emergency.so && \ + cargo build-bpf --manifest-path program/Cargo.toml --features ci --dump # Add neon_test_invoke_program to the genesis @@ -42,6 +42,8 @@ COPY --from=evm-loader-builder /opt/neon-evm/evm_loader/target/release/neon-cli COPY --from=evm-loader-builder /opt/neon-evm/evm_loader/target/release/neon-api /opt/ COPY --from=neon_test_programs /opt/deploy/ /opt/deploy/ +COPY --from=evm-loader-builder /opt/neon-evm/evm_loader/target/release/neon-rpc /opt/ +COPY --from=evm-loader-builder /opt/neon-evm/evm_loader/target/release/libneon_lib.so /opt/libs/current/ COPY ci/wait-for-solana.sh \ ci/wait-for-neon.sh \ diff --git a/ci/docker-compose-ci.yml b/ci/docker-compose-ci.yml index a6351e0be..07b6549f2 100644 --- a/ci/docker-compose-ci.yml +++ b/ci/docker-compose-ci.yml @@ -8,7 +8,7 @@ services: - CI=true hostname: solana ports: - - "8899" + - "8899" expose: - "8899" ulimits: @@ -43,11 +43,42 @@ services: networks: - net + neon-core-rpc: + restart: unless-stopped + hostname: neon_core_rpc + entrypoint: /opt/neon-rpc /opt/libs/current + environment: + RUST_BACKTRACE: full + RUST_LOG: neon=debug + NEON_API_LISTENER_ADDR: 0.0.0.0:3100 + SOLANA_URL: http://solana:8899 + EVM_LOADER: 53DfF883gyixYNXnM7s5xhdeyV8mVk9T4i2hGV9vG9io + NEON_TOKEN_MINT: HPsV9Deocecw3GeZv1FkAPNCBRfuVyfw9MMwjwRe1xaU + NEON_CHAIN_ID: 111 + COMMITMENT: confirmed + NEON_DB_CLICKHOUSE_URLS: "http://45.250.253.36:8123;http://45.250.253.38:8123" + NEON_DB_INDEXER_HOST: 45.250.253.32 + NEON_DB_INDEXER_PORT: 5432 + NEON_DB_INDEXER_DATABASE: indexer + NEON_DB_INDEXER_USER: postgres + NEON_DB_INDEXER_PASSWORD: "vUlpDyAP0gA98R5Bu" + KEYPAIR: /opt/operator-keypairs/id.json + FEEPAIR: /opt/operator-keypairs/id.json + SOLANA_KEY_FOR_CONFIG: BMp6gEnveANdvSvspESJUrNczuHz1GF5UQKjVLCkAZih + image: ${EVM_LOADER_IMAGE} + ports: + - "3100" + expose: + - "3100" + networks: + - net + tests: image: ${NEON_TESTS_IMAGE} environment: - SOLANA_URL=http://solana:8899 - NEON_CORE_API_URL=http://neon_api:8085/api + - NEON_CORE_API_RPC_URL=http://neon_core_rpc:3100 hostname: tests command: sleep infinity networks: diff --git a/ci/docker-compose-test.yml b/ci/docker-compose-test.yml index 3577e8fc5..3f6cf6447 100644 --- a/ci/docker-compose-test.yml +++ b/ci/docker-compose-test.yml @@ -45,11 +45,42 @@ services: - "8085" networks: - net + + neon-core-rpc: + restart: unless-stopped + container_name: neon-core-rpc + hostname: neon_core_rpc + entrypoint: /opt/neon-rpc /opt/libs/current + environment: + RUST_BACKTRACE: full + RUST_LOG: neon=debug + NEON_API_LISTENER_ADDR: 0.0.0.0:3100 + SOLANA_URL: http://solana:8899 + EVM_LOADER: 53DfF883gyixYNXnM7s5xhdeyV8mVk9T4i2hGV9vG9io + NEON_TOKEN_MINT: HPsV9Deocecw3GeZv1FkAPNCBRfuVyfw9MMwjwRe1xaU + NEON_CHAIN_ID: 111 + COMMITMENT: confirmed + NEON_DB_CLICKHOUSE_URLS: "http://45.250.253.36:8123;http://45.250.253.38:8123" + NEON_DB_INDEXER_HOST: 45.250.253.32 + NEON_DB_INDEXER_PORT: 5432 + NEON_DB_INDEXER_DATABASE: indexer + NEON_DB_INDEXER_USER: postgres + NEON_DB_INDEXER_PASSWORD: "vUlpDyAP0gA98R5Bu" + KEYPAIR: /opt/operator-keypairs/id.json + FEEPAIR: /opt/operator-keypairs/id.json + image: ${EVM_LOADER_IMAGE} + ports: + - "3100:3100" + expose: + - "3100" + networks: + - net tests: image: ${NEON_TESTS_IMAGE} environment: - SOLANA_URL=http://solana:8899 - NEON_CORE_API_URL=http://neon_api:8085/api + - NEON_CORE_API_RPC_URL=http://neon_core_rpc:3100 hostname: tests command: sleep infinity networks: diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 2a5f7849e..be490e785 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -12,6 +12,54 @@ dependencies = [ "regex", ] +[[package]] +name = "abi_stable" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69d6512d3eb05ffe5004c59c206de7f99c34951504056ce23fc953842f12c445" +dependencies = [ + "abi_stable_derive", + "abi_stable_shared", + "const_panic", + "core_extensions", + "crossbeam-channel", + "generational-arena", + "libloading", + "lock_api", + "parking_lot", + "paste", + "repr_offset", + "rustc_version", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "abi_stable_derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7178468b407a4ee10e881bc7a328a65e739f0863615cca4429d43916b05e898" +dependencies = [ + "abi_stable_shared", + "as_derive_utils", + "core_extensions", + "proc-macro2", + "quote", + "rustc_version", + "syn 1.0.109", + "typed-arena", +] + +[[package]] +name = "abi_stable_shared" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b5df7688c123e63f4d4d649cba63f2967ba7f7861b1664fca3f77d3dad2b63" +dependencies = [ + "core_extensions", +] + [[package]] name = "actix-codec" version = "0.5.1" @@ -466,6 +514,18 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +[[package]] +name = "as_derive_utils" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff3c96645900a44cf11941c111bd08a6573b0e2f9f69bc9264b179d8fae753c4" +dependencies = [ + "core_extensions", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "ascii" version = "0.9.3" @@ -542,6 +602,15 @@ dependencies = [ "tokio", ] +[[package]] +name = "async-ffi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ed5a937a789391ebc1c77d3a15b060e0d100e6d7c483a2af3f250d6b8dc2a23" +dependencies = [ + "abi_stable", +] + [[package]] name = "async-mutex" version = "1.4.0" @@ -618,6 +687,15 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "beef" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" +dependencies = [ + "serde", +] + [[package]] name = "bincode" version = "1.3.3" @@ -1251,6 +1329,12 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "const_panic" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6051f239ecec86fde3410901ab7860d458d160371533842974fc61f96d15879b" + [[package]] name = "constant_time_eq" version = "0.3.0" @@ -1290,6 +1374,21 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +[[package]] +name = "core_extensions" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92c71dc07c9721607e7a16108336048ee978c3a8b129294534272e8bac96c0ee" +dependencies = [ + "core_extensions_proc_macros", +] + +[[package]] +name = "core_extensions_proc_macros" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f3b219d28b6e3b4ac87bc1fc522e0803ab22e055da177bff0068c4150c61a6" + [[package]] name = "cpufeatures" version = "0.2.6" @@ -1812,6 +1911,15 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "erased-serde" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c138974f9d5e7fe373eb04df7cae98833802ae4b11c24ac7039a21d5af4b26c" +dependencies = [ + "serde", +] + [[package]] name = "errno" version = "0.3.8" @@ -1923,6 +2031,15 @@ dependencies = [ "toml 0.8.0", ] +[[package]] +name = "extensions" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "258f70bd2b060d448403a66d420e81dcac3e5247a4928a887404a5e03715e2e0" +dependencies = [ + "fxhash", +] + [[package]] name = "fastrand" version = "2.0.1" @@ -2124,6 +2241,24 @@ dependencies = [ "slab", ] +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "generational-arena" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877e94aff08e743b651baaea359664321055749b398adff8740a7399af7796e7" +dependencies = [ + "cfg-if", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -2463,7 +2598,9 @@ dependencies = [ "futures-util", "http", "hyper", + "log", "rustls", + "rustls-native-certs", "tokio", "tokio-rustls", ] @@ -2698,6 +2835,76 @@ dependencies = [ "serde_json", ] +[[package]] +name = "jsonrpc-v2" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "759affe8550a30591c68f5e85d1784f24dc65217d2cca765949857f844fcecb0" +dependencies = [ + "actix-service", + "actix-web", + "async-trait", + "bytes", + "erased-serde", + "extensions", + "futures", + "serde", + "serde_json", +] + +[[package]] +name = "jsonrpsee-core" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da2327ba8df2fdbd5e897e2b5ed25ce7f299d345b9736b6828814c3dbd1fd47b" +dependencies = [ + "anyhow", + "async-trait", + "beef", + "futures-util", + "hyper", + "jsonrpsee-types", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "jsonrpsee-http-client" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f80c17f62c7653ce767e3d7288b793dfec920f97067ceb189ebdd3570f2bc20" +dependencies = [ + "async-trait", + "hyper", + "hyper-rustls", + "jsonrpsee-core", + "jsonrpsee-types", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower", + "tracing", + "url", +] + +[[package]] +name = "jsonrpsee-types" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be0be325642e850ed0bdff426674d2e66b2b7117c9be23a7caef68a2902b7d9" +dependencies = [ + "anyhow", + "beef", + "serde", + "serde_json", + "thiserror", + "tracing", +] + [[package]] name = "keccak" version = "0.1.3" @@ -2737,6 +2944,16 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + [[package]] name = "libsecp256k1" version = "0.6.0" @@ -3112,20 +3329,25 @@ dependencies = [ name = "neon-lib" version = "1.11.0-dev" dependencies = [ + "abi_stable", "anyhow", + "async-ffi", "async-trait", "base64 0.21.4", "bincode", "bs58", "build-info", "build-info-build", + "clap 2.34.0", "clickhouse", "enum_dispatch", "ethnum", "evm-loader", "goblin 0.6.1", "hex", + "lazy_static", "log", + "neon-lib-interface", "rand 0.8.5", "scroll", "serde", @@ -3140,12 +3362,63 @@ dependencies = [ "solana-transaction-status", "spl-associated-token-account", "spl-token", + "strum 0.25.0", + "strum_macros 0.25.3", "thiserror", "tokio", "tracing", "web3", ] +[[package]] +name = "neon-lib-interface" +version = "0.1.0" +dependencies = [ + "abi_stable", + "async-ffi", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "neon-rpc" +version = "0.1.0" +dependencies = [ + "actix-web", + "build-info", + "build-info-build", + "clap 2.34.0", + "jsonrpc-v2", + "neon-lib", + "neon-lib-interface", + "semver", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-appender", + "tracing-subscriber", +] + +[[package]] +name = "neon-rpc-client" +version = "0.1.0" +dependencies = [ + "async-trait", + "build-info", + "jsonrpc-v2", + "jsonrpsee-core", + "jsonrpsee-http-client", + "jsonrpsee-types", + "neon-lib", + "serde", + "serde_json", + "thiserror", + "tokio", +] + [[package]] name = "nix" version = "0.26.4" @@ -4050,6 +4323,15 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +[[package]] +name = "repr_offset" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb1070755bd29dffc19d0971cab794e607839ba2ef4b69a9e6fbc8733c1b72ea" +dependencies = [ + "tstr", +] + [[package]] name = "reqwest" version = "0.11.20" @@ -4755,8 +5037,8 @@ dependencies = [ "solana-system-program", "solana-vote-program", "static_assertions", - "strum", - "strum_macros", + "strum 0.24.1", + "strum_macros 0.24.3", "tar", "tempfile", "thiserror", @@ -5571,8 +5853,8 @@ dependencies = [ "solana-zk-token-proof-program", "solana-zk-token-sdk", "static_assertions", - "strum", - "strum_macros", + "strum 0.24.1", + "strum_macros 0.24.3", "symlink", "tar", "tempfile", @@ -6175,9 +6457,15 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" dependencies = [ - "strum_macros", + "strum_macros 0.24.3", ] +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" + [[package]] name = "strum_macros" version = "0.24.3" @@ -6191,6 +6479,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.50", +] + [[package]] name = "subtle" version = "2.4.1" @@ -6647,7 +6948,9 @@ version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" dependencies = [ + "futures-core", "futures-util", + "pin-project", "pin-project-lite", "tokio", "tower-layer", @@ -6760,6 +7063,21 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +[[package]] +name = "tstr" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cca3264971090dec0feef3b455a3c178f02762f7550cf4592991ac64b3be2d7e" +dependencies = [ + "tstr_proc_macros", +] + +[[package]] +name = "tstr_proc_macros" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78122066b0cb818b8afd08f7ed22f7fdbc3e90815035726f0840d0d26c0747a" + [[package]] name = "tungstenite" version = "0.20.1" @@ -6781,6 +7099,12 @@ dependencies = [ "webpki-roots 0.24.0", ] +[[package]] +name = "typed-arena" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" + [[package]] name = "typenum" version = "1.16.0" diff --git a/evm_loader/Cargo.toml b/evm_loader/Cargo.toml index 5081e7429..c52ac9726 100644 --- a/evm_loader/Cargo.toml +++ b/evm_loader/Cargo.toml @@ -4,6 +4,9 @@ members = [ 'api', 'cli', 'lib', + 'lib-interface', + 'rpc', + 'rpc-client', 'program', - 'program-macro' + 'program-macro', ] diff --git a/evm_loader/api/src/api_server/mod.rs b/evm_loader/api/src/api_server/mod.rs index 53b4478d2..c3d449565 100644 --- a/evm_loader/api/src/api_server/mod.rs +++ b/evm_loader/api/src/api_server/mod.rs @@ -1,2 +1 @@ pub mod handlers; -pub mod state; diff --git a/evm_loader/api/src/main.rs b/evm_loader/api/src/main.rs index e52524e72..077e7cf7d 100644 --- a/evm_loader/api/src/main.rs +++ b/evm_loader/api/src/main.rs @@ -9,6 +9,7 @@ use actix_web::web; use actix_web::App; use actix_web::HttpServer; use api_server::handlers::NeonApiError; +use neon_lib::abi::state::State; pub use neon_lib::commands; pub use neon_lib::config; pub use neon_lib::errors; @@ -33,7 +34,7 @@ use tracing::info; use tracing_subscriber::EnvFilter; type NeonApiResult = Result; -type NeonApiState = Data; +type NeonApiState = Data; #[actix_web::main] async fn main() -> NeonApiResult<()> { @@ -51,8 +52,8 @@ async fn main() -> NeonApiResult<()> { info!("{}", get_build_info()); - let api_config = config::load_api_config_from_enviroment(); - let state: NeonApiState = Data::new(api_server::state::State::new(api_config)); + let api_config = config::load_api_config_from_environment(); + let state: NeonApiState = Data::new(State::new(api_config)); let listener_addr = options .value_of("host") diff --git a/evm_loader/lib-interface/.gitignore b/evm_loader/lib-interface/.gitignore new file mode 100644 index 000000000..2f7896d1d --- /dev/null +++ b/evm_loader/lib-interface/.gitignore @@ -0,0 +1 @@ +target/ diff --git a/evm_loader/lib-interface/Cargo.lock b/evm_loader/lib-interface/Cargo.lock new file mode 100644 index 000000000..7c3935937 --- /dev/null +++ b/evm_loader/lib-interface/Cargo.lock @@ -0,0 +1,474 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "abi_stable" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f69d9465d88d24382d43fa68335a92fe9d3c53a918549c693403ed9a85eff50" +dependencies = [ + "abi_stable_derive", + "abi_stable_shared", + "const_panic", + "core_extensions", + "crossbeam-channel", + "generational-arena", + "libloading", + "lock_api", + "parking_lot", + "paste", + "repr_offset", + "rustc_version", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "abi_stable_derive" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aecd3efa5a5294f5c67913d45f985ccb382b3c93327581529610eeecdf4821a" +dependencies = [ + "abi_stable_shared", + "as_derive_utils", + "core_extensions", + "proc-macro2", + "quote", + "rustc_version", + "syn 1.0.109", + "typed-arena", +] + +[[package]] +name = "abi_stable_shared" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b5df7688c123e63f4d4d649cba63f2967ba7f7861b1664fca3f77d3dad2b63" +dependencies = [ + "core_extensions", +] + +[[package]] +name = "as_derive_utils" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff3c96645900a44cf11941c111bd08a6573b0e2f9f69bc9264b179d8fae753c4" +dependencies = [ + "core_extensions", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "async-ffi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ed5a937a789391ebc1c77d3a15b060e0d100e6d7c483a2af3f250d6b8dc2a23" +dependencies = [ + "abi_stable", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "const_panic" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6051f239ecec86fde3410901ab7860d458d160371533842974fc61f96d15879b" + +[[package]] +name = "core_extensions" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92c71dc07c9721607e7a16108336048ee978c3a8b129294534272e8bac96c0ee" +dependencies = [ + "core_extensions_proc_macros", +] + +[[package]] +name = "core_extensions_proc_macros" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f3b219d28b6e3b4ac87bc1fc522e0803ab22e055da177bff0068c4150c61a6" + +[[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "generational-arena" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d3b771574f62d0548cee0ad9057857e9fc25d7a3335f140c84f6acd0bf601" +dependencies = [ + "cfg-if 0.1.10", +] + +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + +[[package]] +name = "libc" +version = "0.2.144" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if 1.0.0", + "winapi", +] + +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "neon-interface" +version = "0.1.0" +dependencies = [ + "abi_stable", + "async-ffi", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + +[[package]] +name = "paste" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" + +[[package]] +name = "proc-macro2" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa1fb82fc0c281dd9671101b66b771ebbe1eaf967b96ac8740dcba4b70005ca8" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "repr_offset" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb1070755bd29dffc19d0971cab794e607839ba2ef4b69a9e6fbc8733c1b72ea" +dependencies = [ + "tstr", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "ryu" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "semver" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" + +[[package]] +name = "serde" +version = "1.0.163" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.163" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.16", +] + +[[package]] +name = "serde_json" +version = "1.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.16", +] + +[[package]] +name = "tstr" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cca3264971090dec0feef3b455a3c178f02762f7550cf4592991ac64b3be2d7e" +dependencies = [ + "tstr_proc_macros", +] + +[[package]] +name = "tstr_proc_macros" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78122066b0cb818b8afd08f7ed22f7fdbc3e90815035726f0840d0d26c0747a" + +[[package]] +name = "typed-arena" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" diff --git a/evm_loader/lib-interface/Cargo.toml b/evm_loader/lib-interface/Cargo.toml new file mode 100644 index 000000000..1a1283d88 --- /dev/null +++ b/evm_loader/lib-interface/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "neon-lib-interface" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +abi_stable = "0.11.1" +thiserror = "1" +async-ffi = { version = "0.4.1", features = ["abi_stable"] } +serde = "1.0.147" +serde_json = "1.0.85" diff --git a/evm_loader/lib-interface/src/lib.rs b/evm_loader/lib-interface/src/lib.rs new file mode 100644 index 000000000..fab07f3f7 --- /dev/null +++ b/evm_loader/lib-interface/src/lib.rs @@ -0,0 +1,59 @@ +#![allow(non_camel_case_types)] + +pub mod types; + +use crate::types::RNeonEVMLibResult; +use std::{collections::HashMap, path::Path}; +use thiserror::Error; + +use abi_stable::{ + library::{LibraryError, RootModule}, + package_version_strings, + std_types::{RStr, RString}, + StableAbi, +}; + +#[repr(C)] +#[derive(StableAbi)] +#[sabi(kind(Prefix(prefix_ref = NeonEVMLib_Ref)))] +#[sabi(missing_field(panic))] +pub struct NeonEVMLib { + pub hash: extern "C" fn() -> RString, + pub get_version: extern "C" fn() -> RString, + pub get_build_info: extern "C" fn() -> RString, + + pub invoke: for<'a> extern "C" fn(RStr<'a>, RStr<'a>) -> RNeonEVMLibResult<'a>, +} + +impl RootModule for NeonEVMLib_Ref { + abi_stable::declare_root_module_statics! {NeonEVMLib_Ref} + + const BASE_NAME: &'static str = "neon-lib-interface"; + const NAME: &'static str = "neon-lib-interface"; + const VERSION_STRINGS: abi_stable::sabi_types::VersionStrings = package_version_strings!(); +} + +#[derive(Error, Debug)] +pub enum NeonEVMLibLoadError { + #[error("abi_stable library error")] + LibraryError(#[from] LibraryError), + #[error("IO error")] + IoError(#[from] std::io::Error), +} + +pub fn load_libraries

( + directory: P, +) -> Result, NeonEVMLibLoadError> +where + P: AsRef, +{ + let paths = std::fs::read_dir(directory)?; + let mut result = HashMap::new(); + for path in paths { + let lib = NeonEVMLib_Ref::load_from_file(&path?.path())?; + let hash = lib.hash()(); + + result.insert(hash.into_string(), lib); + } + Ok(result) +} diff --git a/evm_loader/lib-interface/src/types.rs b/evm_loader/lib-interface/src/types.rs new file mode 100644 index 000000000..c6f8f22fe --- /dev/null +++ b/evm_loader/lib-interface/src/types.rs @@ -0,0 +1,12 @@ +use abi_stable::std_types::{RResult, RString}; +use async_ffi::LocalBorrowingFfiFuture; +use serde::{Deserialize, Serialize}; + +pub type RNeonEVMLibResult<'a> = LocalBorrowingFfiFuture<'a, RResult>; + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct NeonEVMLibError { + pub code: u32, + pub message: String, + pub data: Option, +} diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 0b81f1d26..120025f4d 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -37,6 +37,16 @@ async-trait = "0.1.73" build-info = { version = "0.0.31", features = ["serde"] } enum_dispatch = "0.3.12" web3 = "0.19.0" +neon-lib-interface = { path = "../lib-interface" } +abi_stable = "0.11.2" +async-ffi = { version = "0.4.1", features = ["abi_stable"] } +strum = "0.25.0" +strum_macros = "0.25.3" +clap = "2.33.3" +lazy_static = "1.4.0" [build-dependencies] build-info-build = "0.0.31" + +[lib] +crate-type = ["cdylib", "lib"] diff --git a/evm_loader/lib/src/abi/emulate.rs b/evm_loader/lib/src/abi/emulate.rs new file mode 100644 index 000000000..0937068c2 --- /dev/null +++ b/evm_loader/lib/src/abi/emulate.rs @@ -0,0 +1,20 @@ +use super::params_to_neon_error; +use crate::commands::emulate::{self, EmulateResponse}; +use crate::commands::get_config::BuildConfigSimulator; +use crate::config::APIOptions; +use crate::rpc::Rpc; +use crate::tracing::tracers::TracerTypeEnum; +use crate::{types::EmulateApiRequest, NeonResult}; + +pub async fn execute( + rpc: &(impl Rpc + BuildConfigSimulator), + config: &APIOptions, + params: &str, +) -> NeonResult { + let params: EmulateApiRequest = + serde_json::from_str(params).map_err(|_| params_to_neon_error(params))?; + + emulate::execute(rpc, config.evm_loader, params.body, None::) + .await + .map(|(response, _)| response) +} diff --git a/evm_loader/lib/src/abi/get_balance.rs b/evm_loader/lib/src/abi/get_balance.rs new file mode 100644 index 000000000..5258a1c6b --- /dev/null +++ b/evm_loader/lib/src/abi/get_balance.rs @@ -0,0 +1,17 @@ +use super::params_to_neon_error; +use crate::commands::get_balance::{self, GetBalanceResponse}; +use crate::commands::get_config::BuildConfigSimulator; +use crate::config::APIOptions; +use crate::rpc::Rpc; +use crate::{types::GetBalanceRequest, NeonResult}; + +pub async fn execute( + rpc: &(impl Rpc + BuildConfigSimulator), + config: &APIOptions, + params: &str, +) -> NeonResult> { + let params: GetBalanceRequest = + serde_json::from_str(params).map_err(|_| params_to_neon_error(params))?; + + get_balance::execute(rpc, &config.evm_loader, ¶ms.account).await +} diff --git a/evm_loader/lib/src/abi/get_config.rs b/evm_loader/lib/src/abi/get_config.rs new file mode 100644 index 000000000..5ea8714e3 --- /dev/null +++ b/evm_loader/lib/src/abi/get_config.rs @@ -0,0 +1,12 @@ +use crate::commands::get_config::{self, BuildConfigSimulator, GetConfigResponse}; +use crate::config::APIOptions; +use crate::rpc::Rpc; +use crate::NeonResult; + +pub async fn execute( + rpc: &(impl Rpc + BuildConfigSimulator), + config: &APIOptions, + _params: &str, +) -> NeonResult { + get_config::execute(rpc, config.evm_loader).await +} diff --git a/evm_loader/lib/src/abi/get_contract.rs b/evm_loader/lib/src/abi/get_contract.rs new file mode 100644 index 000000000..dc5367596 --- /dev/null +++ b/evm_loader/lib/src/abi/get_contract.rs @@ -0,0 +1,17 @@ +use super::params_to_neon_error; +use crate::commands::get_config::BuildConfigSimulator; +use crate::commands::get_contract::{self, GetContractResponse}; +use crate::config::APIOptions; +use crate::rpc::Rpc; +use crate::{types::GetContractRequest, NeonResult}; + +pub async fn execute( + rpc: &(impl Rpc + BuildConfigSimulator), + config: &APIOptions, + params: &str, +) -> NeonResult> { + let params: GetContractRequest = + serde_json::from_str(params).map_err(|_| params_to_neon_error(params))?; + + get_contract::execute(rpc, &config.evm_loader, ¶ms.contract).await +} diff --git a/evm_loader/lib/src/abi/get_holder.rs b/evm_loader/lib/src/abi/get_holder.rs new file mode 100644 index 000000000..36a47f27b --- /dev/null +++ b/evm_loader/lib/src/abi/get_holder.rs @@ -0,0 +1,17 @@ +use super::params_to_neon_error; +use crate::commands::get_config::BuildConfigSimulator; +use crate::commands::get_holder::{self, GetHolderResponse}; +use crate::config::APIOptions; +use crate::rpc::Rpc; +use crate::{types::GetHolderRequest, NeonResult}; + +pub async fn execute( + rpc: &(impl Rpc + BuildConfigSimulator), + config: &APIOptions, + params: &str, +) -> NeonResult { + let params: GetHolderRequest = + serde_json::from_str(params).map_err(|_| params_to_neon_error(params))?; + + get_holder::execute(rpc, &config.evm_loader, params.pubkey).await +} diff --git a/evm_loader/lib/src/abi/get_storage_at.rs b/evm_loader/lib/src/abi/get_storage_at.rs new file mode 100644 index 000000000..2a0bf51f1 --- /dev/null +++ b/evm_loader/lib/src/abi/get_storage_at.rs @@ -0,0 +1,17 @@ +use super::params_to_neon_error; +use crate::commands::get_config::BuildConfigSimulator; +use crate::commands::get_storage_at::{self, GetStorageAtReturn}; +use crate::config::APIOptions; +use crate::rpc::Rpc; +use crate::{types::GetStorageAtRequest, NeonResult}; + +pub async fn execute( + rpc: &(impl Rpc + BuildConfigSimulator), + config: &APIOptions, + params: &str, +) -> NeonResult { + let params: GetStorageAtRequest = + serde_json::from_str(params).map_err(|_| params_to_neon_error(params))?; + + get_storage_at::execute(rpc, &config.evm_loader, params.contract, params.index).await +} diff --git a/evm_loader/lib/src/abi/mod.rs b/evm_loader/lib/src/abi/mod.rs new file mode 100644 index 000000000..2e8e40e15 --- /dev/null +++ b/evm_loader/lib/src/abi/mod.rs @@ -0,0 +1,137 @@ +mod emulate; +mod get_balance; +mod get_config; +mod get_contract; +mod get_holder; +mod get_storage_at; +pub mod state; +mod trace; + +use crate::{ + abi::state::State, + config::{self, APIOptions}, + types::RequestWithSlot, + LibMethod, NeonError, +}; +use abi_stable::{ + prefix_type::WithMetadata, + sabi_extern_fn, + std_types::{RStr, RString}, +}; +use async_ffi::FutureExt; +use lazy_static::lazy_static; +use neon_lib_interface::{ + types::{NeonEVMLibError, RNeonEVMLibResult}, + NeonEVMLib, +}; +use serde_json::json; + +lazy_static! { + static ref RUNTIME: tokio::runtime::Runtime = tokio::runtime::Runtime::new().unwrap(); + static ref STATE: State = State::new(load_config().unwrap()); +} + +pub const _MODULE_WM_: &WithMetadata = &WithMetadata::new(NeonEVMLib { + hash, + get_version, + get_build_info, + invoke, +}); + +#[sabi_extern_fn] +fn hash() -> RString { + env!("NEON_REVISION").into() +} + +#[sabi_extern_fn] +fn get_version() -> RString { + env!("CARGO_PKG_VERSION").into() +} + +#[sabi_extern_fn] +fn get_build_info() -> RString { + json!(crate::build_info::get_build_info()) + .to_string() + .into() +} + +#[sabi_extern_fn] +fn invoke<'a>(method: RStr<'a>, params: RStr<'a>) -> RNeonEVMLibResult<'a> { + async move { + // Needed for tokio::task::spawn_blocking using thread local storage inside dynamic library + // since dynamic library and executable have different thread local storage namespaces + let _guard = RUNTIME.enter(); + + dispatch(method.as_str(), params.as_str()) + .await + .map(RString::from) + .map_err(neon_error_to_rstring) + .into() + } + .into_local_ffi() +} + +fn load_config() -> Result { + Ok(config::load_api_config_from_environment()) +} + +async fn dispatch(method_str: &str, params_str: &str) -> Result { + let method: LibMethod = method_str.parse()?; + let RequestWithSlot { + slot, + tx_index_in_block, + } = match params_str { + "" => RequestWithSlot { + slot: None, + tx_index_in_block: None, + }, + _ => serde_json::from_str(params_str).map_err(|_| params_to_neon_error(params_str))?, + }; + let state = &STATE; + let config = &state.config; + let rpc = state.build_rpc(slot, tx_index_in_block).await?; + + match method { + LibMethod::Emulate => emulate::execute(&rpc, config, params_str) + .await + .map(|v| serde_json::to_string(&v).unwrap()), + LibMethod::GetStorageAt => get_storage_at::execute(&rpc, config, params_str) + .await + .map(|v| serde_json::to_string(&v).unwrap()), + LibMethod::GetBalance => get_balance::execute(&rpc, config, params_str) + .await + .map(|v| serde_json::to_string(&v).unwrap()), + LibMethod::GetConfig => get_config::execute(&rpc, config, params_str) + .await + .map(|v| serde_json::to_string(&v).unwrap()), + LibMethod::GetContract => get_contract::execute(&rpc, config, params_str) + .await + .map(|v| serde_json::to_string(&v).unwrap()), + LibMethod::GetHolder => get_holder::execute(&rpc, config, params_str) + .await + .map(|v| serde_json::to_string(&v).unwrap()), + LibMethod::Trace => trace::execute(&rpc, config, params_str) + .await + .map(|v| serde_json::to_string(&v).unwrap()), + // _ => Err(NeonError::IncorrectLibMethod), + } +} + +fn params_to_neon_error(params: &str) -> NeonError { + NeonError::EnvironmentError( + crate::commands::init_environment::EnvironmentError::InvalidProgramParameter(params.into()), + ) +} + +fn neon_error_to_neon_lib_error(error: NeonError) -> NeonEVMLibError { + assert!(error.error_code() >= 0); + NeonEVMLibError { + code: error.error_code() as u32, + message: error.to_string(), + data: None, + } +} + +fn neon_error_to_rstring(error: NeonError) -> RString { + RString::from(serde_json::to_string(&neon_error_to_neon_lib_error(error)).unwrap()) +} diff --git a/evm_loader/api/src/api_server/state.rs b/evm_loader/lib/src/abi/state.rs similarity index 83% rename from evm_loader/api/src/api_server/state.rs rename to evm_loader/lib/src/abi/state.rs index 3a9ae8523..bad3cb07d 100644 --- a/evm_loader/api/src/api_server/state.rs +++ b/evm_loader/lib/src/abi/state.rs @@ -1,7 +1,7 @@ -use neon_lib::config::APIOptions; -use neon_lib::rpc::{CallDbClient, CloneRpcClient, RpcEnum}; -use neon_lib::types::TracerDb; -use neon_lib::NeonError; +use crate::config::APIOptions; +use crate::rpc::{CallDbClient, CloneRpcClient, RpcEnum}; +use crate::types::TracerDb; +use crate::NeonError; pub struct State { pub tracer_db: TracerDb, diff --git a/evm_loader/lib/src/abi/trace.rs b/evm_loader/lib/src/abi/trace.rs new file mode 100644 index 000000000..491bf284f --- /dev/null +++ b/evm_loader/lib/src/abi/trace.rs @@ -0,0 +1,19 @@ +use serde_json::Value; + +use super::params_to_neon_error; +use crate::commands::get_config::BuildConfigSimulator; +use crate::commands::trace::{self}; +use crate::config::APIOptions; +use crate::rpc::Rpc; +use crate::{types::EmulateApiRequest, NeonResult}; + +pub async fn execute( + rpc: &(impl Rpc + BuildConfigSimulator), + config: &APIOptions, + params: &str, +) -> NeonResult { + let params: EmulateApiRequest = + serde_json::from_str(params).map_err(|_| params_to_neon_error(params))?; + + trace::trace_transaction(rpc, config.evm_loader, params.body).await +} diff --git a/evm_loader/lib/src/commands/get_config.rs b/evm_loader/lib/src/commands/get_config.rs index a2e87ee6d..019713936 100644 --- a/evm_loader/lib/src/commands/get_config.rs +++ b/evm_loader/lib/src/commands/get_config.rs @@ -24,7 +24,7 @@ use serde_with::{serde_as, DisplayFromStr}; use solana_client::rpc_config::RpcSimulateTransactionConfig; use tokio::sync::{Mutex, MutexGuard, OnceCell}; -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub enum Status { Ok, Emergency, @@ -41,7 +41,7 @@ pub struct ChainInfo { } #[serde_as] -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct GetConfigResponse { pub version: String, pub revision: String, diff --git a/evm_loader/lib/src/commands/get_holder.rs b/evm_loader/lib/src/commands/get_holder.rs index c58adb69f..fd7ae2d28 100644 --- a/evm_loader/lib/src/commands/get_holder.rs +++ b/evm_loader/lib/src/commands/get_holder.rs @@ -5,7 +5,7 @@ use evm_loader::account::{ }, Holder, StateAccount, StateFinalizedAccount, TAG_HOLDER, TAG_STATE, TAG_STATE_FINALIZED, }; -use serde::Serialize; +use serde::{Deserialize, Serialize}; use solana_sdk::{account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey}; use std::fmt::Display; @@ -13,7 +13,7 @@ use crate::{account_storage::account_info, rpc::Rpc, NeonResult}; use serde_with::{hex::Hex, serde_as, skip_serializing_none, DisplayFromStr}; -#[derive(Debug, Default, Serialize)] +#[derive(Debug, Default, Serialize, Deserialize)] pub enum Status { #[default] Empty, @@ -23,9 +23,17 @@ pub enum Status { Finalized, } +#[serde_as] +#[derive(Debug, Default, Serialize, Deserialize)] +pub struct AccountMeta { + pub is_writable: bool, + #[serde_as(as = "DisplayFromStr")] + pub key: Pubkey, +} + #[serde_as] #[skip_serializing_none] -#[derive(Debug, Default, Serialize)] +#[derive(Debug, Default, Serialize, Deserialize)] pub struct GetHolderResponse { pub status: Status, pub len: Option, diff --git a/evm_loader/lib/src/config.rs b/evm_loader/lib/src/config.rs index 499262899..7706bf814 100644 --- a/evm_loader/lib/src/config.rs +++ b/evm_loader/lib/src/config.rs @@ -28,7 +28,7 @@ pub struct APIOptions { /// # Errors #[must_use] -pub fn load_api_config_from_enviroment() -> APIOptions { +pub fn load_api_config_from_environment() -> APIOptions { let solana_cli_config_path: Option = env::var("SOLANA_CLI_CONFIG_PATH").map(Some).unwrap_or(None); @@ -50,7 +50,7 @@ pub fn load_api_config_from_enviroment() -> APIOptions { .and_then(|v| Pubkey::from_str(&v).ok()) .expect("SOLANA_KEY_FOR_CONFIG variable must be a valid pubkey"); - let db_config = load_db_config_from_enviroment(); + let db_config = load_db_config_from_environment(); APIOptions { solana_cli_config_path, @@ -63,7 +63,7 @@ pub fn load_api_config_from_enviroment() -> APIOptions { } /// # Errors -fn load_db_config_from_enviroment() -> ChDbConfig { +fn load_db_config_from_environment() -> ChDbConfig { let clickhouse_url = env::var("NEON_DB_CLICKHOUSE_URLS") .map(|urls| { urls.split(';') diff --git a/evm_loader/lib/src/errors.rs b/evm_loader/lib/src/errors.rs index a7cf3e0be..e6ab476c5 100644 --- a/evm_loader/lib/src/errors.rs +++ b/evm_loader/lib/src/errors.rs @@ -6,6 +6,7 @@ use std::net::AddrParseError; use std::string::FromUtf8Error; use log::error; +use neon_lib_interface::NeonEVMLibLoadError; use solana_cli::cli::CliError as SolanaCliError; use solana_client::client_error::ClientError as SolanaClientError; use solana_client::tpu_client::TpuSenderError as SolanaTpuSenderError; @@ -45,6 +46,8 @@ pub enum NeonError { /// EVM Loader Error #[error("EVM Error. {0}")] EvmError(#[from] evm_loader::error::Error), + #[error("Can't load db config")] + LoadingDBConfigError, /// Need specify evm_loader #[error("EVM loader must be specified.")] EvmLoaderNotSpecified, @@ -114,6 +117,12 @@ pub enum NeonError { TryFromSliceError(#[from] TryFromSliceError), #[error("Solana pubkey for config must be specified.")] SolanaKeyForConfigNotSpecified, + #[error("library interface error")] + NeonEVMLibLoadError(#[from] NeonEVMLibLoadError), + #[error("Incorrect lib method")] + IncorrectLibMethod, + #[error("strum parse error {0:?}")] + StrumParseError(#[from] strum::ParseError), } impl NeonError { @@ -156,6 +165,10 @@ impl NeonError { NeonError::FromUtf8Error(_) => 258, NeonError::TryFromSliceError(_) => 259, NeonError::SolanaKeyForConfigNotSpecified => 260, + NeonError::NeonEVMLibLoadError(_) => 261, + NeonError::LoadingDBConfigError => 262, + NeonError::IncorrectLibMethod => 263, + NeonError::StrumParseError(_) => 264, } } } diff --git a/evm_loader/lib/src/lib.rs b/evm_loader/lib/src/lib.rs index d50c2f17b..57d634521 100644 --- a/evm_loader/lib/src/lib.rs +++ b/evm_loader/lib/src/lib.rs @@ -1,3 +1,4 @@ +pub mod abi; pub mod account_storage; pub mod build_info; pub mod build_info_common; @@ -9,7 +10,37 @@ pub mod rpc; pub mod tracing; pub mod types; +use abi::_MODULE_WM_; +use abi_stable::export_root_module; pub use config::Config; pub use errors::NeonError; +use neon_lib_interface::NeonEVMLib_Ref; pub type NeonResult = Result; + +const MODULE: NeonEVMLib_Ref = NeonEVMLib_Ref(_MODULE_WM_.static_as_prefix()); + +#[export_root_module] +pub fn get_root_module() -> NeonEVMLib_Ref { + MODULE +} + +use strum_macros::{AsRefStr, Display, EnumString, IntoStaticStr}; + +#[derive(Debug, Clone, Copy, PartialEq, Display, EnumString, IntoStaticStr, AsRefStr)] +pub enum LibMethod { + #[strum(serialize = "emulate")] + Emulate, + #[strum(serialize = "get_storage_at")] + GetStorageAt, + #[strum(serialize = "config")] + GetConfig, + #[strum(serialize = "balance")] + GetBalance, + #[strum(serialize = "contract")] + GetContract, + #[strum(serialize = "holder")] + GetHolder, + #[strum(serialize = "trace")] + Trace, +} diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index cf4138198..904ed772f 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -174,6 +174,30 @@ pub struct GetStorageAtRequest { pub slot: Option, } +#[derive(Deserialize, Serialize, Debug, Default)] +pub struct CancelTrxRequest { + pub storage_account: Pubkey, +} + +#[derive(Deserialize, Serialize, Debug, Default)] +pub struct RequestWithSlot { + pub slot: Option, + pub tx_index_in_block: Option, +} + +#[derive(Deserialize, Serialize, Debug, Default)] +pub struct GetNeonElfRequest { + pub program_location: Option, +} + +#[derive(Deserialize, Serialize, Debug, Default)] +pub struct InitEnvironmentRequest { + pub send_trx: bool, + pub force: bool, + pub keys_dir: Option, + pub file: Option, +} + #[serde_as] #[derive(Deserialize, Serialize, Debug, Default)] pub struct GetHolderRequest { diff --git a/evm_loader/rpc-client/Cargo.toml b/evm_loader/rpc-client/Cargo.toml new file mode 100644 index 000000000..826081a55 --- /dev/null +++ b/evm_loader/rpc-client/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "neon-rpc-client" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +serde = "1.0.189" +serde_json = "1.0.107" +jsonrpc-v2 = "0.13.0" +neon-lib = { path = "../lib" } +thiserror = "1.0.49" +async-trait = "0.1.74" +jsonrpsee-core = "0.20.2" +jsonrpsee-http-client = "0.20.2" +jsonrpsee-types = "0.20.2" +tokio = { version = "1", features = ["full"] } +build-info = { version = "0.0.31", features = ["serde"] } diff --git a/evm_loader/rpc-client/src/config.rs b/evm_loader/rpc-client/src/config.rs new file mode 100644 index 000000000..41a62c1fe --- /dev/null +++ b/evm_loader/rpc-client/src/config.rs @@ -0,0 +1,9 @@ +pub struct NeonRpcClientConfig { + pub url: String, +} + +impl NeonRpcClientConfig { + pub fn new(url: impl Into) -> NeonRpcClientConfig { + NeonRpcClientConfig { url: url.into() } + } +} diff --git a/evm_loader/rpc-client/src/error.rs b/evm_loader/rpc-client/src/error.rs new file mode 100644 index 000000000..2f6564fe3 --- /dev/null +++ b/evm_loader/rpc-client/src/error.rs @@ -0,0 +1,9 @@ +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum NeonRpcClientError { + #[error("Jsonrpc error. {0:?}")] + JsonrpseeError(#[from] jsonrpsee_core::Error), + #[error("serde json error. {0:?}")] + SerdeJsonError(#[from] serde_json::Error), +} diff --git a/evm_loader/rpc-client/src/http.rs b/evm_loader/rpc-client/src/http.rs new file mode 100644 index 000000000..9312d20c7 --- /dev/null +++ b/evm_loader/rpc-client/src/http.rs @@ -0,0 +1,110 @@ +use async_trait::async_trait; +use jsonrpsee_core::{client::ClientT, rpc_params}; +use jsonrpsee_http_client::{HttpClient, HttpClientBuilder}; +use neon_lib::LibMethod; +use neon_lib::{ + commands::{ + emulate::EmulateResponse, get_balance::GetBalanceResponse, get_config::GetConfigResponse, + get_contract::GetContractResponse, get_holder::GetHolderResponse, + get_storage_at::GetStorageAtReturn, + }, + types::{ + EmulateApiRequest, GetBalanceRequest, GetContractRequest, GetHolderRequest, + GetStorageAtRequest, + }, +}; +use serde::de::DeserializeOwned; +use serde::Serialize; + +use crate::{config::NeonRpcClientConfig, NeonRpcClient, NeonRpcClientResult}; + +pub struct NeonRpcHttpClient { + client: HttpClient, +} + +impl NeonRpcHttpClient { + pub async fn new(config: NeonRpcClientConfig) -> NeonRpcClientResult { + Ok(NeonRpcHttpClient { + client: HttpClientBuilder::default().build(config.url)?, + }) + } +} + +pub struct NeonRpcHttpClientBuilder {} + +impl NeonRpcHttpClientBuilder { + pub fn new() -> NeonRpcHttpClientBuilder { + NeonRpcHttpClientBuilder {} + } + + pub async fn build(&self, url: impl Into) -> NeonRpcClientResult { + let config = NeonRpcClientConfig::new(url); + NeonRpcHttpClient::new(config).await + } +} + +impl Default for NeonRpcHttpClientBuilder { + fn default() -> Self { + Self::new() + } +} + +#[async_trait(?Send)] +impl NeonRpcClient for NeonRpcHttpClient { + async fn emulate(&self, params: EmulateApiRequest) -> NeonRpcClientResult { + self.request(LibMethod::Emulate, params).await + } + + async fn balance( + &self, + params: GetBalanceRequest, + ) -> NeonRpcClientResult> { + self.request(LibMethod::GetBalance, params).await + } + + async fn get_contract( + &self, + params: GetContractRequest, + ) -> NeonRpcClientResult> { + self.request(LibMethod::GetContract, params).await + } + + async fn get_config(&self) -> NeonRpcClientResult { + self.request_without_params(LibMethod::GetConfig).await + } + + async fn get_holder(&self, params: GetHolderRequest) -> NeonRpcClientResult { + self.request(LibMethod::GetHolder, params).await + } + + async fn get_storage_at( + &self, + params: GetStorageAtRequest, + ) -> NeonRpcClientResult { + self.request(LibMethod::GetStorageAt, params).await + } + + async fn trace(&self, params: EmulateApiRequest) -> NeonRpcClientResult { + self.request(LibMethod::Trace, params).await + } +} + +impl NeonRpcHttpClient { + async fn request(&self, method: LibMethod, params: P) -> NeonRpcClientResult + where + P: Serialize, + R: DeserializeOwned, + { + Ok(self + .client + .request(method.into(), rpc_params![params]) + .await?) + } + + async fn request_without_params(&self, method: LibMethod) -> NeonRpcClientResult + where + R: DeserializeOwned, + { + Ok(self.client.request(method.into(), rpc_params![]).await?) + } +} diff --git a/evm_loader/rpc-client/src/lib.rs b/evm_loader/rpc-client/src/lib.rs new file mode 100644 index 000000000..609805d17 --- /dev/null +++ b/evm_loader/rpc-client/src/lib.rs @@ -0,0 +1,40 @@ +mod config; +mod error; +pub mod http; + +pub use error::NeonRpcClientError; + +use async_trait::async_trait; +use neon_lib::{ + commands::{ + emulate::EmulateResponse, get_balance::GetBalanceResponse, get_config::GetConfigResponse, + get_contract::GetContractResponse, get_holder::GetHolderResponse, + get_storage_at::GetStorageAtReturn, + }, + types::{ + EmulateApiRequest, GetBalanceRequest, GetContractRequest, GetHolderRequest, + GetStorageAtRequest, + }, +}; + +type NeonRpcClientResult = Result; + +#[async_trait(?Send)] +pub trait NeonRpcClient { + async fn emulate(&self, params: EmulateApiRequest) -> NeonRpcClientResult; + async fn balance( + &self, + params: GetBalanceRequest, + ) -> NeonRpcClientResult>; + async fn get_contract( + &self, + params: GetContractRequest, + ) -> NeonRpcClientResult>; + async fn get_holder(&self, params: GetHolderRequest) -> NeonRpcClientResult; + async fn get_config(&self) -> NeonRpcClientResult; + async fn get_storage_at( + &self, + params: GetStorageAtRequest, + ) -> NeonRpcClientResult; + async fn trace(&self, params: EmulateApiRequest) -> NeonRpcClientResult; +} diff --git a/evm_loader/rpc/.gitignore b/evm_loader/rpc/.gitignore new file mode 100644 index 000000000..e82451797 --- /dev/null +++ b/evm_loader/rpc/.gitignore @@ -0,0 +1,3 @@ +libs +d +keys \ No newline at end of file diff --git a/evm_loader/rpc/Cargo.toml b/evm_loader/rpc/Cargo.toml new file mode 100644 index 000000000..ea03ce5dc --- /dev/null +++ b/evm_loader/rpc/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "neon-rpc" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +actix-web = "4.3.1" +clap = "2.33.3" +jsonrpc-v2 = "0.13.0" +neon-lib-interface = { path = "../lib-interface" } +neon-lib = { path = "../lib" } +semver = "1.0.18" +serde = "1.0.188" +serde_json = "1.0.107" +tokio = { version = "1", features = ["full"] } +build-info = { version = "0.0.31", features = ["serde"] } +thiserror = "1.0" +tracing = "0.1" +tracing-subscriber = { version = "0.3", features = ["env-filter"] } +tracing-appender = "0.2.2" + +[build-dependencies] +build-info-build = "0.0.31" diff --git a/evm_loader/rpc/build.rs b/evm_loader/rpc/build.rs new file mode 100644 index 000000000..d36778f60 --- /dev/null +++ b/evm_loader/rpc/build.rs @@ -0,0 +1,3 @@ +fn main() { + build_info_build::build_script(); +} diff --git a/evm_loader/rpc/src/build_info.rs b/evm_loader/rpc/src/build_info.rs new file mode 100644 index 000000000..85f42da0d --- /dev/null +++ b/evm_loader/rpc/src/build_info.rs @@ -0,0 +1,7 @@ +use neon_lib::build_info_common::SlimBuildInfo; + +build_info::build_info!(fn build_info); + +pub fn get_build_info() -> SlimBuildInfo { + build_info().into() +} diff --git a/evm_loader/rpc/src/context.rs b/evm_loader/rpc/src/context.rs new file mode 100644 index 000000000..614b629a5 --- /dev/null +++ b/evm_loader/rpc/src/context.rs @@ -0,0 +1,6 @@ +use neon_lib_interface::NeonEVMLib_Ref; +use std::collections::HashMap; + +pub struct Context { + pub libraries: HashMap, +} diff --git a/evm_loader/rpc/src/error.rs b/evm_loader/rpc/src/error.rs new file mode 100644 index 000000000..bc7f2818f --- /dev/null +++ b/evm_loader/rpc/src/error.rs @@ -0,0 +1,27 @@ +use neon_lib::errors::NeonError; +use neon_lib_interface::NeonEVMLibLoadError; +use std::net::AddrParseError; + +use thiserror::Error; + +#[allow(clippy::enum_variant_names)] +#[derive(Debug, Error)] +pub enum NeonRPCError { + /// Std IO Error + #[error("Std I/O error. {0:?}")] + StdIoError(#[from] std::io::Error), + #[error("Addr parse error. {0:?}")] + AddrParseError(#[from] AddrParseError), + #[error("Neon error. {0:?}")] + NeonError(#[from] NeonError), + #[error("Neon lib error. {0:?}")] + NeonEVMLibLoadError(#[from] NeonEVMLibLoadError), + #[error("Neon RPC: Incorrect parameters.")] + IncorrectParameters(), +} + +impl From for jsonrpc_v2::Error { + fn from(value: NeonRPCError) -> Self { + jsonrpc_v2::Error::internal(value) + } +} diff --git a/evm_loader/rpc/src/handlers/emulate.rs b/evm_loader/rpc/src/handlers/emulate.rs new file mode 100644 index 000000000..9e068282c --- /dev/null +++ b/evm_loader/rpc/src/handlers/emulate.rs @@ -0,0 +1,17 @@ +use super::invoke; +use crate::{context::Context, error::NeonRPCError}; +use jsonrpc_v2::{Data, Params}; +use neon_lib::{types::EmulateApiRequest, LibMethod}; + +pub async fn handle( + ctx: Data, + Params(params): Params>, +) -> Result { + let param = params.first().ok_or(NeonRPCError::IncorrectParameters())?; + invoke( + LibMethod::Emulate, + ctx, + Some(serde_json::value::to_value(param).unwrap()), + ) + .await +} diff --git a/evm_loader/rpc/src/handlers/get_balance.rs b/evm_loader/rpc/src/handlers/get_balance.rs new file mode 100644 index 000000000..5d78d4b95 --- /dev/null +++ b/evm_loader/rpc/src/handlers/get_balance.rs @@ -0,0 +1,17 @@ +use super::invoke; +use crate::{context::Context, error::NeonRPCError}; +use jsonrpc_v2::{Data, Params}; +use neon_lib::{types::GetBalanceRequest, LibMethod}; + +pub async fn handle( + ctx: Data, + Params(params): Params>, +) -> Result { + let param = params.first().ok_or(NeonRPCError::IncorrectParameters())?; + invoke( + LibMethod::GetBalance, + ctx, + Some(serde_json::value::to_value(param).unwrap()), + ) + .await +} diff --git a/evm_loader/rpc/src/handlers/get_config.rs b/evm_loader/rpc/src/handlers/get_config.rs new file mode 100644 index 000000000..d7f579eb7 --- /dev/null +++ b/evm_loader/rpc/src/handlers/get_config.rs @@ -0,0 +1,8 @@ +use super::invoke; +use crate::context::Context; +use jsonrpc_v2::Data; +use neon_lib::LibMethod; + +pub async fn handle(ctx: Data) -> Result { + invoke(LibMethod::GetConfig, ctx, Option::::None).await +} diff --git a/evm_loader/rpc/src/handlers/get_contract.rs b/evm_loader/rpc/src/handlers/get_contract.rs new file mode 100644 index 000000000..422bd73b4 --- /dev/null +++ b/evm_loader/rpc/src/handlers/get_contract.rs @@ -0,0 +1,17 @@ +use super::invoke; +use crate::{context::Context, error::NeonRPCError}; +use jsonrpc_v2::{Data, Params}; +use neon_lib::{types::GetContractRequest, LibMethod}; + +pub async fn handle( + ctx: Data, + Params(params): Params>, +) -> Result { + let param = params.first().ok_or(NeonRPCError::IncorrectParameters())?; + invoke( + LibMethod::GetContract, + ctx, + Some(serde_json::value::to_value(param).unwrap()), + ) + .await +} diff --git a/evm_loader/rpc/src/handlers/get_holder.rs b/evm_loader/rpc/src/handlers/get_holder.rs new file mode 100644 index 000000000..8140401bf --- /dev/null +++ b/evm_loader/rpc/src/handlers/get_holder.rs @@ -0,0 +1,17 @@ +use super::invoke; +use crate::{context::Context, error::NeonRPCError}; +use jsonrpc_v2::{Data, Params}; +use neon_lib::{types::GetHolderRequest, LibMethod}; + +pub async fn handle( + ctx: Data, + Params(params): Params>, +) -> Result { + let param = params.first().ok_or(NeonRPCError::IncorrectParameters())?; + invoke( + LibMethod::GetHolder, + ctx, + Some(serde_json::value::to_value(param).unwrap()), + ) + .await +} diff --git a/evm_loader/rpc/src/handlers/get_storage_at.rs b/evm_loader/rpc/src/handlers/get_storage_at.rs new file mode 100644 index 000000000..8bf80a4a9 --- /dev/null +++ b/evm_loader/rpc/src/handlers/get_storage_at.rs @@ -0,0 +1,17 @@ +use super::invoke; +use crate::{context::Context, error::NeonRPCError}; +use jsonrpc_v2::{Data, Params}; +use neon_lib::{types::GetStorageAtRequest, LibMethod}; + +pub async fn handle( + ctx: Data, + Params(params): Params>, +) -> Result { + let param = params.first().ok_or(NeonRPCError::IncorrectParameters())?; + invoke( + LibMethod::GetStorageAt, + ctx, + Some(serde_json::value::to_value(param).unwrap()), + ) + .await +} diff --git a/evm_loader/rpc/src/handlers/info.rs b/evm_loader/rpc/src/handlers/info.rs new file mode 100644 index 000000000..afc36bb76 --- /dev/null +++ b/evm_loader/rpc/src/handlers/info.rs @@ -0,0 +1,7 @@ +use serde_json::json; + +use crate::build_info::get_build_info; + +pub async fn handle() -> Result { + Ok(json!(get_build_info())) +} diff --git a/evm_loader/rpc/src/handlers/lib_info.rs b/evm_loader/rpc/src/handlers/lib_info.rs new file mode 100644 index 000000000..1d0f80bdb --- /dev/null +++ b/evm_loader/rpc/src/handlers/lib_info.rs @@ -0,0 +1,7 @@ +use super::lib_build_info; +use crate::context::Context; +use jsonrpc_v2::Data; + +pub async fn handle(ctx: Data) -> Result { + lib_build_info(ctx).await +} diff --git a/evm_loader/rpc/src/handlers/mod.rs b/evm_loader/rpc/src/handlers/mod.rs new file mode 100644 index 000000000..08f6f978d --- /dev/null +++ b/evm_loader/rpc/src/handlers/mod.rs @@ -0,0 +1,82 @@ +pub mod emulate; +pub mod get_balance; +pub mod get_config; +pub mod get_contract; +pub mod get_holder; +pub mod get_storage_at; +pub mod info; +pub mod lib_info; +pub mod trace; + +use crate::context::Context; +use jsonrpc_v2::Data; +use neon_lib::LibMethod; +use neon_lib_interface::{types::NeonEVMLibError, NeonEVMLib_Ref}; +use serde::Serialize; +use serde_json::Value; + +async fn get_library(context: &Data) -> Result<&NeonEVMLib_Ref, jsonrpc_v2::Error> { + // just for testing + let hash = context + .libraries + .keys() + .last() + .ok_or(jsonrpc_v2::Error::internal("library collection is empty"))?; + + let library = context + .libraries + .get(hash) + .ok_or(jsonrpc_v2::Error::internal(format!( + "Library not found for hash {hash}" + )))?; + + tracing::debug!("ver {:?}", library.hash()()); + + Ok(library) +} + +pub async fn invoke( + method: LibMethod, + context: Data, + params: Option, +) -> Result { + let library = get_library(&context).await?; + + let method_str: &str = method.into(); + let mut params_str: String = "".to_string(); + if let Some(params_value) = params { + params_str = serde_json::to_string(¶ms_value).unwrap(); + } + + library.invoke()(method_str.into(), params_str.as_str().into()) + .await + .map(|x| serde_json::from_str::(&x).unwrap()) + .map_err(|s| { + let NeonEVMLibError { + code, + message, + data, + } = serde_json::from_str(s.as_str()).unwrap(); + + jsonrpc_v2::Error::Full { + code: code as i64, + message, + data: Some(Box::new( + data.as_ref() + .and_then(Value::as_str) + .unwrap_or("null") + .to_string(), + )), + } + }) + .into() +} + +pub async fn lib_build_info( + context: Data, +) -> Result { + let library = get_library(&context).await?; + let build_info = library.get_build_info()(); + + Ok(serde_json::from_str::(&build_info).unwrap()) +} diff --git a/evm_loader/rpc/src/handlers/trace.rs b/evm_loader/rpc/src/handlers/trace.rs new file mode 100644 index 000000000..826c65f5c --- /dev/null +++ b/evm_loader/rpc/src/handlers/trace.rs @@ -0,0 +1,17 @@ +use super::invoke; +use crate::{context::Context, error::NeonRPCError}; +use jsonrpc_v2::{Data, Params}; +use neon_lib::{types::EmulateApiRequest, LibMethod}; + +pub async fn handle( + ctx: Data, + Params(params): Params>, +) -> Result { + let param = params.first().ok_or(NeonRPCError::IncorrectParameters())?; + invoke( + LibMethod::Trace, + ctx, + Some(serde_json::value::to_value(param).unwrap()), + ) + .await +} diff --git a/evm_loader/rpc/src/main.rs b/evm_loader/rpc/src/main.rs new file mode 100644 index 000000000..7c0f5a7af --- /dev/null +++ b/evm_loader/rpc/src/main.rs @@ -0,0 +1,75 @@ +// use std::{collections::HashMap, error::Error}; +mod build_info; +mod context; +mod error; +mod handlers; +mod options; +mod rpc; + +use crate::build_info::get_build_info; +use context::Context; +use error::NeonRPCError; +use neon_lib::config; +use std::{env, net::SocketAddr, str::FromStr}; +use tracing::info; +use tracing_appender::non_blocking::NonBlockingBuilder; + +type NeonRPCResult = Result; + +#[actix_web::main] +async fn main() -> NeonRPCResult<()> { + let matches = options::parse(); + + // initialize tracing + let (non_blocking, _guard) = NonBlockingBuilder::default() + .lossy(false) + .finish(std::io::stdout()); + + tracing_subscriber::fmt().with_writer(non_blocking).init(); + + let lib_dir = matches.value_of("LIB-DIR").unwrap(); + let libraries = neon_lib_interface::load_libraries(lib_dir)?; + + info!("BUILD INFO: {}", get_build_info()); + info!( + "LIBRARY DIR: {}, count: {}", + lib_dir, + libraries.keys().len(), + ); + + if libraries.keys().len() > 0 { + info!("=== LIBRARY VERSIONS: ================================================================="); + for library_ver in libraries.keys() { + info!("Lib version: {}", library_ver); + } + info!("=== END LIBRARY VERSIONS =============================================================="); + } + + // check configs + let _api_config = config::load_api_config_from_environment(); + + let ctx = Context { libraries }; + let rpc = rpc::build_rpc(ctx); + + let listener_addr = matches + .value_of("host") + .map(std::borrow::ToOwned::to_owned) + .or_else(|| Some(env::var("NEON_API_LISTENER_ADDR").unwrap_or("0.0.0.0:3100".to_owned()))) + .unwrap(); + + let addr = SocketAddr::from_str(listener_addr.as_str())?; + + actix_web::HttpServer::new(move || { + let rpc = rpc.clone(); + actix_web::App::new().service( + actix_web::web::service("/") + .guard(actix_web::guard::Post()) + .finish(rpc.into_web_service()), + ) + }) + .bind(addr)? + .run() + .await?; + + Ok(()) +} diff --git a/evm_loader/rpc/src/options.rs b/evm_loader/rpc/src/options.rs new file mode 100644 index 000000000..c7d953ce4 --- /dev/null +++ b/evm_loader/rpc/src/options.rs @@ -0,0 +1,26 @@ +use clap::ArgMatches; + +pub fn parse<'a>() -> ArgMatches<'a> { + clap::App::new("Neon Core RPC") + .version(env!("CARGO_PKG_VERSION")) + .author("Neon Labs") + .about("Runs a Neon Core RPC server") + .arg( + clap::Arg::with_name("LIB-DIR") + .env("NEON_LIB_DIR") + .alias("dir") + .help("Directory with neon libraries to load") + .required(true) + .index(1), + ) + .arg( + clap::Arg::with_name("HOST") + .alias("host") + .env("NEON_API_LISTENER_ADDR") + .default_value("0.0.0.0:3100") + .help("RPC host to connect to") + .required(false) + .index(2), + ) + .get_matches() +} diff --git a/evm_loader/rpc/src/rpc.rs b/evm_loader/rpc/src/rpc.rs new file mode 100644 index 000000000..eb49a5042 --- /dev/null +++ b/evm_loader/rpc/src/rpc.rs @@ -0,0 +1,24 @@ +use crate::context::Context; +use crate::handlers::{ + emulate, get_balance, get_config, get_contract, get_holder, get_storage_at, info, lib_info, + trace, +}; + +use jsonrpc_v2::{Data, MapRouter, Server}; +use neon_lib::LibMethod; +use std::sync::Arc; + +pub fn build_rpc(ctx: Context) -> Arc> { + Server::new() + .with_data(Data::new(ctx)) + .with_method("build_info", info::handle) + .with_method("lib_build_info", lib_info::handle) + .with_method(LibMethod::GetStorageAt.to_string(), get_storage_at::handle) + .with_method(LibMethod::Trace.to_string(), trace::handle) + .with_method(LibMethod::Emulate.to_string(), emulate::handle) + .with_method(LibMethod::GetBalance.to_string(), get_balance::handle) + .with_method(LibMethod::GetConfig.to_string(), get_config::handle) + .with_method(LibMethod::GetHolder.to_string(), get_holder::handle) + .with_method(LibMethod::GetContract.to_string(), get_contract::handle) + .finish() +} From a369a10bd5bfa07a96686fe0d11928525ecb2efa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Mar 2024 18:01:54 +0200 Subject: [PATCH 108/318] Bump tracing from 0.1.37 to 0.1.40 in /evm_loader (#307) Bumps [tracing](https://github.com/tokio-rs/tracing) from 0.1.37 to 0.1.40. - [Release notes](https://github.com/tokio-rs/tracing/releases) - [Commits](https://github.com/tokio-rs/tracing/compare/tracing-0.1.37...tracing-0.1.40) --- updated-dependencies: - dependency-name: tracing dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index be490e785..5d449bfed 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -6972,11 +6972,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "log", "pin-project-lite", "tracing-attributes", @@ -6996,20 +6995,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.23" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.50", ] [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", From 8572597ea50af85be8a20e75acf60aa73432e1a5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Mar 2024 22:07:51 +0200 Subject: [PATCH 109/318] Bump serde_with from 3.3.0 to 3.6.1 in /evm_loader (#308) Bumps [serde_with](https://github.com/jonasbb/serde_with) from 3.3.0 to 3.6.1. - [Release notes](https://github.com/jonasbb/serde_with/releases) - [Commits](https://github.com/jonasbb/serde_with/compare/v3.3.0...v3.6.1) --- updated-dependencies: - dependency-name: serde_with dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 13 +++++++------ evm_loader/lib/Cargo.toml | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 5d449bfed..1911a3542 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -3352,7 +3352,7 @@ dependencies = [ "scroll", "serde", "serde_json", - "serde_with 3.3.0", + "serde_with 3.6.1", "solana-clap-utils", "solana-cli", "solana-cli-config", @@ -4742,9 +4742,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.3.0" +version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ca3b16a3d82c4088f343b7480a93550b3eabe1a358569c2dfe38bbcead07237" +checksum = "15d167997bd841ec232f5b2b8e0e26606df2e7caa4c31b95ea9ca52b200bd270" dependencies = [ "base64 0.21.4", "chrono", @@ -4752,8 +4752,9 @@ dependencies = [ "indexmap 1.9.3", "indexmap 2.2.3", "serde", + "serde_derive", "serde_json", - "serde_with_macros 3.3.0", + "serde_with_macros 3.6.1", "time", ] @@ -4771,9 +4772,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.3.0" +version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e6be15c453eb305019bfa438b1593c731f36a289a7853f7707ee29e870b3b3c" +checksum = "865f9743393e638991566a8b7a479043c2c8da94a33e0a31f18214c9cae0a64d" dependencies = [ "darling", "proc-macro2", diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 120025f4d..8993f5bf4 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -24,7 +24,7 @@ base64 = "0.21" hex = { version = "0.4", features = ["serde"] } serde = "1.0" serde_json = { version = "1.0", features = ["preserve_order"] } -serde_with = { version = "3.3", features = ["hex"] } +serde_with = { version = "3.6", features = ["hex"] } log = "0.4.17" rand = "0.8" ethnum = { version = "1.4", default-features = false, features = ["serde"] } From d64940762aef9d49f185f745fea5a8bfe6b57a72 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Mar 2024 11:22:16 +0200 Subject: [PATCH 110/318] Bump clickhouse from 0.11.5 to 0.11.6 in /evm_loader (#309) Bumps [clickhouse](https://github.com/loyd/clickhouse.rs) from 0.11.5 to 0.11.6. - [Changelog](https://github.com/loyd/clickhouse.rs/blob/master/CHANGELOG.md) - [Commits](https://github.com/loyd/clickhouse.rs/compare/v0.11.5...v0.11.6) --- updated-dependencies: - dependency-name: clickhouse dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- evm_loader/lib/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 1911a3542..742495f57 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -1197,9 +1197,9 @@ dependencies = [ [[package]] name = "clickhouse" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33816ee1fea4f60d97abfeb773b9b566ae85f8bfa891758d00a1fb1e5a606591" +checksum = "a0875e527e299fc5f4faba42870bf199a39ab0bb2dbba1b8aef0a2151451130f" dependencies = [ "bstr", "bytes", diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 8993f5bf4..8ae1a4f75 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -31,7 +31,7 @@ ethnum = { version = "1.4", default-features = false, features = ["serde"] } goblin = { version = "0.6.0" } scroll = "0.11.0" tokio = { version = "1", features = ["full"] } -clickhouse = "0.11.5" +clickhouse = "0.11.6" tracing = "0.1" async-trait = "0.1.73" build-info = { version = "0.0.31", features = ["serde"] } From a757fb08778dd6c3bb62461af0b9ca22e28c0633 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Mar 2024 13:08:35 +0200 Subject: [PATCH 111/318] Bump tracing-subscriber from 0.3.17 to 0.3.18 in /evm_loader (#314) Bumps [tracing-subscriber](https://github.com/tokio-rs/tracing) from 0.3.17 to 0.3.18. - [Release notes](https://github.com/tokio-rs/tracing/releases) - [Commits](https://github.com/tokio-rs/tracing/compare/tracing-subscriber-0.3.17...tracing-subscriber-0.3.18) --- updated-dependencies: - dependency-name: tracing-subscriber dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 742495f57..c1c7dd8e4 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -7017,12 +7017,12 @@ dependencies = [ [[package]] name = "tracing-log" -version = "0.1.3" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ - "lazy_static", "log", + "once_cell", "tracing-core", ] @@ -7041,9 +7041,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", "nu-ansi-term", From d022ef0fe6b5695d243089565fd5ba288e1fa3b5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Mar 2024 14:52:12 +0200 Subject: [PATCH 112/318] Bump async-ffi from 0.4.1 to 0.5.0 in /evm_loader (#315) Bumps [async-ffi](https://github.com/oxalica/async-ffi) from 0.4.1 to 0.5.0. - [Release notes](https://github.com/oxalica/async-ffi/releases) - [Changelog](https://github.com/oxalica/async-ffi/blob/master/CHANGELOG.md) - [Commits](https://github.com/oxalica/async-ffi/compare/v0.4.1...v0.5.0) --- updated-dependencies: - dependency-name: async-ffi dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- evm_loader/lib-interface/Cargo.toml | 2 +- evm_loader/lib/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index c1c7dd8e4..193d83a0d 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -604,9 +604,9 @@ dependencies = [ [[package]] name = "async-ffi" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ed5a937a789391ebc1c77d3a15b060e0d100e6d7c483a2af3f250d6b8dc2a23" +checksum = "f4de21c0feef7e5a556e51af767c953f0501f7f300ba785cc99c47bdc8081a50" dependencies = [ "abi_stable", ] diff --git a/evm_loader/lib-interface/Cargo.toml b/evm_loader/lib-interface/Cargo.toml index 1a1283d88..656320378 100644 --- a/evm_loader/lib-interface/Cargo.toml +++ b/evm_loader/lib-interface/Cargo.toml @@ -8,6 +8,6 @@ edition = "2021" [dependencies] abi_stable = "0.11.1" thiserror = "1" -async-ffi = { version = "0.4.1", features = ["abi_stable"] } +async-ffi = { version = "0.5.0", features = ["abi_stable"] } serde = "1.0.147" serde_json = "1.0.85" diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 8ae1a4f75..3d690201a 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -39,7 +39,7 @@ enum_dispatch = "0.3.12" web3 = "0.19.0" neon-lib-interface = { path = "../lib-interface" } abi_stable = "0.11.2" -async-ffi = { version = "0.4.1", features = ["abi_stable"] } +async-ffi = { version = "0.5.0", features = ["abi_stable"] } strum = "0.25.0" strum_macros = "0.25.3" clap = "2.33.3" From 327b8d4aacf453bdb9b1bf0f7bc6186b4242b80f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Mar 2024 17:00:46 +0200 Subject: [PATCH 113/318] Bump serde_bytes from 0.11.12 to 0.11.14 in /evm_loader (#316) Bumps [serde_bytes](https://github.com/serde-rs/bytes) from 0.11.12 to 0.11.14. - [Release notes](https://github.com/serde-rs/bytes/releases) - [Commits](https://github.com/serde-rs/bytes/compare/0.11.12...0.11.14) --- updated-dependencies: - dependency-name: serde_bytes dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- evm_loader/program/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 193d83a0d..8a7581ce2 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -4668,9 +4668,9 @@ dependencies = [ [[package]] name = "serde_bytes" -version = "0.11.12" +version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" +checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" dependencies = [ "serde", ] diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index bd440cc85..34c8d576f 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -49,7 +49,7 @@ rlp = "0.5" static_assertions = "1" borsh = "0.10" bincode = "1" -serde_bytes = "0.11.12" +serde_bytes = "0.11.14" serde = { version = "1.0.186", default-features = false, features = ["derive", "rc"] } ethnum = { version = "1.4", default-features = false, features = ["serde"] } cfg-if = { version = "1.0" } From 9989cfc47285c0b15cb4d057784817d737c09ebd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Mar 2024 22:18:21 +0200 Subject: [PATCH 114/318] Bump ethnum from 1.4.0 to 1.5.0 in /evm_loader (#317) Bumps [ethnum](https://github.com/nlordell/ethnum-rs) from 1.4.0 to 1.5.0. - [Release notes](https://github.com/nlordell/ethnum-rs/releases) - [Commits](https://github.com/nlordell/ethnum-rs/compare/v1.4.0...v1.5.0) --- updated-dependencies: - dependency-name: ethnum dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- evm_loader/api/Cargo.toml | 2 +- evm_loader/cli/Cargo.toml | 2 +- evm_loader/lib/Cargo.toml | 2 +- evm_loader/program/Cargo.toml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 8a7581ce2..899e4dda7 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -1976,9 +1976,9 @@ dependencies = [ [[package]] name = "ethnum" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8ff382b2fa527fb7fb06eeebfc5bbb3f17e3cc6b9d70b006c41daa8824adac" +checksum = "b90ca2580b73ab6a1f724b76ca11ab632df820fd6040c336200d2c1df7b3c82c" dependencies = [ "serde", ] diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 07530d875..a31db5caf 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -12,7 +12,7 @@ solana-sdk = "=1.17.24" solana-client = "=1.17.24" serde = "1.0.186" serde_json = { version = "1.0.114", features = ["preserve_order"] } -ethnum = { version = "1.4", default-features = false, features = ["serde"] } +ethnum = { version = "1.5", default-features = false, features = ["serde"] } tokio = { version = "1", features = ["full"] } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index 28f2d53fd..ab8fbfe30 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -17,7 +17,7 @@ serde = "1.0.186" serde_json = { version = "1.0.114", features = ["preserve_order"] } log = "0.4.17" fern = "0.6" -ethnum = { version = "1.4", default-features = false, features = ["serde"] } +ethnum = { version = "1.5", default-features = false, features = ["serde"] } tokio = { version = "1", features = ["full"] } neon-lib = { path = "../lib" } build-info = { version = "0.0.31", features = ["serde"] } diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 3d690201a..443b68ee6 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -27,7 +27,7 @@ serde_json = { version = "1.0", features = ["preserve_order"] } serde_with = { version = "3.6", features = ["hex"] } log = "0.4.17" rand = "0.8" -ethnum = { version = "1.4", default-features = false, features = ["serde"] } +ethnum = { version = "1.5", default-features = false, features = ["serde"] } goblin = { version = "0.6.0" } scroll = "0.11.0" tokio = { version = "1", features = ["full"] } diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 34c8d576f..c7f3dfab8 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -51,7 +51,7 @@ borsh = "0.10" bincode = "1" serde_bytes = "0.11.14" serde = { version = "1.0.186", default-features = false, features = ["derive", "rc"] } -ethnum = { version = "1.4", default-features = false, features = ["serde"] } +ethnum = { version = "1.5", default-features = false, features = ["serde"] } cfg-if = { version = "1.0" } log = { version = "0.4", default-features = false, optional = true } maybe-async = "0.2.7" From 2dff70a9dc780a30cd1d1b77a6c0752cdc6eceb8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Mar 2024 22:39:43 +0200 Subject: [PATCH 115/318] Bump base64 from 0.21.4 to 0.22.0 in /evm_loader (#318) Bumps [base64](https://github.com/marshallpierce/rust-base64) from 0.21.4 to 0.22.0. - [Changelog](https://github.com/marshallpierce/rust-base64/blob/master/RELEASE-NOTES.md) - [Commits](https://github.com/marshallpierce/rust-base64/compare/v0.21.4...v0.22.0) --- updated-dependencies: - dependency-name: base64 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 50 ++++++++++++++++++++++----------------- evm_loader/lib/Cargo.toml | 2 +- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 899e4dda7..c89aafe43 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -88,7 +88,7 @@ dependencies = [ "actix-service", "actix-utils", "ahash 0.8.5", - "base64 0.21.4", + "base64 0.21.7", "bitflags 2.4.0", "brotli", "bytes", @@ -677,9 +677,15 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.4" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" +checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" [[package]] name = "base64ct" @@ -924,7 +930,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b314717755dd6a06fc11ad3f7909ba4c0ae2ab516f5cb0404fe924c71bfc7d0" dependencies = [ "anyhow", - "base64 0.21.4", + "base64 0.21.7", "bincode", "build-info-common", "cargo_metadata", @@ -957,7 +963,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffd5f241ddd417436c48d35da9869480891449ddd1ae3fd483bbcfbae741a422" dependencies = [ "anyhow", - "base64 0.21.4", + "base64 0.21.7", "bincode", "build-info-common", "chrono", @@ -2420,7 +2426,7 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" dependencies = [ - "base64 0.21.4", + "base64 0.21.7", "bytes", "headers-core", "http", @@ -3333,7 +3339,7 @@ dependencies = [ "anyhow", "async-ffi", "async-trait", - "base64 0.21.4", + "base64 0.22.0", "bincode", "bs58", "build-info", @@ -4339,7 +4345,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" dependencies = [ "async-compression", - "base64 0.21.4", + "base64 0.21.7", "bytes", "encoding_rs", "futures-core", @@ -4510,7 +4516,7 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" dependencies = [ - "base64 0.21.4", + "base64 0.21.7", ] [[package]] @@ -4746,7 +4752,7 @@ version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15d167997bd841ec232f5b2b8e0e26606df2e7caa4c31b95ea9ca52b200bd270" dependencies = [ - "base64 0.21.4", + "base64 0.21.7", "chrono", "hex", "indexmap 1.9.3", @@ -4968,7 +4974,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f22a6b3c7e728d335dcfca063e57e1a7c43a5ad2d6889f9b1684b1ab5cc25dd4" dependencies = [ "Inflector", - "base64 0.21.4", + "base64 0.21.7", "bincode", "bs58", "bv", @@ -5242,7 +5248,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f2b5acd03e51421cc6531738115ca763b168a8e34dd4442bb683eebff5c4c5a" dependencies = [ "Inflector", - "base64 0.21.4", + "base64 0.21.7", "chrono", "clap 2.34.0", "console", @@ -5541,7 +5547,7 @@ dependencies = [ "ark-ec", "ark-ff", "ark-serialize", - "base64 0.21.4", + "base64 0.21.7", "bincode", "bitflags 2.4.0", "blake3", @@ -5591,7 +5597,7 @@ version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a92f2a945295cdc782e5a9223b96982755e32babc6e7992ca3f73ccccd111ce" dependencies = [ - "base64 0.21.4", + "base64 0.21.7", "bincode", "eager", "enum-iterator", @@ -5621,7 +5627,7 @@ checksum = "ee70dfdbb935266d7d85adcf957eec196bd033a7b8fbce16db21611cbf91d582" dependencies = [ "assert_matches", "async-trait", - "base64 0.21.4", + "base64 0.21.7", "bincode", "chrono-humanize", "crossbeam-channel", @@ -5732,7 +5738,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45106dab6a4b406ddfd6c0e6f4b4dea2c1cac5d1dbaf11ed644fc102f7293a9b" dependencies = [ "async-trait", - "base64 0.21.4", + "base64 0.21.7", "bincode", "bs58", "indicatif", @@ -5757,7 +5763,7 @@ version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0190bf789cc7a1f3508928f01051381cc15bda16120a2a080ff10aa311388970" dependencies = [ - "base64 0.21.4", + "base64 0.21.7", "bs58", "jsonrpc-core", "reqwest", @@ -5793,7 +5799,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64ca87344dfc2b5e1058b4d528b736076d9b335a1cf69a3de2bb3807f8c72594" dependencies = [ "arrayref", - "base64 0.21.4", + "base64 0.21.7", "bincode", "blake3", "bv", @@ -5870,7 +5876,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa149a29cb505742bca6bce7447d979e746452ec40e9b1eb3e50d51a0f0510cd" dependencies = [ "assert_matches", - "base64 0.21.4", + "base64 0.21.7", "bincode", "bitflags 2.4.0", "borsh 0.10.3", @@ -6059,7 +6065,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a4107eac6b20f3349c49af21eaca73cd3d92a2c1b03118531349415ab4e7f84" dependencies = [ "Inflector", - "base64 0.21.4", + "base64 0.21.7", "bincode", "borsh 0.10.3", "bs58", @@ -6170,7 +6176,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7845f8390725707661732fb4df99c5c82eb3f7549c187160c317706e839c5702" dependencies = [ "aes-gcm-siv", - "base64 0.21.4", + "base64 0.21.7", "bincode", "bytemuck", "byteorder", @@ -7374,7 +7380,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5388522c899d1e1c96a4c307e3797e0f697ba7c77dd8e0e625ecba9dd0342937" dependencies = [ "arrayvec", - "base64 0.21.4", + "base64 0.21.7", "bytes", "derive_more", "ethabi", diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 443b68ee6..ee2a10516 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -20,7 +20,7 @@ solana-program-test = "=1.17.24" spl-token = { version = "~4.0", default-features = false, features = ["no-entrypoint"] } spl-associated-token-account = { version = "~2.3", default-features = false, features = ["no-entrypoint"] } bs58 = "0.4.0" -base64 = "0.21" +base64 = "0.22" hex = { version = "0.4", features = ["serde"] } serde = "1.0" serde_json = { version = "1.0", features = ["preserve_order"] } From ba2bb9ddff7265270c2da47143eee2fcd068ebca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Mar 2024 23:02:44 +0200 Subject: [PATCH 116/318] Bump strum from 0.25.0 to 0.26.1 in /evm_loader (#319) Bumps [strum](https://github.com/Peternator7/strum) from 0.25.0 to 0.26.1. - [Release notes](https://github.com/Peternator7/strum/releases) - [Changelog](https://github.com/Peternator7/strum/blob/master/CHANGELOG.md) - [Commits](https://github.com/Peternator7/strum/commits/v0.26.1) --- updated-dependencies: - dependency-name: strum dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 6 +++--- evm_loader/lib/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index c89aafe43..51d8421b4 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -3368,7 +3368,7 @@ dependencies = [ "solana-transaction-status", "spl-associated-token-account", "spl-token", - "strum 0.25.0", + "strum 0.26.1", "strum_macros 0.25.3", "thiserror", "tokio", @@ -6469,9 +6469,9 @@ dependencies = [ [[package]] name = "strum" -version = "0.25.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +checksum = "723b93e8addf9aa965ebe2d11da6d7540fa2283fcea14b3371ff055f7ba13f5f" [[package]] name = "strum_macros" diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index ee2a10516..93a56a072 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -40,7 +40,7 @@ web3 = "0.19.0" neon-lib-interface = { path = "../lib-interface" } abi_stable = "0.11.2" async-ffi = { version = "0.5.0", features = ["abi_stable"] } -strum = "0.25.0" +strum = "0.26.1" strum_macros = "0.25.3" clap = "2.33.3" lazy_static = "1.4.0" From d689d34c87a4b3d6640fab9b55a8cecd5538df53 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Mar 2024 23:53:16 +0200 Subject: [PATCH 117/318] Bump jsonrpsee-types from 0.20.3 to 0.22.2 in /evm_loader (#321) Bumps [jsonrpsee-types](https://github.com/paritytech/jsonrpsee) from 0.20.3 to 0.22.2. - [Release notes](https://github.com/paritytech/jsonrpsee/releases) - [Changelog](https://github.com/paritytech/jsonrpsee/blob/master/CHANGELOG.md) - [Commits](https://github.com/paritytech/jsonrpsee/compare/v0.20.3...v0.22.2) --- updated-dependencies: - dependency-name: jsonrpsee-types dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 19 ++++++++++++++++--- evm_loader/rpc-client/Cargo.toml | 2 +- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 51d8421b4..09c65dc0a 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -2869,7 +2869,7 @@ dependencies = [ "beef", "futures-util", "hyper", - "jsonrpsee-types", + "jsonrpsee-types 0.20.3", "serde", "serde_json", "thiserror", @@ -2887,7 +2887,7 @@ dependencies = [ "hyper", "hyper-rustls", "jsonrpsee-core", - "jsonrpsee-types", + "jsonrpsee-types 0.20.3", "serde", "serde_json", "thiserror", @@ -2911,6 +2911,19 @@ dependencies = [ "tracing", ] +[[package]] +name = "jsonrpsee-types" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3467fd35feeee179f71ab294516bdf3a81139e7aeebdd860e46897c12e1a3368" +dependencies = [ + "anyhow", + "beef", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "keccak" version = "0.1.3" @@ -3417,7 +3430,7 @@ dependencies = [ "jsonrpc-v2", "jsonrpsee-core", "jsonrpsee-http-client", - "jsonrpsee-types", + "jsonrpsee-types 0.22.2", "neon-lib", "serde", "serde_json", diff --git a/evm_loader/rpc-client/Cargo.toml b/evm_loader/rpc-client/Cargo.toml index 826081a55..1c041aac4 100644 --- a/evm_loader/rpc-client/Cargo.toml +++ b/evm_loader/rpc-client/Cargo.toml @@ -14,6 +14,6 @@ thiserror = "1.0.49" async-trait = "0.1.74" jsonrpsee-core = "0.20.2" jsonrpsee-http-client = "0.20.2" -jsonrpsee-types = "0.20.2" +jsonrpsee-types = "0.22.2" tokio = { version = "1", features = ["full"] } build-info = { version = "0.0.31", features = ["serde"] } From 71bcb2c4beb2bf660e6ae5f37d4d31b442e2dd56 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 9 Mar 2024 00:26:33 +0200 Subject: [PATCH 118/318] Bump syn from 1.0.109 to 2.0.50 in /evm_loader (#322) Bumps [syn](https://github.com/dtolnay/syn) from 1.0.109 to 2.0.50. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/1.0.109...2.0.50) --- updated-dependencies: - dependency-name: syn dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 2 +- evm_loader/program-macro/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 09c65dc0a..648f6acd3 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -2033,7 +2033,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 1.0.109", + "syn 2.0.50", "toml 0.8.0", ] diff --git a/evm_loader/program-macro/Cargo.toml b/evm_loader/program-macro/Cargo.toml index 5255b1dde..cdd27ac2d 100644 --- a/evm_loader/program-macro/Cargo.toml +++ b/evm_loader/program-macro/Cargo.toml @@ -9,7 +9,7 @@ authors = ["NeonLabs Maintainers "] proc-macro = true [dependencies] -syn = "1" +syn = "2" proc-macro2 = "1" quote = "1" itertools = "0.12" From d6ba9cba5498caea9f9ba84238133d4403924f1e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 9 Mar 2024 05:23:33 +0200 Subject: [PATCH 119/318] Bump maybe-async from 0.2.7 to 0.2.10 in /evm_loader (#323) Bumps [maybe-async](https://github.com/fMeow/maybe-async-rs) from 0.2.7 to 0.2.10. - [Changelog](https://github.com/fMeow/maybe-async-rs/blob/main/CHANGELOG.md) - [Commits](https://github.com/fMeow/maybe-async-rs/compare/v0.2.7...v0.2.10) --- updated-dependencies: - dependency-name: maybe-async dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 6 +++--- evm_loader/program/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 648f6acd3..c61f4d18a 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -3150,13 +3150,13 @@ dependencies = [ [[package]] name = "maybe-async" -version = "0.2.7" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f1b8c13cb1f814b634a96b2c725449fe7ed464a7b8781de8688be5ffbd3f305" +checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.50", ] [[package]] diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index c7f3dfab8..0485c2ac5 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -54,7 +54,7 @@ serde = { version = "1.0.186", default-features = false, features = ["derive", " ethnum = { version = "1.5", default-features = false, features = ["serde"] } cfg-if = { version = "1.0" } log = { version = "0.4", default-features = false, optional = true } -maybe-async = "0.2.7" +maybe-async = "0.2.10" async-trait = { version = "0.1.73", optional = true } [target.'cfg(target_os = "solana")'.dependencies.maybe-async] From 259c89026a70710315b63d4403097a21647fd2c5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 9 Mar 2024 05:58:57 +0200 Subject: [PATCH 120/318] Bump actix-web from 4.4.0 to 4.5.1 in /evm_loader (#324) Bumps [actix-web](https://github.com/actix/actix-web) from 4.4.0 to 4.5.1. - [Release notes](https://github.com/actix/actix-web/releases) - [Changelog](https://github.com/actix/actix-web/blob/master/CHANGES.md) - [Commits](https://github.com/actix/actix-web/compare/web-v4.4.0...web-v4.5.1) --- updated-dependencies: - dependency-name: actix-web dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 21 ++++++++++----------- evm_loader/api/Cargo.toml | 2 +- evm_loader/rpc/Cargo.toml | 2 +- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index c61f4d18a..bf2e7f0ff 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -79,9 +79,9 @@ dependencies = [ [[package]] name = "actix-http" -version = "3.4.0" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92ef85799cba03f76e4f7c10f533e66d87c9a7e7055f3391f09000ad8351bc9" +checksum = "d223b13fd481fc0d1f83bb12659ae774d9e3601814c68a0bc539731698cca743" dependencies = [ "actix-codec", "actix-rt", @@ -113,7 +113,7 @@ dependencies = [ "tokio", "tokio-util 0.7.7", "tracing", - "zstd 0.12.4", + "zstd 0.13.0", ] [[package]] @@ -200,9 +200,9 @@ dependencies = [ [[package]] name = "actix-web" -version = "4.4.0" +version = "4.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4a5b5e29603ca8c94a77c65cf874718ceb60292c5a5c3e5f4ace041af462b9" +checksum = "43a6556ddebb638c2358714d853257ed226ece6023ef9364f23f0c70737ea984" dependencies = [ "actix-codec", "actix-http", @@ -7841,11 +7841,11 @@ dependencies = [ [[package]] name = "zstd" -version = "0.12.4" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c" +checksum = "bffb3309596d527cfcba7dfc6ed6052f1d39dfbd7c867aa2e865e4a449c10110" dependencies = [ - "zstd-safe 6.0.6", + "zstd-safe 7.0.0", ] [[package]] @@ -7860,11 +7860,10 @@ dependencies = [ [[package]] name = "zstd-safe" -version = "6.0.6" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581" +checksum = "43747c7422e2924c11144d5229878b98180ef8b06cca4ab5af37afc8a8d8ea3e" dependencies = [ - "libc", "zstd-sys", ] diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index a31db5caf..96c22b1d3 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -19,7 +19,7 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] } tracing-appender = "0.2.2" tower = { version = "0.4", features = ["make"] } neon-lib = { path = "../lib" } -actix-web = "4.4.0" +actix-web = "4.5.1" actix-request-identifier = "4.1.0" hex = "0.4.2" build-info = { version = "0.0.31", features = ["serde"] } diff --git a/evm_loader/rpc/Cargo.toml b/evm_loader/rpc/Cargo.toml index ea03ce5dc..5ca2d3bfe 100644 --- a/evm_loader/rpc/Cargo.toml +++ b/evm_loader/rpc/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -actix-web = "4.3.1" +actix-web = "4.5.1" clap = "2.33.3" jsonrpc-v2 = "0.13.0" neon-lib-interface = { path = "../lib-interface" } From b3151e7bfebb7758f97fc9a7af1505b2776585c1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 9 Mar 2024 06:30:53 +0200 Subject: [PATCH 121/318] Bump log from 0.4.20 to 0.4.21 in /evm_loader (#325) Bumps [log](https://github.com/rust-lang/log) from 0.4.20 to 0.4.21. - [Release notes](https://github.com/rust-lang/log/releases) - [Changelog](https://github.com/rust-lang/log/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/log/compare/0.4.20...0.4.21) --- updated-dependencies: - dependency-name: log dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- evm_loader/cli/Cargo.toml | 2 +- evm_loader/lib/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index bf2e7f0ff..99e5d2e11 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -3095,9 +3095,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "lru" diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index ab8fbfe30..ce6537a44 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -15,7 +15,7 @@ solana-cli-config = "=1.17.24" hex = "0.4.2" serde = "1.0.186" serde_json = { version = "1.0.114", features = ["preserve_order"] } -log = "0.4.17" +log = "0.4.21" fern = "0.6" ethnum = { version = "1.5", default-features = false, features = ["serde"] } tokio = { version = "1", features = ["full"] } diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 93a56a072..23b819ab7 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -25,7 +25,7 @@ hex = { version = "0.4", features = ["serde"] } serde = "1.0" serde_json = { version = "1.0", features = ["preserve_order"] } serde_with = { version = "3.6", features = ["hex"] } -log = "0.4.17" +log = "0.4.21" rand = "0.8" ethnum = { version = "1.5", default-features = false, features = ["serde"] } goblin = { version = "0.6.0" } From 2dc8ab6cbdf105a4d3119839032d6ef960ba46d8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 9 Mar 2024 08:28:42 +0100 Subject: [PATCH 122/318] Bump tracing-appender from 0.2.2 to 0.2.3 in /evm_loader (#326) Bumps [tracing-appender](https://github.com/tokio-rs/tracing) from 0.2.2 to 0.2.3. - [Release notes](https://github.com/tokio-rs/tracing/releases) - [Commits](https://github.com/tokio-rs/tracing/compare/tracing-appender-0.2.2...tracing-appender-0.2.3) --- updated-dependencies: - dependency-name: tracing-appender dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 5 +++-- evm_loader/api/Cargo.toml | 2 +- evm_loader/rpc/Cargo.toml | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 99e5d2e11..db5336cd0 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -7004,11 +7004,12 @@ dependencies = [ [[package]] name = "tracing-appender" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d48f71a791638519505cefafe162606f706c25592e4bde4d97600c0195312e" +checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" dependencies = [ "crossbeam-channel", + "thiserror", "time", "tracing-subscriber", ] diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 96c22b1d3..c3d9cd375 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -16,7 +16,7 @@ ethnum = { version = "1.5", default-features = false, features = ["serde"] } tokio = { version = "1", features = ["full"] } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } -tracing-appender = "0.2.2" +tracing-appender = "0.2.3" tower = { version = "0.4", features = ["make"] } neon-lib = { path = "../lib" } actix-web = "4.5.1" diff --git a/evm_loader/rpc/Cargo.toml b/evm_loader/rpc/Cargo.toml index 5ca2d3bfe..4bfcf8624 100644 --- a/evm_loader/rpc/Cargo.toml +++ b/evm_loader/rpc/Cargo.toml @@ -19,7 +19,7 @@ build-info = { version = "0.0.31", features = ["serde"] } thiserror = "1.0" tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } -tracing-appender = "0.2.2" +tracing-appender = "0.2.3" [build-dependencies] build-info-build = "0.0.31" From 560be27bb6ed742eb705c2d8659156844139e8b7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 9 Mar 2024 10:53:33 +0100 Subject: [PATCH 123/318] Bump toml from 0.8.0 to 0.8.2 in /evm_loader (#327) Bumps [toml](https://github.com/toml-rs/toml) from 0.8.0 to 0.8.2. - [Commits](https://github.com/toml-rs/toml/compare/toml-v0.8.0...toml-v0.8.2) --- updated-dependencies: - dependency-name: toml dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index db5336cd0..d83264533 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -2034,7 +2034,7 @@ dependencies = [ "quote", "serde", "syn 2.0.50", - "toml 0.8.0", + "toml 0.8.2", ] [[package]] @@ -6919,14 +6919,14 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c226a7bba6d859b63c92c4b4fe69c5b6b72d0cb897dbc8e6012298e6154cb56e" +checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.20.0", + "toml_edit 0.20.2", ] [[package]] @@ -6951,9 +6951,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.20.0" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ff63e60a958cefbb518ae1fd6566af80d9d4be430a33f3723dfc47d1d411d95" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ "indexmap 2.2.3", "serde", From 48850f953e3a084b3e0012c2cb3f0bd7605c98cf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 9 Mar 2024 17:12:17 +0100 Subject: [PATCH 124/318] Bump bs58 from 0.4.0 to 0.5.0 in /evm_loader (#329) Bumps [bs58](https://github.com/Nullus157/bs58-rs) from 0.4.0 to 0.5.0. - [Changelog](https://github.com/Nullus157/bs58-rs/blob/main/CHANGELOG.md) - [Commits](https://github.com/Nullus157/bs58-rs/compare/0.4.0...0.5.0) --- updated-dependencies: - dependency-name: bs58 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 31 +++++++++++++++++++---------- evm_loader/lib/Cargo.toml | 2 +- evm_loader/program-macro/Cargo.toml | 2 +- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index d83264533..55e79bec5 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -903,6 +903,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" +[[package]] +name = "bs58" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" +dependencies = [ + "tinyvec", +] + [[package]] name = "bstr" version = "1.4.0" @@ -2028,7 +2037,7 @@ dependencies = [ name = "evm-loader-macro" version = "1.0.0" dependencies = [ - "bs58", + "bs58 0.5.0", "itertools 0.12.1", "proc-macro2", "quote", @@ -3354,7 +3363,7 @@ dependencies = [ "async-trait", "base64 0.22.0", "bincode", - "bs58", + "bs58 0.5.0", "build-info", "build-info-build", "clap 2.34.0", @@ -4989,7 +4998,7 @@ dependencies = [ "Inflector", "base64 0.21.7", "bincode", - "bs58", + "bs58 0.4.0", "bv", "lazy_static", "serde", @@ -5194,7 +5203,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c343823d715ee17413e807a4646b061e0f90ced78dfe0d625ce951c34142891a" dependencies = [ "bincode", - "bs58", + "bs58 0.4.0", "clap 2.34.0", "console", "const_format", @@ -5417,7 +5426,7 @@ dependencies = [ "ahash 0.8.5", "blake3", "block-buffer 0.10.4", - "bs58", + "bs58 0.4.0", "bv", "byteorder", "cc", @@ -5566,7 +5575,7 @@ dependencies = [ "blake3", "borsh 0.10.3", "borsh 0.9.3", - "bs58", + "bs58 0.4.0", "bv", "bytemuck", "cc", @@ -5753,7 +5762,7 @@ dependencies = [ "async-trait", "base64 0.21.7", "bincode", - "bs58", + "bs58 0.4.0", "indicatif", "log", "reqwest", @@ -5777,7 +5786,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0190bf789cc7a1f3508928f01051381cc15bda16120a2a080ff10aa311388970" dependencies = [ "base64 0.21.7", - "bs58", + "bs58 0.4.0", "jsonrpc-core", "reqwest", "semver", @@ -5893,7 +5902,7 @@ dependencies = [ "bincode", "bitflags 2.4.0", "borsh 0.10.3", - "bs58", + "bs58 0.4.0", "bytemuck", "byteorder", "chrono", @@ -5942,7 +5951,7 @@ version = "1.17.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd8ad88355cf03e34b60ba12f65dffc44054e453aa1113a50169ee42ab6ad7a3" dependencies = [ - "bs58", + "bs58 0.4.0", "proc-macro2", "quote", "rustversion", @@ -6081,7 +6090,7 @@ dependencies = [ "base64 0.21.7", "bincode", "borsh 0.10.3", - "bs58", + "bs58 0.4.0", "lazy_static", "log", "serde", diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 23b819ab7..eee27e9d8 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -19,7 +19,7 @@ solana-transaction-status = "=1.17.24" solana-program-test = "=1.17.24" spl-token = { version = "~4.0", default-features = false, features = ["no-entrypoint"] } spl-associated-token-account = { version = "~2.3", default-features = false, features = ["no-entrypoint"] } -bs58 = "0.4.0" +bs58 = "0.5.0" base64 = "0.22" hex = { version = "0.4", features = ["serde"] } serde = "1.0" diff --git a/evm_loader/program-macro/Cargo.toml b/evm_loader/program-macro/Cargo.toml index cdd27ac2d..6beb96c78 100644 --- a/evm_loader/program-macro/Cargo.toml +++ b/evm_loader/program-macro/Cargo.toml @@ -13,6 +13,6 @@ syn = "2" proc-macro2 = "1" quote = "1" itertools = "0.12" -bs58 = "0.4" +bs58 = "0.5" serde = { version = "1.0", features = [ "derive" ] } toml = "0.8" From 952d889230d5ded4f0911800c082403301858f3f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 9 Mar 2024 17:56:10 +0100 Subject: [PATCH 125/318] Bump strum_macros from 0.25.3 to 0.26.1 in /evm_loader (#330) Bumps [strum_macros](https://github.com/Peternator7/strum) from 0.25.3 to 0.26.1. - [Release notes](https://github.com/Peternator7/strum/releases) - [Changelog](https://github.com/Peternator7/strum/blob/master/CHANGELOG.md) - [Commits](https://github.com/Peternator7/strum/commits/v0.26.1) --- updated-dependencies: - dependency-name: strum_macros dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 6 +++--- evm_loader/lib/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 55e79bec5..8ba939a62 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -3391,7 +3391,7 @@ dependencies = [ "spl-associated-token-account", "spl-token", "strum 0.26.1", - "strum_macros 0.25.3", + "strum_macros 0.26.1", "thiserror", "tokio", "tracing", @@ -6510,9 +6510,9 @@ dependencies = [ [[package]] name = "strum_macros" -version = "0.25.3" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +checksum = "7a3417fc93d76740d974a01654a09777cb500428cc874ca9f45edfe0c4d4cd18" dependencies = [ "heck 0.4.1", "proc-macro2", diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index eee27e9d8..2c988a08b 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -41,7 +41,7 @@ neon-lib-interface = { path = "../lib-interface" } abi_stable = "0.11.2" async-ffi = { version = "0.5.0", features = ["abi_stable"] } strum = "0.26.1" -strum_macros = "0.25.3" +strum_macros = "0.26.1" clap = "2.33.3" lazy_static = "1.4.0" From 97826bd67bbda5bb3da70a878e035a0352ea1993 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 9 Mar 2024 21:35:05 +0100 Subject: [PATCH 126/318] Bump anyhow from 1.0.70 to 1.0.80 in /evm_loader (#332) Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.70 to 1.0.80. - [Release notes](https://github.com/dtolnay/anyhow/releases) - [Commits](https://github.com/dtolnay/anyhow/compare/1.0.70...1.0.80) --- updated-dependencies: - dependency-name: anyhow dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 8ba939a62..1f84f8f66 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -381,9 +381,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.70" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" +checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" [[package]] name = "ark-bn254" From 1c61bb5f5f9de630a6a98011bf27f71f1fc2b7de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 9 Mar 2024 22:20:01 +0100 Subject: [PATCH 127/318] Bump syn from 2.0.50 to 2.0.52 in /evm_loader (#333) Bumps [syn](https://github.com/dtolnay/syn) from 2.0.50 to 2.0.52. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.50...2.0.52) --- updated-dependencies: - dependency-name: syn dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 84 +++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 1f84f8f66..b965a42e3 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -123,7 +123,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -247,7 +247,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -628,7 +628,7 @@ checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -982,7 +982,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.50", + "syn 2.0.52", "xz2", ] @@ -1025,7 +1025,7 @@ checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -1561,7 +1561,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -1578,7 +1578,7 @@ checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -1602,7 +1602,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -1613,7 +1613,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -1785,7 +1785,7 @@ checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -1879,7 +1879,7 @@ checksum = "eecf8589574ce9b895052fa12d69af7a233f99e6107f5cb8dd1044f2a17bfdcb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -1892,7 +1892,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -1904,7 +1904,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -2042,7 +2042,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.50", + "syn 2.0.52", "toml 0.8.2", ] @@ -2217,7 +2217,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -3165,7 +3165,7 @@ checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -3556,7 +3556,7 @@ checksum = "cfb77679af88f8b125209d354a202862602672222e7f2313fdd6dc349bad4712" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -3638,7 +3638,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -3650,7 +3650,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -3712,7 +3712,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -3901,7 +3901,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -4061,7 +4061,7 @@ checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -4711,7 +4711,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -4795,7 +4795,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -4807,7 +4807,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -5456,7 +5456,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -5955,7 +5955,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -6290,7 +6290,7 @@ checksum = "fadbefec4f3c678215ca72bd71862697bb06b41fd77c0088902dd3203354387b" dependencies = [ "quote", "spl-discriminator-syn", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -6302,7 +6302,7 @@ dependencies = [ "proc-macro2", "quote", "sha2 0.10.8", - "syn 2.0.50", + "syn 2.0.52", "thiserror", ] @@ -6350,7 +6350,7 @@ dependencies = [ "proc-macro2", "quote", "sha2 0.10.8", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -6518,7 +6518,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -6546,9 +6546,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.50" +version = "2.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" dependencies = [ "proc-macro2", "quote", @@ -6658,7 +6658,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -6669,7 +6669,7 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", "test-case-core", ] @@ -6705,7 +6705,7 @@ checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -6822,7 +6822,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -7031,7 +7031,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -7341,7 +7341,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", "wasm-bindgen-shared", ] @@ -7375,7 +7375,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -7817,7 +7817,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] @@ -7837,7 +7837,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.50", + "syn 2.0.52", ] [[package]] From 41e88acef954a178a40e96cc59a67421316755c4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 10 Mar 2024 07:44:49 +0100 Subject: [PATCH 128/318] Bump async-trait from 0.1.74 to 0.1.77 in /evm_loader (#334) Bumps [async-trait](https://github.com/dtolnay/async-trait) from 0.1.74 to 0.1.77. - [Release notes](https://github.com/dtolnay/async-trait/releases) - [Commits](https://github.com/dtolnay/async-trait/commits) --- updated-dependencies: - dependency-name: async-trait dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- evm_loader/lib/Cargo.toml | 2 +- evm_loader/program/Cargo.toml | 2 +- evm_loader/rpc-client/Cargo.toml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index b965a42e3..e2792c7b7 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -622,9 +622,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.74" +version = "0.1.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 2c988a08b..0f6b313f0 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -33,7 +33,7 @@ scroll = "0.11.0" tokio = { version = "1", features = ["full"] } clickhouse = "0.11.6" tracing = "0.1" -async-trait = "0.1.73" +async-trait = "0.1.77" build-info = { version = "0.0.31", features = ["serde"] } enum_dispatch = "0.3.12" web3 = "0.19.0" diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 0485c2ac5..ac6927396 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -55,7 +55,7 @@ ethnum = { version = "1.5", default-features = false, features = ["serde"] } cfg-if = { version = "1.0" } log = { version = "0.4", default-features = false, optional = true } maybe-async = "0.2.10" -async-trait = { version = "0.1.73", optional = true } +async-trait = { version = "0.1.77", optional = true } [target.'cfg(target_os = "solana")'.dependencies.maybe-async] version = "0.2.7" diff --git a/evm_loader/rpc-client/Cargo.toml b/evm_loader/rpc-client/Cargo.toml index 1c041aac4..ee34bd506 100644 --- a/evm_loader/rpc-client/Cargo.toml +++ b/evm_loader/rpc-client/Cargo.toml @@ -11,7 +11,7 @@ serde_json = "1.0.107" jsonrpc-v2 = "0.13.0" neon-lib = { path = "../lib" } thiserror = "1.0.49" -async-trait = "0.1.74" +async-trait = "0.1.77" jsonrpsee-core = "0.20.2" jsonrpsee-http-client = "0.20.2" jsonrpsee-types = "0.22.2" From 4a54890a77588d9178e7b98ac79256c3ac85bcb5 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Mon, 11 Mar 2024 08:31:38 +0100 Subject: [PATCH 129/318] NDEV-2301 & NDEV-2328 & NDEV-2299: Implement debug_traceTransaction prestateTracer, callTracer & trace_replayTransaction stateDiff tracer (#310) --- evm_loader/Cargo.lock | 1 + evm_loader/lib/Cargo.toml | 1 + evm_loader/lib/src/commands/emulate.rs | 4 +- evm_loader/lib/src/commands/trace.rs | 9 +- evm_loader/lib/src/tracing/mod.rs | 8 +- .../lib/src/tracing/tracers/call_tracer.rs | 307 +++++++++++++ evm_loader/lib/src/tracing/tracers/mod.rs | 61 ++- .../lib/src/tracing/tracers/openeth/mod.rs | 3 + .../src/tracing/tracers/openeth/state_diff.rs | 72 ++++ .../lib/src/tracing/tracers/openeth/tracer.rs | 72 ++++ .../lib/src/tracing/tracers/openeth/types.rs | 406 ++++++++++++++++++ .../tracing/tracers/prestate_tracer/mod.rs | 2 + .../tracers/prestate_tracer/state_diff.rs | 138 ++++++ .../tracing/tracers/prestate_tracer/tracer.rs | 71 +++ .../lib/src/tracing/tracers/state_diff.rs | 282 ++++++++++++ .../lib/src/tracing/tracers/struct_logger.rs | 214 +++++---- evm_loader/lib/src/types/mod.rs | 3 +- evm_loader/program/src/error.rs | 4 +- evm_loader/program/src/evm/mod.rs | 122 +++--- evm_loader/program/src/evm/opcode.rs | 114 ++--- evm_loader/program/src/evm/opcode_table.rs | 340 ++++++++------- evm_loader/program/src/evm/tracing.rs | 39 +- 22 files changed, 1819 insertions(+), 454 deletions(-) create mode 100644 evm_loader/lib/src/tracing/tracers/call_tracer.rs create mode 100644 evm_loader/lib/src/tracing/tracers/openeth/mod.rs create mode 100644 evm_loader/lib/src/tracing/tracers/openeth/state_diff.rs create mode 100644 evm_loader/lib/src/tracing/tracers/openeth/tracer.rs create mode 100644 evm_loader/lib/src/tracing/tracers/openeth/types.rs create mode 100644 evm_loader/lib/src/tracing/tracers/prestate_tracer/mod.rs create mode 100644 evm_loader/lib/src/tracing/tracers/prestate_tracer/state_diff.rs create mode 100644 evm_loader/lib/src/tracing/tracers/prestate_tracer/tracer.rs create mode 100644 evm_loader/lib/src/tracing/tracers/state_diff.rs diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index e2792c7b7..fb80fb007 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -3359,6 +3359,7 @@ version = "1.11.0-dev" dependencies = [ "abi_stable", "anyhow", + "arrayref", "async-ffi", "async-trait", "base64 0.22.0", diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 0f6b313f0..3bf6b4d3f 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -44,6 +44,7 @@ strum = "0.26.1" strum_macros = "0.26.1" clap = "2.33.3" lazy_static = "1.4.0" +arrayref = "0.3.6" [build-dependencies] build-info-build = "0.0.31" diff --git a/evm_loader/lib/src/commands/emulate.rs b/evm_loader/lib/src/commands/emulate.rs index 6501b0c82..93fc56f16 100644 --- a/evm_loader/lib/src/commands/emulate.rs +++ b/evm_loader/lib/src/commands/emulate.rs @@ -76,7 +76,7 @@ pub async fn execute( ) .await?; - let step_limit = emulate_request.step_limit.unwrap_or(100000); + let step_limit = emulate_request.step_limit.unwrap_or(100_000); emulate_trx(emulate_request.tx, &mut storage, step_limit, tracer).await } @@ -137,7 +137,7 @@ async fn emulate_trx( result: exit_status.into_result().unwrap_or_default(), iterations, }, - tracer.map(|tracer| tracer.into_traces()), + tracer.map(|tracer| tracer.into_traces(used_gas)), )) } diff --git a/evm_loader/lib/src/commands/trace.rs b/evm_loader/lib/src/commands/trace.rs index 96fdc5c97..dfb2f98fd 100644 --- a/evm_loader/lib/src/commands/trace.rs +++ b/evm_loader/lib/src/commands/trace.rs @@ -18,13 +18,10 @@ pub async fn trace_transaction( .map(|c| c.trace_config.clone()) .unwrap_or_default(); - let tracer = new_tracer(&trace_config)?; + let tracer = new_tracer(&emulate_request.tx, trace_config)?; - let (r, traces) = + let (_, traces) = super::emulate::execute(rpc, program_id, emulate_request, Some(tracer)).await?; - let mut traces = traces.expect("traces should not be None"); - traces["gas"] = r.used_gas.into(); - - Ok(traces) + Ok(traces.expect("traces should not be None")) } diff --git a/evm_loader/lib/src/tracing/mod.rs b/evm_loader/lib/src/tracing/mod.rs index a42ff140c..adbb83878 100644 --- a/evm_loader/lib/src/tracing/mod.rs +++ b/evm_loader/lib/src/tracing/mod.rs @@ -1,9 +1,11 @@ +use std::collections::HashMap; + use ethnum::U256; -use evm_loader::types::Address; use serde_json::Value; -use std::collections::HashMap; use web3::types::Bytes; +use evm_loader::types::Address; + pub mod tracers; /// See @@ -65,6 +67,8 @@ pub struct TraceConfig { pub disable_stack: bool, #[serde(default)] pub enable_return_data: bool, + #[serde(default)] + pub limit: usize, pub tracer: Option, pub timeout: Option, pub tracer_config: Option, diff --git a/evm_loader/lib/src/tracing/tracers/call_tracer.rs b/evm_loader/lib/src/tracing/tracers/call_tracer.rs new file mode 100644 index 000000000..d9b3d2087 --- /dev/null +++ b/evm_loader/lib/src/tracing/tracers/call_tracer.rs @@ -0,0 +1,307 @@ +use crate::tracing::tracers::state_diff::to_web3_u256; +use crate::tracing::tracers::Tracer; +use crate::tracing::TraceConfig; +use crate::types::TxParams; +use async_trait::async_trait; +use evm_loader::error::{format_revert_error, format_revert_panic}; +use evm_loader::evm::database::Database; +use evm_loader::evm::opcode_table::Opcode; +use evm_loader::evm::tracing::{Event, EventListener}; +use evm_loader::evm::{opcode_table, Context, ExitStatus}; +use evm_loader::types::Address; +use lazy_static::lazy_static; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use std::collections::HashMap; +use web3::types::{Bytes, H256, U256}; + +pub struct CallTracer { + config: CallTracerConfig, + call_stack: Vec, + depth: usize, +} + +impl CallTracer { + pub fn new(trace_config: TraceConfig, tx: &TxParams) -> Self { + CallTracer { + config: trace_config.into(), + call_stack: vec![CallFrame { + gas: tx.gas_limit.map(to_web3_u256).unwrap_or_default(), + gas_used: tx.actual_gas_used.map(to_web3_u256).unwrap_or_default(), + ..CallFrame::default() + }], + depth: 0, + } + } +} + +#[derive(Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CallTracerConfig { + #[serde(default)] + pub only_top_call: bool, + // If true, call tracer won't collect any subcalls + #[serde(default)] + pub with_log: bool, // If true, call tracer will collect event logs +} + +impl From for CallTracerConfig { + fn from(trace_config: TraceConfig) -> Self { + let tracer_config = trace_config + .tracer_config + .expect("tracer_config should not be None for \"callTracer\""); + serde_json::from_value(tracer_config).expect("tracer_config should be CallTracerConfig") + } +} + +#[derive(Serialize)] +pub struct CallLog { + address: Address, + topics: Vec, + data: Bytes, + // Position of the log relative to subcalls within the same trace + // See https://github.com/ethereum/go-ethereum/pull/28389 for details + position: U256, +} + +#[derive(Default, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CallFrame { + from: Address, + gas: U256, + gas_used: U256, + #[serde(skip_serializing_if = "Option::is_none")] + to: Option

, + input: Bytes, + #[serde(skip_serializing_if = "is_empty")] + output: Bytes, + #[serde(skip_serializing_if = "String::is_empty")] + error: String, + #[serde(skip_serializing_if = "String::is_empty")] + revert_reason: String, + #[serde(skip_serializing_if = "Vec::is_empty")] + calls: Vec, + #[serde(skip_serializing_if = "Vec::is_empty")] + logs: Vec, + // Placed at end on purpose. The RLP will be decoded to 0 instead of + // nil if there are non-empty elements after in the struct. + #[serde(skip_serializing_if = "Option::is_none")] + value: Option, + #[serde(rename = "type")] + type_string: Opcode, +} + +impl CallFrame { + fn process_output(&mut self, status: ExitStatus) { + if status.is_succeed().unwrap_or_default() { + self.output = status.into_result().unwrap_or_default().into(); + return; + } + + if let ExitStatus::Revert(_) = status { + self.error = "execution reverted".to_string(); + } + + if self.type_string == opcode_table::CREATE || self.type_string == opcode_table::CREATE2 { + self.to = None; + } + + self.output = status.into_result().unwrap_or_default().into(); + self.revert_reason = format_revert_message(&self.output.0); + } + + // clear_failed_logs clears the logs of a callframe and all its children + // in case of execution failure. + fn clear_failed_logs(&mut self, parent_failed: bool) { + let failed = !self.error.is_empty() || parent_failed; + if failed { + self.logs.clear(); + } + for call in &mut self.calls { + call.clear_failed_logs(failed); + } + } +} + +fn format_revert_message(msg: &[u8]) -> String { + if let Some(reason) = format_revert_error(msg) { + return reason.to_string(); + } + + if let Some(reason) = format_revert_panic(msg) { + return get_panic_message(reason); + } + + String::new() +} + +fn get_panic_message(reason: ethnum::U256) -> String { + let reason = reason.as_u64(); + PANIC_REASONS + .get(&reason) + .map(|s| s.to_string()) + .unwrap_or(format!("unknown panic code: {reason:#x}")) +} + +lazy_static! { + // panic_reasons map is for readable panic codes + // see this linkage for the details + // https://docs.soliditylang.org/en/v0.8.21/control-structures.html#panic-via-assert-and-error-via-require + // the reason string list is copied from ethers.js + // https://github.com/ethers-io/ethers.js/blob/fa3a883ff7c88611ce766f58bdd4b8ac90814470/src.ts/abi/interface.ts#L207-L218 + static ref PANIC_REASONS: HashMap = HashMap::from([ + (0x00, "generic panic"), + (0x01, "assert(false)"), + (0x11, "arithmetic underflow or overflow"), + (0x12, "division or modulo by zero"), + (0x21, "enum overflow"), + (0x22, "invalid encoded storage byte array accessed"), + (0x31, "out-of-bounds array access; popping on an empty array"), + (0x32, "out-of-bounds access of an array or bytesN"), + (0x41, "out of memory"), + (0x51, "uninitialized function"), + ]); +} + +fn is_empty(bytes: &Bytes) -> bool { + bytes.0.is_empty() +} + +#[async_trait(?Send)] +impl EventListener for CallTracer { + async fn event( + &mut self, + _executor_state: &impl Database, + event: Event, + ) -> evm_loader::error::Result<()> { + match event { + Event::BeginVM { + context, + opcode, + input, + .. + } => { + self.depth += 1; + self.handle_begin_vm(context, opcode, input); + } + Event::EndVM { status, .. } => { + self.handle_end_vm(status); + self.depth -= 1; + } + Event::BeginStep { + context, + opcode, + stack, + memory, + .. + } => { + // Only logs need to be captured via opcode processing + if !self.config.with_log { + return Ok(()); + } + + // Avoid processing nested calls when only caring about top call + if self.config.only_top_call && self.depth > 1 { + return Ok(()); + } + + match opcode { + opcode_table::LOG0 + | opcode_table::LOG1 + | opcode_table::LOG2 + | opcode_table::LOG3 + | opcode_table::LOG4 => { + let size = (opcode.0 - opcode_table::LOG0.0) as usize; + + let m_start = U256::from(stack[stack.len() - 1]).as_usize(); + let m_size = U256::from(stack[stack.len() - 2]).as_usize(); + + let mut topics = Vec::with_capacity(size); + + for i in 0..size { + topics.push(H256::from(stack[stack.len() - 2 - (i + 1)])); + } + + let call_log = CallLog { + address: context.contract, + topics, + data: memory[m_start..m_start + m_size].to_vec().into(), + position: self.call_stack.last().unwrap().calls.len().into(), + }; + + self.call_stack.last_mut().unwrap().logs.push(call_log); + } + _ => {} + } + } + } + + Ok(()) + } +} + +impl CallTracer { + fn handle_begin_vm(&mut self, context: Context, opcode: Opcode, input: Vec) { + if self.depth == 1 { + let call_frame = &mut self.call_stack[0]; + call_frame.from = context.caller; + call_frame.to = Some(context.contract); + call_frame.input = input.into(); + call_frame.value = Some(to_web3_u256(context.value)); + call_frame.type_string = opcode; + return; + } + + if self.config.only_top_call { + return; + } + + self.call_stack.push(CallFrame { + from: context.caller, + to: Some(context.contract), + input: input.into(), + value: Some(to_web3_u256(context.value)), + type_string: opcode, + ..CallFrame::default() + }) + } + + fn handle_end_vm(&mut self, status: ExitStatus) { + if self.depth == 1 { + self.call_stack[0].process_output(status); + if self.config.with_log { + self.call_stack[0].clear_failed_logs(false); + } + return; + } + + if self.config.only_top_call { + return; + } + + if self.call_stack.len() <= 1 { + return; + } + + let mut call_frame = self.call_stack.pop().unwrap(); + + call_frame.process_output(status); + + self.call_stack.last_mut().unwrap().calls.push(call_frame); + } +} + +impl Tracer for CallTracer { + fn into_traces(mut self, emulator_gas_used: u64) -> Value { + if self.call_stack.len() != 1 { + panic!("incorrect number of top-level calls"); + } + + let call_frame = &mut self.call_stack[0]; + if call_frame.gas_used.is_zero() { + call_frame.gas_used = U256::from(emulator_gas_used); + } + + serde_json::to_value(call_frame).expect("serialization should not fail") + } +} diff --git a/evm_loader/lib/src/tracing/tracers/mod.rs b/evm_loader/lib/src/tracing/tracers/mod.rs index 0f54f6391..cd8cd941c 100644 --- a/evm_loader/lib/src/tracing/tracers/mod.rs +++ b/evm_loader/lib/src/tracing/tracers/mod.rs @@ -1,41 +1,72 @@ +use crate::tracing::tracers::call_tracer::CallTracer; +use crate::tracing::tracers::openeth::tracer::OpenEthereumTracer; +use crate::tracing::tracers::prestate_tracer::tracer::PrestateTracer; use crate::tracing::tracers::struct_logger::StructLogger; use crate::tracing::TraceConfig; +use crate::types::TxParams; +use async_trait::async_trait; +use enum_dispatch::enum_dispatch; use evm_loader::evm::database::Database; -use evm_loader::evm::tracing::{Event, EventListener}; +use evm_loader::evm::tracing::Event; +use evm_loader::evm::tracing::EventListener; use serde_json::Value; +pub mod call_tracer; +pub mod openeth; +pub mod prestate_tracer; +pub mod state_diff; pub mod struct_logger; +#[enum_dispatch(Tracer)] pub enum TracerTypeEnum { StructLogger(StructLogger), + OpenEthereumTracer(OpenEthereumTracer), + PrestateTracer(PrestateTracer), + CallTracer(CallTracer), } +// cannot use enum_dispatch because of trait and enum in different crates +#[async_trait(?Send)] impl EventListener for TracerTypeEnum { - fn event(&mut self, executor_state: &impl Database, event: Event) { + async fn event( + &mut self, + executor_state: &impl Database, + event: Event, + ) -> evm_loader::error::Result<()> { match self { - TracerTypeEnum::StructLogger(struct_logger) => { - struct_logger.event(executor_state, event) - } + TracerTypeEnum::StructLogger(tracer) => tracer.event(executor_state, event).await, + TracerTypeEnum::OpenEthereumTracer(tracer) => tracer.event(executor_state, event).await, + TracerTypeEnum::PrestateTracer(tracer) => tracer.event(executor_state, event).await, + TracerTypeEnum::CallTracer(tracer) => tracer.event(executor_state, event).await, } } } +#[enum_dispatch] pub trait Tracer: EventListener { - fn into_traces(self) -> Value; + fn into_traces(self, emulator_gas_used: u64) -> Value; } -impl Tracer for TracerTypeEnum { - fn into_traces(self) -> Value { - match self { - TracerTypeEnum::StructLogger(struct_logger) => struct_logger.into_traces(), - } - } -} - -pub fn new_tracer(trace_config: &TraceConfig) -> evm_loader::error::Result { +pub fn new_tracer( + tx: &TxParams, + trace_config: TraceConfig, +) -> evm_loader::error::Result { match trace_config.tracer.as_deref() { None | Some("") => Ok(TracerTypeEnum::StructLogger(StructLogger::new( trace_config, + tx, + ))), + Some("openethereum") => Ok(TracerTypeEnum::OpenEthereumTracer(OpenEthereumTracer::new( + trace_config, + tx, + ))), + Some("prestateTracer") => Ok(TracerTypeEnum::PrestateTracer(PrestateTracer::new( + trace_config, + tx, + ))), + Some("callTracer") => Ok(TracerTypeEnum::CallTracer(CallTracer::new( + trace_config, + tx, ))), _ => Err(evm_loader::error::Error::Custom(format!( "Unsupported tracer: {:?}", diff --git a/evm_loader/lib/src/tracing/tracers/openeth/mod.rs b/evm_loader/lib/src/tracing/tracers/openeth/mod.rs new file mode 100644 index 000000000..99c667778 --- /dev/null +++ b/evm_loader/lib/src/tracing/tracers/openeth/mod.rs @@ -0,0 +1,3 @@ +pub mod state_diff; +pub mod tracer; +pub mod types; diff --git a/evm_loader/lib/src/tracing/tracers/openeth/state_diff.rs b/evm_loader/lib/src/tracing/tracers/openeth/state_diff.rs new file mode 100644 index 000000000..7fb825e18 --- /dev/null +++ b/evm_loader/lib/src/tracing/tracers/openeth/state_diff.rs @@ -0,0 +1,72 @@ +use crate::tracing::tracers::state_diff::StateMap; +use std::collections::BTreeMap; +use web3::types::{AccountDiff, ChangedType, Diff, StateDiff, H160, H256}; + +pub fn into_state_diff(state_map: StateMap) -> StateDiff { + let mut state_diff = BTreeMap::new(); + + for (address, states) in state_map.into_iter() { + let pre_account = states.pre; + let post_account = states.post; + + if pre_account.is_empty() { + state_diff.insert( + H160::from(address.as_bytes()), + AccountDiff { + balance: build_diff(None, Some(post_account.balance)), + nonce: build_diff(None, Some(post_account.nonce.into())), + code: build_diff(None, Some(post_account.code.clone())), + storage: storage_diff(&pre_account.storage, &post_account.storage), + }, + ); + } else { + state_diff.insert( + H160::from(address.as_bytes()), + AccountDiff { + balance: build_diff(Some(pre_account.balance), Some(post_account.balance)), + nonce: build_diff( + Some(pre_account.nonce.into()), + Some(post_account.nonce.into()), + ), + code: build_diff( + Some(pre_account.code.clone()), + Some(post_account.code.clone()), + ), + storage: storage_diff(&pre_account.storage, &post_account.storage), + }, + ); + } + } + + StateDiff(state_diff) +} + +fn storage_diff( + account_initial_storage: &BTreeMap, + account_final_storage: &BTreeMap, +) -> BTreeMap> { + let mut storage_diff = BTreeMap::new(); + + for (key, initial_value) in account_initial_storage { + let final_value = account_final_storage.get(key).cloned(); + + storage_diff.insert(*key, build_diff(Some(*initial_value), final_value)); + } + + storage_diff +} + +fn build_diff(from: Option, to: Option) -> Diff { + match (from, to) { + (None, Some(to)) => Diff::Born(to), + (None, None) => Diff::Same, + (Some(from), None) => Diff::Died(from), + (Some(from), Some(to)) => { + if from == to { + Diff::Same + } else { + Diff::Changed(ChangedType { from, to }) + } + } + } +} diff --git a/evm_loader/lib/src/tracing/tracers/openeth/tracer.rs b/evm_loader/lib/src/tracing/tracers/openeth/tracer.rs new file mode 100644 index 000000000..135eecaae --- /dev/null +++ b/evm_loader/lib/src/tracing/tracers/openeth/tracer.rs @@ -0,0 +1,72 @@ +use async_trait::async_trait; + +use evm_loader::evm::database::Database; +use serde_json::Value; +use web3::types::Bytes; + +use evm_loader::evm::tracing::{Event, EventListener}; + +use crate::tracing::tracers::openeth::state_diff::into_state_diff; +use crate::tracing::tracers::openeth::types::{CallAnalytics, TraceResults}; +use crate::tracing::tracers::state_diff::StateDiffTracer; +use crate::tracing::tracers::Tracer; +use crate::tracing::TraceConfig; +use crate::types::TxParams; + +pub struct OpenEthereumTracer { + output: Option, + call_analytics: CallAnalytics, + state_diff_tracer: StateDiffTracer, +} + +impl OpenEthereumTracer { + #[must_use] + pub fn new(trace_config: TraceConfig, tx: &TxParams) -> Self { + OpenEthereumTracer { + output: None, + call_analytics: trace_config.into(), + state_diff_tracer: StateDiffTracer::new(tx), + } + } +} + +impl From for CallAnalytics { + fn from(trace_config: TraceConfig) -> Self { + let tracer_config = trace_config + .tracer_config + .expect("tracer_config should not be None for \"openethereum\" tracer"); + serde_json::from_value(tracer_config).expect("tracer_config should be CallAnalytics") + } +} + +#[async_trait(?Send)] +impl EventListener for OpenEthereumTracer { + async fn event( + &mut self, + executor_state: &impl Database, + event: Event, + ) -> evm_loader::error::Result<()> { + if let Event::EndVM { status, .. } = &event { + self.output = status.clone().into_result().map(Into::into); + } + self.state_diff_tracer.event(executor_state, event).await + } +} + +impl Tracer for OpenEthereumTracer { + fn into_traces(self, emulator_gas_used: u64) -> Value { + serde_json::to_value(TraceResults { + output: self.output.unwrap_or_default(), + trace: vec![], + vm_trace: None, + state_diff: if self.call_analytics.state_diffing { + Some(into_state_diff( + self.state_diff_tracer.into_state_map(emulator_gas_used), + )) + } else { + None + }, + }) + .expect("serialization should not fail") + } +} diff --git a/evm_loader/lib/src/tracing/tracers/openeth/types.rs b/evm_loader/lib/src/tracing/tracers/openeth/types.rs new file mode 100644 index 000000000..e2d438ac1 --- /dev/null +++ b/evm_loader/lib/src/tracing/tracers/openeth/types.rs @@ -0,0 +1,406 @@ +/// Types copied from +use std::fmt; + +use serde::ser::SerializeStruct; +use serde::{Deserialize, Serialize, Serializer}; +use web3::types::{Bytes, StateDiff, H160, U256}; + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +/// A diff of some chunk of memory. +pub struct TraceResults { + /// The output of the call/create + pub output: Bytes, + /// The transaction trace. + pub state_diff: Option, + /// The transaction trace. + pub trace: Vec, + /// The transaction trace. + pub vm_trace: Option, +} + +/// Trace +#[derive(Debug, Clone)] +pub struct Trace { + /// Trace address + trace_address: Vec, + /// Subtraces + subtraces: usize, + /// Action + action: Action, + /// Result + result: Res, +} + +impl Serialize for Trace { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut struc = serializer.serialize_struct("Trace", 4)?; + match self.action { + Action::Call(ref call) => { + struc.serialize_field("type", "call")?; + struc.serialize_field("action", call)?; + } + Action::Create(ref create) => { + struc.serialize_field("type", "create")?; + struc.serialize_field("action", create)?; + } + Action::Suicide(ref suicide) => { + struc.serialize_field("type", "suicide")?; + struc.serialize_field("action", suicide)?; + } + Action::Reward(ref reward) => { + struc.serialize_field("type", "reward")?; + struc.serialize_field("action", reward)?; + } + } + + match self.result { + Res::Call(ref call) => struc.serialize_field("result", call)?, + Res::Create(ref create) => struc.serialize_field("result", create)?, + Res::FailedCall(ref error) | Res::FailedCreate(ref error) => { + struc.serialize_field("error", &error.to_string())?; + } + Res::None => struc.serialize_field("result", &None as &Option)?, + } + + struc.serialize_field("traceAddress", &self.trace_address)?; + struc.serialize_field("subtraces", &self.subtraces)?; + + struc.end() + } +} + +/// Action +#[derive(Debug, Clone)] +pub enum Action { + /// Call + Call(Call), + /// Create + Create(Create), + /// Suicide + Suicide(Suicide), + /// Reward + Reward(Reward), +} + +/// Call response +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Call { + /// Sender + from: H160, + /// Recipient + to: H160, + /// Transfered Value + value: U256, + /// Gas + gas: U256, + /// Input data + input: Bytes, + /// The type of the call. + call_type: CallType, +} + +/// Call type. +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "lowercase")] +pub enum CallType { + /// None + None, + /// Call + Call, + /// Call code + CallCode, + /// Delegate call + DelegateCall, + /// Static call + StaticCall, +} + +/// Create response +#[derive(Debug, Clone, Serialize)] +pub struct Create { + /// Sender + from: H160, + /// Value + value: U256, + /// Gas + gas: U256, + /// Initialization code + init: Bytes, +} + +/// Suicide +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Suicide { + /// Address. + pub address: H160, + /// Refund address. + pub refund_address: H160, + /// Balance. + pub balance: U256, +} + +/// Reward action +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Reward { + /// Author's address. + pub author: H160, + /// Reward amount. + pub value: U256, + /// Reward type. + pub reward_type: RewardType, +} + +/// Reward type. +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub enum RewardType { + /// Block + Block, + /// Uncle + Uncle, + /// EmptyStep (AuthorityRound) + EmptyStep, + /// External (attributed as part of an external protocol) + External, +} + +#[derive(Debug, Clone, Serialize)] +/// A record of a full VM trace for a CALL/CREATE. +pub struct VMTrace { + /// The code to be executed. + pub code: Bytes, + /// The operations executed. + pub ops: Vec, +} + +#[derive(Debug, Clone, Serialize)] +/// A record of the execution of a single VM operation. +pub struct VMOperation { + /// The program counter. + pub pc: usize, + /// The gas cost for this instruction. + pub cost: u64, + /// Information concerning the execution of the operation. + pub ex: Option, + /// Subordinate trace of the CALL/CREATE if applicable. + #[serde(bound = "VMTrace: Serialize")] + pub sub: Option, +} + +#[derive(Debug, Clone, Serialize)] +/// A record of an executed VM operation. +pub struct VMExecutedOperation { + /// The total gas used. + pub used: u64, + /// The stack item placed, if any. + pub push: Vec, + /// If altered, the memory delta. + pub mem: Option, + /// The altered storage value, if any. + pub store: Option, +} + +#[derive(Debug, Clone, Serialize)] +/// A diff of some chunk of memory. +pub struct MemoryDiff { + /// Offset into memory the change begins. + pub off: usize, + /// The changed data. + pub data: Bytes, +} + +#[derive(Debug, Clone, Serialize)] +/// A diff of some storage value. +pub struct StorageDiff { + /// Which key in storage is changed. + pub key: U256, + /// What the value has been changed to. + pub val: U256, +} + +#[derive(Debug, Clone)] +pub enum Res { + /// Call + Call(CallResult), + /// Create + Create(CreateResult), + /// Call failure + FailedCall(TraceError), + /// Creation failure + FailedCreate(TraceError), + /// None + None, +} + +/// Call Result +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CallResult { + /// Gas used + gas_used: U256, + /// Output bytes + output: Bytes, +} + +/// Create Result +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CreateResult { + /// Gas used + gas_used: U256, + /// Code + code: Bytes, + /// Assigned address + address: H160, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum TraceError { + /// `OutOfGas` is returned when transaction execution runs out of gas. + OutOfGas, + /// `BadJumpDestination` is returned when execution tried to move + /// to position that wasn't marked with JUMPDEST instruction + BadJumpDestination, + /// `BadInstructions` is returned when given instruction is not supported + BadInstruction, + /// `StackUnderflow` when there is not enough stack elements to execute instruction + StackUnderflow, + /// When execution would exceed defined Stack Limit + OutOfStack, + /// When there is not enough subroutine stack elements to return from + SubStackUnderflow, + /// When execution would exceed defined subroutine Stack Limit + OutOfSubStack, + /// When the code walks into a subroutine, that is not allowed + InvalidSubEntry, + /// When builtin contract failed on input data + BuiltIn, + /// Returned on evm internal error. Should never be ignored during development. + /// Likely to cause consensus issues. + Internal, + /// When execution tries to modify the state in static context + MutableCallInStaticContext, + /// When invalid code was attempted to deploy + InvalidCode, + /// Wasm error + Wasm, + /// Contract tried to access past the return data buffer. + OutOfBounds, + /// Execution has been reverted with REVERT instruction. + Reverted, +} + +impl fmt::Display for TraceError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::TraceError::{ + BadInstruction, BadJumpDestination, BuiltIn, Internal, InvalidCode, InvalidSubEntry, + MutableCallInStaticContext, OutOfBounds, OutOfGas, OutOfStack, OutOfSubStack, Reverted, + StackUnderflow, SubStackUnderflow, Wasm, + }; + let message = match *self { + OutOfGas => "Out of gas", + BadJumpDestination => "Bad jump destination", + BadInstruction => "Bad instruction", + StackUnderflow => "Stack underflow", + OutOfStack => "Out of stack", + SubStackUnderflow => "Subroutine stack underflow", + OutOfSubStack => "Subroutine stack overflow", + BuiltIn => "Built-in failed", + InvalidSubEntry => "Invalid subroutine entry", + InvalidCode => "Invalid code", + Wasm => "Wasm runtime error", + Internal => "Internal error", + MutableCallInStaticContext => "Mutable Call In Static Context", + OutOfBounds => "Out of bounds", + Reverted => "Reverted", + }; + message.fmt(f) + } +} + +pub type TraceOptions = Vec; + +#[must_use] +pub fn to_call_analytics(flags: &TraceOptions) -> CallAnalytics { + CallAnalytics { + transaction_tracing: flags.contains(&("trace".to_owned())), + vm_tracing: flags.contains(&("vmTrace".to_owned())), + state_diffing: flags.contains(&("stateDiff".to_owned())), + } +} + +/// Options concerning what analytics we run on the call. +#[derive(Eq, PartialEq, Default, Clone, Copy, Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CallAnalytics { + /// Make a transaction trace. + pub transaction_tracing: bool, + /// Make a VM trace. + pub vm_tracing: bool, + /// Make a diff. + pub state_diffing: bool, +} + +#[cfg(test)] +mod tests { + use serde_json; + + use super::*; + + #[test] + fn test_vmtrace_serialize() { + let t = VMTrace { + code: vec![0, 1, 2, 3].into(), + ops: vec![ + VMOperation { + pc: 0, + cost: 10, + ex: None, + sub: None, + }, + VMOperation { + pc: 1, + cost: 11, + ex: Some(VMExecutedOperation { + used: 10, + push: vec![69.into()], + mem: None, + store: None, + }), + sub: Some(VMTrace { + code: vec![0].into(), + ops: vec![VMOperation { + pc: 0, + cost: 0, + ex: Some(VMExecutedOperation { + used: 10, + push: vec![42.into()], + mem: Some(MemoryDiff { + off: 42, + data: vec![1, 2, 3].into(), + }), + store: Some(StorageDiff { + key: 69.into(), + val: 42.into(), + }), + }), + sub: None, + }], + }), + }, + ], + }; + let serialized = serde_json::to_string(&t).unwrap(); + assert_eq!( + serialized, + r#"{"code":"0x00010203","ops":[{"pc":0,"cost":10,"ex":null,"sub":null},{"pc":1,"cost":11,"ex":{"used":10,"push":["0x45"],"mem":null,"store":null},"sub":{"code":"0x00","ops":[{"pc":0,"cost":0,"ex":{"used":10,"push":["0x2a"],"mem":{"off":42,"data":"0x010203"},"store":{"key":"0x45","val":"0x2a"}},"sub":null}]}}]}"# + ); + } +} diff --git a/evm_loader/lib/src/tracing/tracers/prestate_tracer/mod.rs b/evm_loader/lib/src/tracing/tracers/prestate_tracer/mod.rs new file mode 100644 index 000000000..a18ea1d3c --- /dev/null +++ b/evm_loader/lib/src/tracing/tracers/prestate_tracer/mod.rs @@ -0,0 +1,2 @@ +mod state_diff; +pub mod tracer; diff --git a/evm_loader/lib/src/tracing/tracers/prestate_tracer/state_diff.rs b/evm_loader/lib/src/tracing/tracers/prestate_tracer/state_diff.rs new file mode 100644 index 000000000..d070aee9f --- /dev/null +++ b/evm_loader/lib/src/tracing/tracers/prestate_tracer/state_diff.rs @@ -0,0 +1,138 @@ +use std::collections::BTreeMap; + +use serde::{Deserialize, Serialize}; +use web3::types::{Bytes, H256, U256}; + +use crate::tracing::tracers::state_diff::StateMap; +use evm_loader::types::Address; + +/// See +type PrestateTracerState = BTreeMap; + +/// See +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct PrestateTracerAccount { + #[serde(skip_serializing_if = "Option::is_none")] + pub balance: Option, + #[serde(skip_serializing_if = "is_empty")] + pub code: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub nonce: Option, + #[serde(skip_serializing_if = "BTreeMap::is_empty")] + pub storage: BTreeMap, +} + +fn is_empty(bytes: &Option) -> bool { + match bytes { + None => true, + Some(bytes) => bytes.0.is_empty(), + } +} + +/// See +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct PrestateTracerDiffModeResult { + pub post: PrestateTracerState, + pub pre: PrestateTracerState, +} + +pub fn build_prestate_tracer_pre_state(state_map: StateMap) -> PrestateTracerState { + let mut result = BTreeMap::new(); + + for (address, states) in state_map { + let pre_account = states.pre; + + if pre_account.is_empty() { + continue; + } + + result.insert( + address, + PrestateTracerAccount { + balance: Some(pre_account.balance), + code: Some(pre_account.code), + nonce: Some(pre_account.nonce), + storage: pre_account.storage, + }, + ); + } + + result +} + +/// See +pub fn build_prestate_tracer_diff_mode_result(state_map: StateMap) -> PrestateTracerDiffModeResult { + let mut pre = build_prestate_tracer_pre_state(state_map.clone()); + + let mut post = BTreeMap::new(); + + for (address, states) in state_map { + let pre_account = states.pre; + let post_account = states.post; + + let mut modified = false; + + let balance = if post_account.balance != pre_account.balance { + modified = true; + Some(post_account.balance) + } else { + None + }; + + let code = if post_account.code != pre_account.code { + modified = true; + Some(post_account.code.clone()) + } else { + None + }; + + let nonce = if post_account.nonce != pre_account.nonce { + modified = true; + Some(post_account.nonce) + } else { + None + }; + + let mut storage = BTreeMap::new(); + + for (key, initial_value) in pre_account.storage { + // don't include the empty slot + if initial_value == H256::zero() { + pre.entry(address).and_modify(|account| { + account.storage.remove(&key); + }); + } + + let final_value = post_account.storage.get(&key).cloned().unwrap_or_default(); + + // Omit unchanged slots + if initial_value == final_value { + pre.entry(address).and_modify(|account| { + account.storage.remove(&key); + }); + } else { + modified = true; + if final_value != H256::zero() { + storage.insert(key, final_value); + } + } + } + + if modified { + post.insert( + address, + PrestateTracerAccount { + balance, + code, + nonce, + storage, + }, + ); + } else { + // if state is not modified, then no need to include into the pre state + pre.remove(&address); + } + } + + PrestateTracerDiffModeResult { post, pre } +} diff --git a/evm_loader/lib/src/tracing/tracers/prestate_tracer/tracer.rs b/evm_loader/lib/src/tracing/tracers/prestate_tracer/tracer.rs new file mode 100644 index 000000000..75857bba5 --- /dev/null +++ b/evm_loader/lib/src/tracing/tracers/prestate_tracer/tracer.rs @@ -0,0 +1,71 @@ +use crate::tracing::tracers::prestate_tracer::state_diff::{ + build_prestate_tracer_diff_mode_result, build_prestate_tracer_pre_state, +}; +use crate::tracing::tracers::state_diff::StateDiffTracer; +use crate::tracing::tracers::Tracer; +use crate::tracing::TraceConfig; +use crate::types::TxParams; +use async_trait::async_trait; +use evm_loader::evm::database::Database; +use evm_loader::evm::tracing::{Event, EventListener}; +use serde::{Deserialize, Serialize}; +use serde_json::Value; + +/// See +pub struct PrestateTracer { + config: PrestateTracerConfig, + state_diff_tracer: StateDiffTracer, +} + +impl PrestateTracer { + pub fn new(trace_config: TraceConfig, tx: &TxParams) -> Self { + PrestateTracer { + config: trace_config.into(), + state_diff_tracer: StateDiffTracer::new(tx), + } + } +} + +impl From for PrestateTracerConfig { + fn from(trace_config: TraceConfig) -> Self { + trace_config + .tracer_config + .map(|tracer_config| { + serde_json::from_value(tracer_config) + .expect("tracer_config should be PrestateTracerConfig") + }) + .unwrap_or_default() + } +} + +/// See +#[derive(Serialize, Deserialize, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct PrestateTracerConfig { + #[serde(default)] + pub diff_mode: bool, +} + +#[async_trait(?Send)] +impl EventListener for PrestateTracer { + async fn event( + &mut self, + executor_state: &impl Database, + event: Event, + ) -> evm_loader::error::Result<()> { + self.state_diff_tracer.event(executor_state, event).await + } +} + +impl Tracer for PrestateTracer { + fn into_traces(self, emulator_gas_used: u64) -> Value { + let state_map = self.state_diff_tracer.into_state_map(emulator_gas_used); + + if self.config.diff_mode { + serde_json::to_value(build_prestate_tracer_diff_mode_result(state_map)) + } else { + serde_json::to_value(build_prestate_tracer_pre_state(state_map)) + } + .expect("serialization should not fail") + } +} diff --git a/evm_loader/lib/src/tracing/tracers/state_diff.rs b/evm_loader/lib/src/tracing/tracers/state_diff.rs new file mode 100644 index 000000000..6fd1571af --- /dev/null +++ b/evm_loader/lib/src/tracing/tracers/state_diff.rs @@ -0,0 +1,282 @@ +use arrayref::array_ref; +use async_trait::async_trait; +use std::collections::btree_map::Entry; +use std::collections::BTreeMap; + +use ethnum::U256; +use web3::types::{Bytes, H256}; + +use crate::types::TxParams; +use evm_loader::evm::database::Database; +use evm_loader::evm::tracing::{Event, EventListener}; +use evm_loader::evm::{opcode_table, Buffer}; +use evm_loader::types::Address; +use serde::{Deserialize, Serialize}; + +pub type StateMap = BTreeMap; + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct Account { + pub balance: web3::types::U256, + pub code: Bytes, + pub nonce: u64, + pub storage: BTreeMap, +} + +impl Account { + pub fn is_empty(&self) -> bool { + self.balance.is_zero() && self.nonce == 0 && self.code.0.is_empty() + } +} + +// TODO NDEV-2451 - Add operator balance diff to pre and post state +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct States { + pub post: Account, + pub pre: Account, +} + +fn map_code(buffer: Buffer) -> Bytes { + buffer.to_vec().into() +} + +pub(crate) fn to_web3_u256(v: U256) -> web3::types::U256 { + web3::types::U256::from(v.to_be_bytes()) +} + +#[derive(Default, Debug)] +pub struct StateDiffTracer { + from: Address, + gas_price: web3::types::U256, + tx_fee: web3::types::U256, + depth: usize, + state_map: StateMap, +} + +#[async_trait(?Send)] +impl EventListener for StateDiffTracer { + /// See + async fn event( + &mut self, + executor_state: &impl Database, + event: Event, + ) -> evm_loader::error::Result<()> { + match event { + Event::BeginVM { + context, + chain_id, + opcode, + .. + } => { + self.depth += 1; + + if self.depth == 1 { + self.lookup_account(executor_state, chain_id, context.caller) + .await?; + self.lookup_account(executor_state, chain_id, context.contract) + .await?; + + let value = to_web3_u256(context.value); + + self.state_map + .entry(context.caller) + .or_default() + .pre + .balance += value; + + self.state_map + .entry(context.contract) + .or_default() + .pre + .balance -= value; + + self.state_map.entry(context.caller).or_default().pre.nonce -= 1; + + if opcode == opcode_table::CREATE { + self.state_map + .entry(context.contract) + .or_default() + .pre + .nonce -= 1; + } + } + } + Event::EndVM { + context, chain_id, .. + } => { + if self.depth == 1 { + for (address, states) in &mut self.state_map { + states.post = Account { + balance: to_web3_u256( + executor_state.balance(*address, chain_id).await?, + ), + code: map_code(executor_state.code(*address).await?), + nonce: executor_state.nonce(*address, chain_id).await?, + storage: { + let mut new_storage = BTreeMap::new(); + + for key in states.pre.storage.keys() { + new_storage.insert( + *key, + H256::from( + executor_state + .storage( + *address, + U256::from_be_bytes(key.to_fixed_bytes()), + ) + .await?, + ), + ); + } + + new_storage + }, + }; + } + + self.state_map + .entry(context.caller) + .or_default() + .post + .balance -= self.tx_fee; + } + + self.depth -= 1; + } + Event::BeginStep { + context, + chain_id, + opcode, + stack, + memory, + .. + } => { + let contract = context.contract; + match opcode { + opcode_table::SLOAD | opcode_table::SSTORE if !stack.is_empty() => { + let index = H256::from(&stack[stack.len() - 1]); + self.lookup_storage(executor_state, contract, index).await?; + } + opcode_table::EXTCODECOPY + | opcode_table::EXTCODEHASH + | opcode_table::EXTCODESIZE + | opcode_table::BALANCE + | opcode_table::SELFDESTRUCT + if !stack.is_empty() => + { + let address = Address::from(*array_ref!(stack[stack.len() - 1], 12, 20)); + self.lookup_account(executor_state, chain_id, address) + .await?; + } + opcode_table::DELEGATECALL + | opcode_table::CALL + | opcode_table::STATICCALL + | opcode_table::CALLCODE + if stack.len() >= 5 => + { + let address = Address::from(*array_ref!(stack[stack.len() - 2], 12, 20)); + self.lookup_account(executor_state, chain_id, address) + .await?; + } + opcode_table::CREATE => { + let nonce = executor_state + .nonce(contract, context.contract_chain_id) + .await?; + + let created_address = Address::from_create(&contract, nonce); + self.lookup_account(executor_state, chain_id, created_address) + .await?; + } + opcode_table::CREATE2 if stack.len() >= 4 => { + let offset = U256::from_be_bytes(stack[stack.len() - 2]).as_usize(); + let length = U256::from_be_bytes(stack[stack.len() - 3]).as_usize(); + let salt = stack[stack.len() - 4]; + + let initialization_code = &memory[offset..offset + length]; + let created_address = + Address::from_create2(&contract, &salt, initialization_code); + self.lookup_account(executor_state, chain_id, created_address) + .await?; + } + _ => {} + } + } + } + Ok(()) + } +} + +impl StateDiffTracer { + pub fn new(tx: &TxParams) -> Self { + StateDiffTracer { + from: tx.from, + gas_price: tx.gas_price.map(to_web3_u256).unwrap_or_default(), + tx_fee: to_web3_u256( + tx.actual_gas_used + .unwrap_or_default() + .saturating_mul(tx.gas_price.unwrap_or_default()), + ), + ..StateDiffTracer::default() + } + } + + /// See + async fn lookup_account( + &mut self, + executor_state: &impl Database, + chain_id: u64, + address: Address, + ) -> evm_loader::error::Result<()> { + match self.state_map.entry(address) { + Entry::Vacant(entry) => { + entry.insert(States { + post: Default::default(), + pre: Account { + balance: to_web3_u256(executor_state.balance(address, chain_id).await?), + code: map_code(executor_state.code(address).await?), + nonce: executor_state.nonce(address, chain_id).await?, + storage: BTreeMap::new(), + }, + }); + } + Entry::Occupied(_) => {} + }; + Ok(()) + } + + /// See + async fn lookup_storage( + &mut self, + executor_state: &impl Database, + address: Address, + index: H256, + ) -> evm_loader::error::Result<()> { + match self + .state_map + .entry(address) + .or_default() + .pre + .storage + .entry(index) + { + Entry::Vacant(entry) => { + entry.insert(H256::from( + executor_state + .storage(address, U256::from_be_bytes(index.to_fixed_bytes())) + .await?, + )); + } + Entry::Occupied(_) => {} + }; + Ok(()) + } + + pub fn into_state_map(mut self, emulator_gas_used: u64) -> StateMap { + if self.tx_fee.is_zero() { + self.state_map.entry(self.from).or_default().post.balance -= + web3::types::U256::from(emulator_gas_used).saturating_mul(self.gas_price); + } + + self.state_map + } +} diff --git a/evm_loader/lib/src/tracing/tracers/struct_logger.rs b/evm_loader/lib/src/tracing/tracers/struct_logger.rs index e8d23c922..825153ca2 100644 --- a/evm_loader/lib/src/tracing/tracers/struct_logger.rs +++ b/evm_loader/lib/src/tracing/tracers/struct_logger.rs @@ -1,44 +1,48 @@ +use async_trait::async_trait; use std::collections::BTreeMap; use ethnum::U256; use evm_loader::evm::database::Database; -use evm_loader::evm::ExitStatus; use serde::Serialize; use serde_json::Value; use web3::types::Bytes; +use evm_loader::evm::opcode_table::Opcode; +use evm_loader::evm::tracing::{Event, EventListener}; +use evm_loader::evm::{opcode_table, ExitStatus}; +use evm_loader::types::Address; + use crate::tracing::tracers::Tracer; use crate::tracing::TraceConfig; -use evm_loader::evm::opcode_table::OPNAMES; -use evm_loader::evm::tracing::{Event, EventListener}; +use crate::types::TxParams; /// `StructLoggerResult` groups all structured logs emitted by the EVM /// while replaying a transaction in debug mode as well as transaction /// execution status, the amount of gas used and the return value /// see -#[derive(Serialize, Debug, Clone)] +#[derive(Serialize)] #[serde(rename_all = "camelCase")] -pub struct StructLoggerResult { +struct StructLoggerResult { /// Total used gas but include the refunded gas - pub gas: u64, + gas: u64, /// Is execution failed or not - pub failed: bool, + failed: bool, /// The data after execution or revert reason - pub return_value: String, + return_value: String, /// Logs emitted during execution - pub struct_logs: Vec, + struct_logs: Vec, } /// `StructLog` stores a structured log emitted by the EVM while replaying a /// transaction in debug mode /// see -#[derive(Serialize, Debug, Clone)] +#[derive(Serialize)] #[serde(rename_all = "camelCase")] -pub struct StructLog { +struct StructLog { /// Program counter. pc: u64, /// Operation name - op: &'static str, + op: Opcode, /// Amount of used gas gas: u64, /// Gas cost for this instruction. @@ -50,8 +54,8 @@ pub struct StructLog { /// Snapshot of the current stack sate #[serde(skip_serializing_if = "Option::is_none")] stack: Option>, - #[serde(skip_serializing_if = "Option::is_none")] - return_data: Option, + #[serde(skip_serializing_if = "is_empty")] + return_data: Bytes, /// Snapshot of the current memory sate #[serde(skip_serializing_if = "Option::is_none")] memory: Option>, // chunks of 32 bytes @@ -64,108 +68,108 @@ pub struct StructLog { refund: u64, } +fn is_empty(bytes: &Bytes) -> bool { + bytes.0.is_empty() +} + /// This is only used for serialize #[allow(clippy::trivially_copy_pass_by_ref)] fn is_zero(num: &u64) -> bool { *num == 0 } -impl StructLog { - #[must_use] - pub fn new( - opcode: u8, - pc: u64, - gas_cost: u64, - depth: usize, - memory: Option>, - stack: Option>, - ) -> Self { - let op = OPNAMES[opcode as usize]; - Self { - pc, - op, - gas: 0, - gas_cost, - depth, - memory, - stack, - return_data: None, - storage: None, - error: None, - refund: 0, - } - } -} - -#[derive(Debug)] -#[allow(clippy::struct_excessive_bools)] -struct Config { - enable_memory: bool, - disable_storage: bool, - disable_stack: bool, - enable_return_data: bool, -} - -impl From<&TraceConfig> for Config { - fn from(trace_config: &TraceConfig) -> Self { - Self { - enable_memory: trace_config.enable_memory, - disable_storage: trace_config.disable_storage, - disable_stack: trace_config.disable_stack, - enable_return_data: trace_config.enable_return_data, - } - } -} - -#[derive(Debug)] pub struct StructLogger { - config: Config, + actual_gas_used: Option, + config: TraceConfig, logs: Vec, depth: usize, - storage_access: Option<(U256, U256)>, + storage: BTreeMap>, exit_status: Option, } impl StructLogger { #[must_use] - pub fn new(trace_config: &TraceConfig) -> Self { + pub fn new(config: TraceConfig, tx: &TxParams) -> Self { StructLogger { - config: trace_config.into(), + actual_gas_used: tx.actual_gas_used, + config, logs: vec![], depth: 0, - storage_access: None, + storage: BTreeMap::new(), exit_status: None, } } } +#[async_trait(?Send)] impl EventListener for StructLogger { - fn event(&mut self, _executor_state: &impl Database, event: Event) { + /// See + async fn event( + &mut self, + executor_state: &impl Database, + event: Event, + ) -> evm_loader::error::Result<()> { match event { Event::BeginVM { .. } => { self.depth += 1; } - Event::EndVM { status } => { + Event::EndVM { status, .. } => { if self.depth == 1 { self.exit_status = Some(status); } self.depth -= 1; } Event::BeginStep { + context, opcode, pc, stack, memory, + return_data, + .. } => { + if self.config.limit > 0 && self.logs.len() >= self.config.limit { + return Ok(()); + } + + let storage = if !self.config.disable_storage { + if opcode == opcode_table::SLOAD && !stack.is_empty() { + let index = U256::from_be_bytes(stack[stack.len() - 1]); + + self.storage.entry(context.contract).or_default().insert( + hex::encode(index.to_be_bytes()), + hex::encode(executor_state.storage(context.contract, index).await?), + ); + + Some( + self.storage + .get(&context.contract) + .cloned() + .unwrap_or_default(), + ) + } else if opcode == opcode_table::SSTORE && stack.len() >= 2 { + self.storage.entry(context.contract).or_default().insert( + hex::encode(stack[stack.len() - 1]), + hex::encode(stack[stack.len() - 2]), + ); + + Some( + self.storage + .get(&context.contract) + .cloned() + .unwrap_or_default(), + ) + } else { + None + } + } else { + None + }; + let stack = if self.config.disable_stack { None } else { - Some( - stack - .iter() - .map(|entry| U256::from_be_bytes(*entry)) - .collect(), - ) + Some(stack.into_iter().map(U256::from_be_bytes).collect()) }; let memory = if self.config.enable_memory { @@ -174,44 +178,30 @@ impl EventListener for StructLogger { None }; - let log = StructLog::new(opcode, pc as u64, 0, self.depth, memory, stack); - self.logs.push(log); - } - Event::EndStep { - gas_used, - return_data, - } => { - let last = self - .logs - .last_mut() - .expect("`EndStep` event before `BeginStep`"); - last.gas = gas_used; - if !self.config.disable_storage { - if let Some((index, value)) = self.storage_access.take() { - last.storage.get_or_insert_with(Default::default).insert( - hex::encode(index.to_be_bytes()), - hex::encode(value.to_be_bytes()), - ); - }; - } - if self.config.enable_return_data { - last.return_data = return_data.map(Into::into); - } - } - Event::StorageAccess { index, value } => { - if !self.config.disable_storage { - self.storage_access = Some((index, U256::from_be_bytes(value))); - } + self.logs.push(StructLog { + pc: pc as u64, + op: opcode, + gas: 0, + gas_cost: 0, + depth: self.depth, + memory, + stack, + return_data: return_data.into(), + storage, + error: None, + refund: 0, + }); } }; + Ok(()) } } impl Tracer for StructLogger { - fn into_traces(self) -> Value { - let exit_status = self.exit_status.expect("Emulation is not completed"); + fn into_traces(self, emulator_gas_used: u64) -> Value { + let exit_status = self.exit_status.expect("Exit status should be set"); let result = StructLoggerResult { - gas: 0, + gas: self.actual_gas_used.map_or(emulator_gas_used, U256::as_u64), failed: !exit_status .is_succeed() .expect("Emulation is not completed"), @@ -235,7 +225,7 @@ mod tests { .to_string(), struct_logs: vec![StructLog { pc: 8, - op: "PUSH2", + op: opcode_table::PUSH2, gas: 0, gas_cost: 0, depth: 1, @@ -245,7 +235,7 @@ mod tests { "0000000000000000000000000000000000000000000000000000000000000000".to_string(), "0000000000000000000000000000000000000000000000000000000000000080".to_string(), ]), - return_data: None, + return_data: vec![].into(), storage: None, refund: 0, error: None, @@ -263,13 +253,13 @@ mod tests { .to_string(), struct_logs: vec![StructLog { pc: 0, - op: "PUSH1", + op: opcode_table::PUSH1, gas: 0, gas_cost: 0, depth: 1, stack: None, memory: None, - return_data: None, + return_data: vec![].into(), storage: None, refund: 0, error: None, @@ -287,13 +277,13 @@ mod tests { .to_string(), struct_logs: vec![StructLog { pc: 0, - op: "PUSH1", + op: opcode_table::PUSH1, gas: 0, gas_cost: 0, depth: 1, stack: Some(vec![]), memory: Some(vec![]), - return_data: None, + return_data: vec![].into(), storage: None, refund: 0, error: None, diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index 904ed772f..f60c9d051 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -37,7 +37,7 @@ pub struct AccessListItem { #[serde_as] #[skip_serializing_none] -#[derive(Clone, Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize, Default)] pub struct TxParams { pub nonce: Option, pub from: Address, @@ -46,6 +46,7 @@ pub struct TxParams { pub data: Option>, pub value: Option, pub gas_limit: Option, + pub actual_gas_used: Option, pub gas_price: Option, pub access_list: Option>, pub chain_id: Option, diff --git a/evm_loader/program/src/error.rs b/evm_loader/program/src/error.rs index c0afb84f7..22e79f95b 100644 --- a/evm_loader/program/src/error.rs +++ b/evm_loader/program/src/error.rs @@ -228,7 +228,7 @@ macro_rules! Err { } #[must_use] -fn format_revert_error(msg: &[u8]) -> Option<&str> { +pub fn format_revert_error(msg: &[u8]) -> Option<&str> { if msg.starts_with(&[0x08, 0xc3, 0x79, 0xa0]) { // Error(string) function selector let msg = &msg[4..]; @@ -255,7 +255,7 @@ fn format_revert_error(msg: &[u8]) -> Option<&str> { } #[must_use] -fn format_revert_panic(msg: &[u8]) -> Option { +pub fn format_revert_panic(msg: &[u8]) -> Option { if msg.starts_with(&[0x4e, 0x48, 0x7b, 0x71]) { // Panic(uint256) function selector let msg = &msg[4..]; diff --git a/evm_loader/program/src/evm/mod.rs b/evm_loader/program/src/evm/mod.rs index d26a722cf..295ca5d16 100644 --- a/evm_loader/program/src/evm/mod.rs +++ b/evm_loader/program/src/evm/mod.rs @@ -33,44 +33,74 @@ pub mod tracing; mod utils; macro_rules! tracing_event { - ($self:ident, $backend:ident, $x:expr) => { + ($self:expr, $backend:expr, $event:expr) => { #[cfg(not(target_os = "solana"))] if let Some(tracer) = &mut $self.tracer { - tracer.event($backend, $x); + tracer.event($backend, $event).await?; } }; - ($self:ident, $backend:ident, $condition:expr, $x:expr) => { - #[cfg(not(target_os = "solana"))] - if let Some(tracer) = &mut $self.tracer { - if $condition { - tracer.event($backend, $x); +} + +macro_rules! begin_vm { + ($self:expr, $backend:expr, $context:expr, $chain_id:expr, $input:expr, $opcode:expr) => { + tracing_event!( + $self, + $backend, + crate::evm::tracing::Event::BeginVM { + context: $context, + chain_id: $chain_id, + input: $input.to_vec(), + opcode: $opcode } - } + ); + }; + ($self:expr, $backend:expr, $context:expr, $chain_id:expr, $input:expr) => { + begin_vm!( + $self, + $backend, + $context, + $chain_id, + $input, + $self.execution_code.get_or_default($self.pc).into() + ); }; } -macro_rules! trace_end_step { - ($self:ident, $backend:ident, $return_data:expr) => { - #[cfg(not(target_os = "solana"))] - if let Some(tracer) = &mut $self.tracer { - tracer.event( - $backend, - crate::evm::tracing::Event::EndStep { - gas_used: 0_u64, - return_data: $return_data, - }, - ) - } +macro_rules! end_vm { + ($self:expr, $backend:expr, $status:expr) => { + tracing_event!( + $self, + $backend, + crate::evm::tracing::Event::EndVM { + context: $self.context, + chain_id: $self.chain_id, + status: $status + } + ); }; - ($self:ident, $backend:ident, $condition:expr; $return_data_getter:expr) => { - #[cfg(not(target_os = "solana"))] - if $condition { - trace_end_step!($self, $backend, $return_data_getter) - } +} + +macro_rules! begin_step { + ($self:expr, $backend:expr) => { + tracing_event!( + $self, + $backend, + crate::evm::tracing::Event::BeginStep { + context: $self.context, + chain_id: $self.chain_id, + opcode: $self.execution_code.get_or_default($self.pc).into(), + pc: $self.pc, + stack: $self.stack.to_vec(), + memory: $self.memory.to_vec(), + return_data: $self.return_data.to_vec() + } + ); }; } -pub(crate) use trace_end_step; +pub(crate) use begin_step; +pub(crate) use begin_vm; +pub(crate) use end_vm; pub(crate) use tracing_event; #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] @@ -344,12 +374,20 @@ impl Machine { let mut step = 0_u64; - tracing_event!( + begin_vm!( self, backend, - tracing::Event::BeginVM { - context: self.context, - code: self.execution_code.to_vec() + self.context, + self.chain_id, + if self.reason == Reason::Call { + self.call_data.to_vec() + } else { + self.execution_code.to_vec() + }, + if self.reason == Reason::Call { + opcode_table::CALL + } else { + opcode_table::CREATE } ); @@ -367,16 +405,7 @@ impl Machine { let opcode = self.execution_code.get_or_default(self.pc); - tracing_event!( - self, - backend, - tracing::Event::BeginStep { - opcode, - pc: self.pc, - stack: self.stack.to_vec(), - memory: self.memory.to_vec() - } - ); + begin_step!(self, backend); let opcode_result = match self.execute_opcode(backend, opcode).await { Ok(result) => result, @@ -386,11 +415,6 @@ impl Machine { } }; - trace_end_step!(self, backend, opcode_result != Action::Noop; match &opcode_result { - Action::Return(value) | Action::Revert(value) => Some(value.clone()), - _ => None, - }); - match opcode_result { Action::Continue => self.pc += 1, Action::Jump(target) => self.pc = target, @@ -403,14 +427,6 @@ impl Machine { } }; - tracing_event!( - self, - backend, - tracing::Event::EndVM { - status: status.clone() - } - ); - Ok((status, step, self.tracer.take())) } diff --git a/evm_loader/program/src/evm/opcode.rs b/evm_loader/program/src/evm/opcode.rs index 2206cf82f..892c5800a 100644 --- a/evm_loader/program/src/evm/opcode.rs +++ b/evm_loader/program/src/evm/opcode.rs @@ -5,14 +5,15 @@ use ethnum::{I256, U256}; use maybe_async::maybe_async; use super::{ + begin_vm, database::{Database, DatabaseExt}, - tracing_event, Context, Machine, Reason, + end_vm, tracing_event, Context, Machine, Reason, }; use crate::evm::tracing::EventListener; use crate::{ debug::log_data, error::{Error, Result}, - evm::{trace_end_step, Buffer}, + evm::Buffer, types::Address, }; @@ -802,12 +803,6 @@ impl Machine { let index = self.stack.pop_u256()?; let value = backend.storage(self.context.contract, index).await?; - tracing_event!( - self, - backend, - super::tracing::Event::StorageAccess { index, value } - ); - self.stack.push_array(&value)?; Ok(Action::Continue) @@ -823,12 +818,6 @@ impl Machine { let index = self.stack.pop_u256()?; let value = *self.stack.pop_array()?; - tracing_event!( - self, - backend, - super::tracing::Event::StorageAccess { index, value } - ); - backend.set_storage(self.context.contract, index, value)?; Ok(Action::Continue) @@ -1082,14 +1071,7 @@ impl Machine { code_address: None, }; - tracing_event!( - self, - backend, - super::tracing::Event::BeginVM { - context, - code: init_code.to_vec() - } - ); + begin_vm!(self, backend, context, chain_id, init_code); self.fork( Reason::Create, @@ -1143,14 +1125,7 @@ impl Machine { code_address: Some(address), }; - tracing_event!( - self, - backend, - super::tracing::Event::BeginVM { - context, - code: code.to_vec() - } - ); + begin_vm!(self, backend, context, chain_id, call_data); self.fork( Reason::Call, @@ -1199,14 +1174,7 @@ impl Machine { ..self.context }; - tracing_event!( - self, - backend, - super::tracing::Event::BeginVM { - context, - code: code.to_vec() - } - ); + begin_vm!(self, backend, context, chain_id, call_data); self.fork( Reason::Call, @@ -1253,14 +1221,7 @@ impl Machine { ..self.context }; - tracing_event!( - self, - backend, - super::tracing::Event::BeginVM { - context, - code: code.to_vec() - } - ); + begin_vm!(self, backend, context, self.chain_id, call_data); self.fork( Reason::Call, @@ -1303,14 +1264,7 @@ impl Machine { code_address: Some(address), }; - tracing_event!( - self, - backend, - super::tracing::Event::BeginVM { - context, - code: code.to_vec() - } - ); + begin_vm!(self, backend, context, chain_id, call_data); self.fork( Reason::Call, @@ -1379,19 +1333,16 @@ impl Machine { backend.commit_snapshot(); log_data(&[b"EXIT", b"RETURN"]); - if self.parent.is_none() { - return Ok(Action::Return(return_data)); - } - - trace_end_step!(self, backend, Some(return_data.clone())); - tracing_event!( + end_vm!( self, backend, - super::tracing::Event::EndVM { - status: super::ExitStatus::Return(return_data.clone()) - } + super::ExitStatus::Return(return_data.clone()) ); + if self.parent.is_none() { + return Ok(Action::Return(return_data)); + } + let returned = self.join(); match returned.reason { Reason::Call => { @@ -1429,19 +1380,16 @@ impl Machine { backend.revert_snapshot(); log_data(&[b"EXIT", b"REVERT", &return_data]); - if self.parent.is_none() { - return Ok(Action::Revert(return_data)); - } - - trace_end_step!(self, backend, Some(return_data.clone())); - tracing_event!( + end_vm!( self, backend, - super::tracing::Event::EndVM { - status: super::ExitStatus::Revert(return_data.clone()) - } + super::ExitStatus::Revert(return_data.clone()) ); + if self.parent.is_none() { + return Ok(Action::Revert(return_data)); + } + let returned = self.join(); match returned.reason { Reason::Call => { @@ -1486,19 +1434,12 @@ impl Machine { backend.commit_snapshot(); log_data(&[b"EXIT", b"SELFDESTRUCT"]); + end_vm!(self, backend, super::ExitStatus::Suicide); + if self.parent.is_none() { return Ok(Action::Suicide); } - trace_end_step!(self, backend, None); - tracing_event!( - self, - backend, - super::tracing::Event::EndVM { - status: super::ExitStatus::Suicide - } - ); - let returned = self.join(); match returned.reason { Reason::Call => { @@ -1519,19 +1460,12 @@ impl Machine { backend.commit_snapshot(); log_data(&[b"EXIT", b"STOP"]); + end_vm!(self, backend, super::ExitStatus::Stop); + if self.parent.is_none() { return Ok(Action::Stop); } - trace_end_step!(self, backend, None); - tracing_event!( - self, - backend, - super::tracing::Event::EndVM { - status: super::ExitStatus::Stop - } - ); - let returned = self.join(); match returned.reason { Reason::Call => { diff --git a/evm_loader/program/src/evm/opcode_table.rs b/evm_loader/program/src/evm/opcode_table.rs index 2f954da47..5f1730951 100644 --- a/evm_loader/program/src/evm/opcode_table.rs +++ b/evm_loader/program/src/evm/opcode_table.rs @@ -4,7 +4,7 @@ use crate::evm::tracing::EventListener; use super::{database::Database, opcode::Action, Machine}; macro_rules! opcode_table { - ($( $opcode:literal, $opname:literal, $op:path;)*) => { + ($($opcode:literal, $opname:ident, $op:path;)*) => { #[cfg(target_os = "solana")] type OpCode = fn(&mut Machine, &mut B) -> Result; @@ -39,168 +39,192 @@ macro_rules! opcode_table { pub const OPNAMES: [&str; 256] = { let mut opnames: [&str; 256] = [""; 256]; - $(opnames[$opcode as usize] = $opname;)* + $(opnames[$opcode as usize] = stringify!($opname);)* opnames }; + + #[repr(transparent)] + #[derive(PartialEq, Eq, Default)] + pub struct Opcode(pub u8); + + #[cfg(not(target_os = "solana"))] + $(pub const $opname: Opcode = Opcode($opcode);)* + + #[cfg(not(target_os = "solana"))] + impl From for Opcode { + fn from(opcode: u8) -> Self { + Opcode(opcode) + } + } + + #[cfg(not(target_os = "solana"))] + impl serde::Serialize for Opcode { + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + serializer.serialize_str(OPNAMES[self.0 as usize]) + } + } } } opcode_table![ - 0x00, "STOP", Self::opcode_stop; - 0x01, "ADD", Self::opcode_add; - 0x02, "MUL", Self::opcode_mul; - 0x03, "SUB", Self::opcode_sub; - 0x04, "DIV", Self::opcode_div; - 0x05, "SDIV", Self::opcode_sdiv; - 0x06, "MOD", Self::opcode_mod; - 0x07, "SMOD", Self::opcode_smod; - 0x08, "ADDMOD", Self::opcode_addmod; - 0x09, "MULMOD", Self::opcode_mulmod; - 0x0A, "EXP", Self::opcode_exp; - 0x0B, "SIGNEXTEND", Self::opcode_signextend; - - 0x10, "LT", Self::opcode_lt; - 0x11, "GT", Self::opcode_gt; - 0x12, "SLT", Self::opcode_slt; - 0x13, "SGT", Self::opcode_sgt; - 0x14, "EQ", Self::opcode_eq; - 0x15, "ISZERO", Self::opcode_iszero; - 0x16, "AND", Self::opcode_and; - 0x17, "OR", Self::opcode_or; - 0x18, "XOR", Self::opcode_xor; - 0x19, "NOT", Self::opcode_not; - 0x1A, "BYTE", Self::opcode_byte; - 0x1B, "SHL", Self::opcode_shl; - 0x1C, "SHR", Self::opcode_shr; - 0x1D, "SAR", Self::opcode_sar; - - 0x20, "KECCAK256", Self::opcode_sha3; - - 0x30, "ADDRESS", Self::opcode_address; - 0x31, "BALANCE", Self::opcode_balance; - 0x32, "ORIGIN", Self::opcode_origin; - 0x33, "CALLER", Self::opcode_caller; - 0x34, "CALLVALUE", Self::opcode_callvalue; - 0x35, "CALLDATALOAD", Self::opcode_calldataload; - 0x36, "CALLDATASIZE", Self::opcode_calldatasize; - 0x37, "CALLDATACOPY", Self::opcode_calldatacopy; - 0x38, "CODESIZE", Self::opcode_codesize; - 0x39, "CODECOPY", Self::opcode_codecopy; - 0x3A, "GASPRICE", Self::opcode_gasprice; - 0x3B, "EXTCODESIZE", Self::opcode_extcodesize; - 0x3C, "EXTCODECOPY", Self::opcode_extcodecopy; - 0x3D, "RETURNDATASIZE", Self::opcode_returndatasize; - 0x3E, "RETURNDATACOPY", Self::opcode_returndatacopy; - 0x3F, "EXTCODEHASH", Self::opcode_extcodehash; - 0x40, "BLOCKHASH", Self::opcode_blockhash; - 0x41, "COINBASE", Self::opcode_coinbase; - 0x42, "TIMESTAMP", Self::opcode_timestamp; - 0x43, "NUMBER", Self::opcode_number; - 0x44, "PREVRANDAO", Self::opcode_difficulty; - 0x45, "GASLIMIT", Self::opcode_gaslimit; - 0x46, "CHAINID", Self::opcode_chainid; - 0x47, "SELFBALANCE", Self::opcode_selfbalance; - 0x48, "BASEFEE", Self::opcode_basefee; - - 0x50, "POP", Self::opcode_pop; - 0x51, "MLOAD", Self::opcode_mload; - 0x52, "MSTORE", Self::opcode_mstore; - 0x53, "MSTORE8", Self::opcode_mstore8; - 0x54, "SLOAD", Self::opcode_sload; - 0x55, "SSTORE", Self::opcode_sstore; - 0x56, "JUMP", Self::opcode_jump; - 0x57, "JUMPI", Self::opcode_jumpi; - 0x58, "PC", Self::opcode_pc; - 0x59, "MSIZE", Self::opcode_msize; - 0x5A, "GAS", Self::opcode_gas; - 0x5B, "JUMPDEST", Self::opcode_jumpdest; - - 0x5F, "PUSH0", Self::opcode_push_0; - 0x60, "PUSH1", Self::opcode_push_1; - 0x61, "PUSH2", Self::opcode_push_2_31::<2>; - 0x62, "PUSH3", Self::opcode_push_2_31::<3>; - 0x63, "PUSH4", Self::opcode_push_2_31::<4>; - 0x64, "PUSH5", Self::opcode_push_2_31::<5>; - 0x65, "PUSH6", Self::opcode_push_2_31::<6>; - 0x66, "PUSH7", Self::opcode_push_2_31::<7>; - 0x67, "PUSH8", Self::opcode_push_2_31::<8>; - 0x68, "PUSH9", Self::opcode_push_2_31::<9>; - 0x69, "PUSH10", Self::opcode_push_2_31::<10>; - 0x6A, "PUSH11", Self::opcode_push_2_31::<11>; - 0x6B, "PUSH12", Self::opcode_push_2_31::<12>; - 0x6C, "PUSH13", Self::opcode_push_2_31::<13>; - 0x6D, "PUSH14", Self::opcode_push_2_31::<14>; - 0x6E, "PUSH15", Self::opcode_push_2_31::<15>; - 0x6F, "PUSH16", Self::opcode_push_2_31::<16>; - 0x70, "PUSH17", Self::opcode_push_2_31::<17>; - 0x71, "PUSH18", Self::opcode_push_2_31::<18>; - 0x72, "PUSH19", Self::opcode_push_2_31::<19>; - 0x73, "PUSH20", Self::opcode_push_2_31::<20>; - 0x74, "PUSH21", Self::opcode_push_2_31::<21>; - 0x75, "PUSH22", Self::opcode_push_2_31::<22>; - 0x76, "PUSH23", Self::opcode_push_2_31::<23>; - 0x77, "PUSH24", Self::opcode_push_2_31::<24>; - 0x78, "PUSH25", Self::opcode_push_2_31::<25>; - 0x79, "PUSH26", Self::opcode_push_2_31::<26>; - 0x7A, "PUSH27", Self::opcode_push_2_31::<27>; - 0x7B, "PUSH28", Self::opcode_push_2_31::<28>; - 0x7C, "PUSH29", Self::opcode_push_2_31::<29>; - 0x7D, "PUSH30", Self::opcode_push_2_31::<30>; - 0x7E, "PUSH31", Self::opcode_push_2_31::<31>; - 0x7F, "PUSH32", Self::opcode_push_32; - - 0x80, "DUP1", Self::opcode_dup_1_16::<1>; - 0x81, "DUP2", Self::opcode_dup_1_16::<2>; - 0x82, "DUP3", Self::opcode_dup_1_16::<3>; - 0x83, "DUP4", Self::opcode_dup_1_16::<4>; - 0x84, "DUP5", Self::opcode_dup_1_16::<5>; - 0x85, "DUP6", Self::opcode_dup_1_16::<6>; - 0x86, "DUP7", Self::opcode_dup_1_16::<7>; - 0x87, "DUP8", Self::opcode_dup_1_16::<8>; - 0x88, "DUP9", Self::opcode_dup_1_16::<9>; - 0x89, "DUP10", Self::opcode_dup_1_16::<10>; - 0x8A, "DUP11", Self::opcode_dup_1_16::<11>; - 0x8B, "DUP12", Self::opcode_dup_1_16::<12>; - 0x8C, "DUP13", Self::opcode_dup_1_16::<13>; - 0x8D, "DUP14", Self::opcode_dup_1_16::<14>; - 0x8E, "DUP15", Self::opcode_dup_1_16::<15>; - 0x8F, "DUP16", Self::opcode_dup_1_16::<16>; - - 0x90, "SWAP1", Self::opcode_swap_1_16::<1>; - 0x91, "SWAP2", Self::opcode_swap_1_16::<2>; - 0x92, "SWAP3", Self::opcode_swap_1_16::<3>; - 0x93, "SWAP4", Self::opcode_swap_1_16::<4>; - 0x94, "SWAP5", Self::opcode_swap_1_16::<5>; - 0x95, "SWAP6", Self::opcode_swap_1_16::<6>; - 0x96, "SWAP7", Self::opcode_swap_1_16::<7>; - 0x97, "SWAP8", Self::opcode_swap_1_16::<8>; - 0x98, "SWAP9", Self::opcode_swap_1_16::<9>; - 0x99, "SWAP10", Self::opcode_swap_1_16::<10>; - 0x9A, "SWAP11", Self::opcode_swap_1_16::<11>; - 0x9B, "SWAP12", Self::opcode_swap_1_16::<12>; - 0x9C, "SWAP13", Self::opcode_swap_1_16::<13>; - 0x9D, "SWAP14", Self::opcode_swap_1_16::<14>; - 0x9E, "SWAP15", Self::opcode_swap_1_16::<15>; - 0x9F, "SWAP16", Self::opcode_swap_1_16::<16>; - - 0xA0, "LOG0", Self::opcode_log_0_4::<0>; - 0xA1, "LOG1", Self::opcode_log_0_4::<1>; - 0xA2, "LOG2", Self::opcode_log_0_4::<2>; - 0xA3, "LOG3", Self::opcode_log_0_4::<3>; - 0xA4, "LOG4", Self::opcode_log_0_4::<4>; - - 0xF0, "CREATE", Self::opcode_create; - 0xF1, "CALL", Self::opcode_call; - 0xF2, "CALLCODE", Self::opcode_callcode; - 0xF3, "RETURN", Self::opcode_return; - 0xF4, "DELEGATECALL", Self::opcode_delegatecall; - 0xF5, "CREATE2", Self::opcode_create2; - - 0xFA, "STATICCALL", Self::opcode_staticcall; - - 0xFD, "REVERT", Self::opcode_revert; - 0xFE, "INVALID", Self::opcode_invalid; - - 0xFF, "SELFDESTRUCT", Self::opcode_selfdestruct; + 0x00, STOP, Self::opcode_stop; + 0x01, ADD, Self::opcode_add; + 0x02, MUL, Self::opcode_mul; + 0x03, SUB, Self::opcode_sub; + 0x04, DIV, Self::opcode_div; + 0x05, SDIV, Self::opcode_sdiv; + 0x06, MOD, Self::opcode_mod; + 0x07, SMOD, Self::opcode_smod; + 0x08, ADDMOD, Self::opcode_addmod; + 0x09, MULMOD, Self::opcode_mulmod; + 0x0A, EXP, Self::opcode_exp; + 0x0B, SIGNEXTEND, Self::opcode_signextend; + + 0x10, LT, Self::opcode_lt; + 0x11, GT, Self::opcode_gt; + 0x12, SLT, Self::opcode_slt; + 0x13, SGT, Self::opcode_sgt; + 0x14, EQ, Self::opcode_eq; + 0x15, ISZERO, Self::opcode_iszero; + 0x16, AND, Self::opcode_and; + 0x17, OR, Self::opcode_or; + 0x18, XOR, Self::opcode_xor; + 0x19, NOT, Self::opcode_not; + 0x1A, BYTE, Self::opcode_byte; + 0x1B, SHL, Self::opcode_shl; + 0x1C, SHR, Self::opcode_shr; + 0x1D, SAR, Self::opcode_sar; + + 0x20, KECCAK256, Self::opcode_sha3; + + 0x30, ADDRESS, Self::opcode_address; + 0x31, BALANCE, Self::opcode_balance; + 0x32, ORIGIN, Self::opcode_origin; + 0x33, CALLER, Self::opcode_caller; + 0x34, CALLVALUE, Self::opcode_callvalue; + 0x35, CALLDATALOAD, Self::opcode_calldataload; + 0x36, CALLDATASIZE, Self::opcode_calldatasize; + 0x37, CALLDATACOPY, Self::opcode_calldatacopy; + 0x38, CODESIZE, Self::opcode_codesize; + 0x39, CODECOPY, Self::opcode_codecopy; + 0x3A, GASPRICE, Self::opcode_gasprice; + 0x3B, EXTCODESIZE, Self::opcode_extcodesize; + 0x3C, EXTCODECOPY, Self::opcode_extcodecopy; + 0x3D, RETURNDATASIZE, Self::opcode_returndatasize; + 0x3E, RETURNDATACOPY, Self::opcode_returndatacopy; + 0x3F, EXTCODEHASH, Self::opcode_extcodehash; + 0x40, BLOCKHASH, Self::opcode_blockhash; + 0x41, COINBASE, Self::opcode_coinbase; + 0x42, TIMESTAMP, Self::opcode_timestamp; + 0x43, NUMBER, Self::opcode_number; + 0x44, PREVRANDAO, Self::opcode_difficulty; + 0x45, GASLIMIT, Self::opcode_gaslimit; + 0x46, CHAINID, Self::opcode_chainid; + 0x47, SELFBALANCE, Self::opcode_selfbalance; + 0x48, BASEFEE, Self::opcode_basefee; + + 0x50, POP, Self::opcode_pop; + 0x51, MLOAD, Self::opcode_mload; + 0x52, MSTORE, Self::opcode_mstore; + 0x53, MSTORE8, Self::opcode_mstore8; + 0x54, SLOAD, Self::opcode_sload; + 0x55, SSTORE, Self::opcode_sstore; + 0x56, JUMP, Self::opcode_jump; + 0x57, JUMPI, Self::opcode_jumpi; + 0x58, PC, Self::opcode_pc; + 0x59, MSIZE, Self::opcode_msize; + 0x5A, GAS, Self::opcode_gas; + 0x5B, JUMPDEST, Self::opcode_jumpdest; + + 0x5F, PUSH0, Self::opcode_push_0; + 0x60, PUSH1, Self::opcode_push_1; + 0x61, PUSH2, Self::opcode_push_2_31::<2>; + 0x62, PUSH3, Self::opcode_push_2_31::<3>; + 0x63, PUSH4, Self::opcode_push_2_31::<4>; + 0x64, PUSH5, Self::opcode_push_2_31::<5>; + 0x65, PUSH6, Self::opcode_push_2_31::<6>; + 0x66, PUSH7, Self::opcode_push_2_31::<7>; + 0x67, PUSH8, Self::opcode_push_2_31::<8>; + 0x68, PUSH9, Self::opcode_push_2_31::<9>; + 0x69, PUSH10, Self::opcode_push_2_31::<10>; + 0x6A, PUSH11, Self::opcode_push_2_31::<11>; + 0x6B, PUSH12, Self::opcode_push_2_31::<12>; + 0x6C, PUSH13, Self::opcode_push_2_31::<13>; + 0x6D, PUSH14, Self::opcode_push_2_31::<14>; + 0x6E, PUSH15, Self::opcode_push_2_31::<15>; + 0x6F, PUSH16, Self::opcode_push_2_31::<16>; + 0x70, PUSH17, Self::opcode_push_2_31::<17>; + 0x71, PUSH18, Self::opcode_push_2_31::<18>; + 0x72, PUSH19, Self::opcode_push_2_31::<19>; + 0x73, PUSH20, Self::opcode_push_2_31::<20>; + 0x74, PUSH21, Self::opcode_push_2_31::<21>; + 0x75, PUSH22, Self::opcode_push_2_31::<22>; + 0x76, PUSH23, Self::opcode_push_2_31::<23>; + 0x77, PUSH24, Self::opcode_push_2_31::<24>; + 0x78, PUSH25, Self::opcode_push_2_31::<25>; + 0x79, PUSH26, Self::opcode_push_2_31::<26>; + 0x7A, PUSH27, Self::opcode_push_2_31::<27>; + 0x7B, PUSH28, Self::opcode_push_2_31::<28>; + 0x7C, PUSH29, Self::opcode_push_2_31::<29>; + 0x7D, PUSH30, Self::opcode_push_2_31::<30>; + 0x7E, PUSH31, Self::opcode_push_2_31::<31>; + 0x7F, PUSH32, Self::opcode_push_32; + + 0x80, DUP1, Self::opcode_dup_1_16::<1>; + 0x81, DUP2, Self::opcode_dup_1_16::<2>; + 0x82, DUP3, Self::opcode_dup_1_16::<3>; + 0x83, DUP4, Self::opcode_dup_1_16::<4>; + 0x84, DUP5, Self::opcode_dup_1_16::<5>; + 0x85, DUP6, Self::opcode_dup_1_16::<6>; + 0x86, DUP7, Self::opcode_dup_1_16::<7>; + 0x87, DUP8, Self::opcode_dup_1_16::<8>; + 0x88, DUP9, Self::opcode_dup_1_16::<9>; + 0x89, DUP10, Self::opcode_dup_1_16::<10>; + 0x8A, DUP11, Self::opcode_dup_1_16::<11>; + 0x8B, DUP12, Self::opcode_dup_1_16::<12>; + 0x8C, DUP13, Self::opcode_dup_1_16::<13>; + 0x8D, DUP14, Self::opcode_dup_1_16::<14>; + 0x8E, DUP15, Self::opcode_dup_1_16::<15>; + 0x8F, DUP16, Self::opcode_dup_1_16::<16>; + + 0x90, SWAP1, Self::opcode_swap_1_16::<1>; + 0x91, SWAP2, Self::opcode_swap_1_16::<2>; + 0x92, SWAP3, Self::opcode_swap_1_16::<3>; + 0x93, SWAP4, Self::opcode_swap_1_16::<4>; + 0x94, SWAP5, Self::opcode_swap_1_16::<5>; + 0x95, SWAP6, Self::opcode_swap_1_16::<6>; + 0x96, SWAP7, Self::opcode_swap_1_16::<7>; + 0x97, SWAP8, Self::opcode_swap_1_16::<8>; + 0x98, SWAP9, Self::opcode_swap_1_16::<9>; + 0x99, SWAP10, Self::opcode_swap_1_16::<10>; + 0x9A, SWAP11, Self::opcode_swap_1_16::<11>; + 0x9B, SWAP12, Self::opcode_swap_1_16::<12>; + 0x9C, SWAP13, Self::opcode_swap_1_16::<13>; + 0x9D, SWAP14, Self::opcode_swap_1_16::<14>; + 0x9E, SWAP15, Self::opcode_swap_1_16::<15>; + 0x9F, SWAP16, Self::opcode_swap_1_16::<16>; + + 0xA0, LOG0, Self::opcode_log_0_4::<0>; + 0xA1, LOG1, Self::opcode_log_0_4::<1>; + 0xA2, LOG2, Self::opcode_log_0_4::<2>; + 0xA3, LOG3, Self::opcode_log_0_4::<3>; + 0xA4, LOG4, Self::opcode_log_0_4::<4>; + + 0xF0, CREATE, Self::opcode_create; + 0xF1, CALL, Self::opcode_call; + 0xF2, CALLCODE, Self::opcode_callcode; + 0xF3, RETURN, Self::opcode_return; + 0xF4, DELEGATECALL, Self::opcode_delegatecall; + 0xF5, CREATE2, Self::opcode_create2; + + 0xFA, STATICCALL, Self::opcode_staticcall; + + 0xFD, REVERT, Self::opcode_revert; + 0xFE, INVALID, Self::opcode_invalid; + + 0xFF, SELFDESTRUCT, Self::opcode_selfdestruct; ]; diff --git a/evm_loader/program/src/evm/tracing.rs b/evm_loader/program/src/evm/tracing.rs index 8f7776206..983faeb54 100644 --- a/evm_loader/program/src/evm/tracing.rs +++ b/evm_loader/program/src/evm/tracing.rs @@ -1,38 +1,51 @@ +use maybe_async::maybe_async; + use super::{Context, ExitStatus}; use crate::evm::database::Database; -use ethnum::U256; +use crate::evm::opcode_table::Opcode; pub struct NoopEventListener; +#[maybe_async(?Send)] pub trait EventListener { - fn event(&mut self, executor_state: &impl Database, event: Event); + async fn event( + &mut self, + executor_state: &impl Database, + event: Event, + ) -> crate::error::Result<()>; } +#[maybe_async(?Send)] impl EventListener for NoopEventListener { - fn event(&mut self, _executor_state: &impl Database, _event: Event) {} + async fn event( + &mut self, + _executor_state: &impl Database, + _event: Event, + ) -> crate::error::Result<()> { + Ok(()) + } } /// Trace event pub enum Event { BeginVM { context: Context, - code: Vec, + chain_id: u64, + input: Vec, + opcode: Opcode, }, EndVM { + context: Context, + chain_id: u64, status: ExitStatus, }, BeginStep { - opcode: u8, + context: Context, + chain_id: u64, + opcode: Opcode, pc: usize, stack: Vec<[u8; 32]>, memory: Vec, - }, - EndStep { - gas_used: u64, - return_data: Option>, - }, - StorageAccess { - index: U256, - value: [u8; 32], + return_data: Vec, }, } From 75613349de45407be2ac47b8d8ea427598af5e14 Mon Sep 17 00:00:00 2001 From: Kristina Nikolaeva <112946046+kristinaNikolaevaa@users.noreply.github.com> Date: Mon, 11 Mar 2024 11:53:47 +0100 Subject: [PATCH 130/318] fix slack notofication (#306) --- .github/workflows/pipeline.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index e1e58d6e3..ba86f7d2a 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -127,8 +127,8 @@ jobs: failure() && (github.ref_name == 'develop' || github.ref_name == 'master' || - steps.is_version_branch.outputs.value) || - startsWith(github.ref , 'refs/tags/') + steps.is_version_branch.outputs.value || + startsWith(github.ref , 'refs/tags/')) run: | python3 ./.github/workflows/deploy.py send_notification \ --url=${{secrets.SLACK_EVM_CHANNEL_URL}} \ From 3490f2af30f90b6e0a05191dbaea8421c46eaab7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 13 Mar 2024 07:20:47 +0100 Subject: [PATCH 131/318] Bump strum_macros from 0.26.1 to 0.26.2 in /evm_loader (#337) Bumps [strum_macros](https://github.com/Peternator7/strum) from 0.26.1 to 0.26.2. - [Release notes](https://github.com/Peternator7/strum/releases) - [Changelog](https://github.com/Peternator7/strum/blob/master/CHANGELOG.md) - [Commits](https://github.com/Peternator7/strum/commits) --- updated-dependencies: - dependency-name: strum_macros dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 6 +++--- evm_loader/lib/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index fb80fb007..9a68322ef 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -3392,7 +3392,7 @@ dependencies = [ "spl-associated-token-account", "spl-token", "strum 0.26.1", - "strum_macros 0.26.1", + "strum_macros 0.26.2", "thiserror", "tokio", "tracing", @@ -6511,9 +6511,9 @@ dependencies = [ [[package]] name = "strum_macros" -version = "0.26.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a3417fc93d76740d974a01654a09777cb500428cc874ca9f45edfe0c4d4cd18" +checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" dependencies = [ "heck 0.4.1", "proc-macro2", diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 3bf6b4d3f..b08bb133b 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -41,7 +41,7 @@ neon-lib-interface = { path = "../lib-interface" } abi_stable = "0.11.2" async-ffi = { version = "0.5.0", features = ["abi_stable"] } strum = "0.26.1" -strum_macros = "0.26.1" +strum_macros = "0.26.2" clap = "2.33.3" lazy_static = "1.4.0" arrayref = "0.3.6" From efe26b07357927c13d332caadcbd17346ef31891 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Wed, 13 Mar 2024 14:38:32 +0100 Subject: [PATCH 132/318] NDEV-2755: Update Solana to v1.17.25 (#339) --- .github/workflows/deploy.py | 7 +- evm_loader/Cargo.lock | 208 +++++++++++++++++----------------- evm_loader/api/Cargo.toml | 4 +- evm_loader/cli/Cargo.toml | 8 +- evm_loader/lib/Cargo.toml | 14 +-- evm_loader/program/Cargo.toml | 2 +- 6 files changed, 122 insertions(+), 121 deletions(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index c9f6b7041..94bf327b0 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -32,8 +32,8 @@ IMAGE_NAME = os.environ.get("IMAGE_NAME") RUN_LINK_REPO = os.environ.get("RUN_LINK_REPO") DOCKERHUB_ORG_NAME = os.environ.get("DOCKERHUB_ORG_NAME") -SOLANA_NODE_VERSION = 'v1.17.24' -SOLANA_BPF_VERSION = 'v1.17.24' +SOLANA_NODE_VERSION = 'v1.17.25' +SOLANA_BPF_VERSION = 'v1.17.25' VERSION_BRANCH_TEMPLATE = r"[vt]{1}\d{1,2}\.\d{1,2}\.x.*" docker_client = docker.APIClient() @@ -42,6 +42,7 @@ PROXY_ENDPOINT = os.environ.get("PROXY_ENDPOINT") NEON_TESTS_ENDPOINT = os.environ.get("NEON_TESTS_ENDPOINT") + @click.group() def cli(): pass @@ -112,7 +113,7 @@ def run_tests(github_sha, neon_test_branch, base_ref_branch): if GithubClient.is_branch_exist(NEON_TESTS_ENDPOINT, neon_test_branch) \ and neon_test_branch not in ('master', 'develop'): neon_test_image_tag = neon_test_branch - elif re.match(VERSION_BRANCH_TEMPLATE, base_ref_branch): # PR to version branch + elif re.match(VERSION_BRANCH_TEMPLATE, base_ref_branch): # PR to version branch neon_test_image_tag = base_ref_branch else: neon_test_image_tag = 'latest' diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 9a68322ef..c8a9e6c05 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -4992,9 +4992,9 @@ dependencies = [ [[package]] name = "solana-account-decoder" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f22a6b3c7e728d335dcfca063e57e1a7c43a5ad2d6889f9b1684b1ab5cc25dd4" +checksum = "942b6faa78521915895cbe52f62c5ba29e0962fff976271ec983a68a6e6b9f6a" dependencies = [ "Inflector", "base64 0.21.7", @@ -5017,9 +5017,9 @@ dependencies = [ [[package]] name = "solana-accounts-db" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40d27b41953b4df1fc59e4a3f8b9d7a9c1dbe23987c33610a5de13f4e5978c73" +checksum = "edd6a1553b26a656730428fcb9d888ae67f9459e0d11d344224ad110f894f58e" dependencies = [ "arrayref", "bincode", @@ -5076,9 +5076,9 @@ dependencies = [ [[package]] name = "solana-address-lookup-table-program" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b116b626f50fddaeb00e5f2d59f891b1dc0da6ddde8faea57f068594a289410b" +checksum = "00cfecfcf82ce18010a93fca9b1225c8fc2aed50b39687b83131e115477987b3" dependencies = [ "bincode", "bytemuck", @@ -5097,9 +5097,9 @@ dependencies = [ [[package]] name = "solana-banks-client" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "999ac7745cb153f1e42be9c13380e2858016160f8cda531d717c953452ddcc57" +checksum = "f7ab648b93dc07615d9fa2f08a5881b04a4da1de1add36f510c5115ffd17768e" dependencies = [ "borsh 0.10.3", "futures", @@ -5114,9 +5114,9 @@ dependencies = [ [[package]] name = "solana-banks-interface" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed3ad0bfdafdc5d59fe27b1bdc4188a8449a2dc0a205b0e50751a05fbeffe41" +checksum = "2a98467b41a47e933f37ec322aca24548ff8673af8760857d864d99a4ad7143f" dependencies = [ "serde", "solana-sdk", @@ -5125,9 +5125,9 @@ dependencies = [ [[package]] name = "solana-banks-server" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5094cf57a50a33277cb404f27fdd86b5ce408245f70af2abde41cc4206cc5b7d" +checksum = "175dfcce508944095b3ed6c9638c4f9b4384335a434c84d038279d84a101a447" dependencies = [ "bincode", "crossbeam-channel", @@ -5145,9 +5145,9 @@ dependencies = [ [[package]] name = "solana-bpf-loader-program" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201a24b71000fdc57f92b78eac49440f51c1f9fa0d9e38c16df0ca4373d188e8" +checksum = "942697980093d9b974493386d4739c8dca13411ffcaede34fa9de116715ea6b6" dependencies = [ "bincode", "byteorder", @@ -5164,9 +5164,9 @@ dependencies = [ [[package]] name = "solana-bucket-map" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a747b8bcb0145d8d18bf643c5923db98a68052425f84ef7782555b4faeaf053f" +checksum = "873df2da0e84f56a2c488188da8a6723969cd183be3a79bc8108d0061be1c9d6" dependencies = [ "bv", "bytemuck", @@ -5182,9 +5182,9 @@ dependencies = [ [[package]] name = "solana-clap-utils" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0702c8a53c0c86a704ceaaa7a5bbe19d21c217b0b18815f6f629ef1b4a4d428" +checksum = "c4b76f277d3c922d15ffcb30e0aab0919fe5691017278038a5d0935481607fc9" dependencies = [ "chrono", "clap 2.34.0", @@ -5199,9 +5199,9 @@ dependencies = [ [[package]] name = "solana-cli" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c343823d715ee17413e807a4646b061e0f90ced78dfe0d625ce951c34142891a" +checksum = "f574acb2d3cba2c0751efe2d59ab06a7dddd7c3368ff057d2f7faf59f06e94ec" dependencies = [ "bincode", "bs58 0.4.0", @@ -5250,9 +5250,9 @@ dependencies = [ [[package]] name = "solana-cli-config" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bf0d8122695686e2e42f0daf6d5bd06f3b3e3e29d23fef9ab78ad0b5bc80f64" +checksum = "fd2e387f55b824a56c9f5d969ff2262bdc354125f00b85d9f9a9d42f8186fbf6" dependencies = [ "dirs-next", "lazy_static", @@ -5266,9 +5266,9 @@ dependencies = [ [[package]] name = "solana-cli-output" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f2b5acd03e51421cc6531738115ca763b168a8e34dd4442bb683eebff5c4c5a" +checksum = "ad011b611f8d783fb80eabfc4815304e878e300b2e32179e0cd3ebb890a2ece9" dependencies = [ "Inflector", "base64 0.21.7", @@ -5293,9 +5293,9 @@ dependencies = [ [[package]] name = "solana-client" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de7cc0c90c0b8ad5033062895682223d203c172d8bcecd3a1f97e91e72c10d11" +checksum = "ab357a45351eeab99539eed5af638af9d577a32fdefa25baf2504fccfb97cab9" dependencies = [ "async-trait", "bincode", @@ -5326,9 +5326,9 @@ dependencies = [ [[package]] name = "solana-compute-budget-program" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dbcccdbc33ffd69cb2d53089e142638745a835a2c9debd2640ad251a7d93ca3" +checksum = "d75ae20a4b7848724ba315ef67c2090f738a41e2ddbc08eecdd406313b8cb7f9" dependencies = [ "solana-program-runtime", "solana-sdk", @@ -5336,9 +5336,9 @@ dependencies = [ [[package]] name = "solana-config-program" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dae9df8d8b30eb66dd3b1bc9b634b21e5ac32ac8aea43d8114eea1553944af44" +checksum = "677b61fe38df5db47589d6d09085baf8792006a268447b8fe0542b462a127f2f" dependencies = [ "bincode", "chrono", @@ -5350,9 +5350,9 @@ dependencies = [ [[package]] name = "solana-connection-cache" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cd72e23fb92c6f26d5990d9196dd58be3c4b6453bb86a51bb4612bc5a37370d" +checksum = "0a3f6a921263f29e0a7f808fe9659a3fc7e6dfbd42ce4811ca95436a95aee89b" dependencies = [ "async-trait", "bincode", @@ -5372,9 +5372,9 @@ dependencies = [ [[package]] name = "solana-cost-model" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a70328e6683d4e5fa7fc7ef5e0b1744eeb94591070e54546f7ed6110a8bfc6e" +checksum = "aa1e9853c0511e9730a1dca659d064012003053d35ceefe33f779c1c9496bab8" dependencies = [ "lazy_static", "log", @@ -5396,9 +5396,9 @@ dependencies = [ [[package]] name = "solana-faucet" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1a842848786964f5e1a938c0668d152691eb3dd33631cb470115dc66407418" +checksum = "1ff31c13459aacb78360cdb53d575d4daf6d33a1bf4d19677b5a0b721f1d7e67" dependencies = [ "bincode", "byteorder", @@ -5420,9 +5420,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b29d81ae90aa6acd4e7a3809d4f6516f888c780182819ccc12187cd02e59b94" +checksum = "de577bb681dfc3afeda6247dbc381f8c74a31eeed141883e6a9a36e93fdcf784" dependencies = [ "ahash 0.8.5", "blake3", @@ -5450,9 +5450,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi-macro" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9c4400284bb28fedd23abc0e7008f9ec7db8d20f9b296a438bd08ed417db98e" +checksum = "e6373184605334be54d85564b657e7b4d88bdf4e3c011abccce4fd2712c96caf" dependencies = [ "proc-macro2", "quote", @@ -5462,9 +5462,9 @@ dependencies = [ [[package]] name = "solana-loader-v4-program" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac967ae044389601bda6a5158c397f6a3bbcbbf558b93e127782c702f0649a89" +checksum = "770ace194d2c96f8d99315db722d20dcbf330c46e3c6bcef60c47d5d45252184" dependencies = [ "log", "solana-measure", @@ -5475,9 +5475,9 @@ dependencies = [ [[package]] name = "solana-logger" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c0fbccd60c8332712714468630d51c8668c838459fc5ffecfa615c84248eb82" +checksum = "f6959774302d4407c77d5fbdd4d5e31c2696f5ac1c74bf0cdcac704b474bc6fd" dependencies = [ "env_logger", "lazy_static", @@ -5486,9 +5486,9 @@ dependencies = [ [[package]] name = "solana-measure" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e1efcb7d2d9e4c4cf2f65c15505e1b4967bbfadd2aa004e417488b015be9fc" +checksum = "9327e70f9cb17094077531449f7487677c4d380bd99b9494dca85af5ea5f5e19" dependencies = [ "log", "solana-sdk", @@ -5496,9 +5496,9 @@ dependencies = [ [[package]] name = "solana-metrics" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11c7e8d9664ab39890f627abc142d5f0402a16cb3591be4fdd288dbc35bd786c" +checksum = "ca5e3931823a9bdaee5d65d27195804127911578abddaddda3025f6af6647c08" dependencies = [ "crossbeam-channel", "gethostname", @@ -5511,9 +5511,9 @@ dependencies = [ [[package]] name = "solana-net-utils" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a39ec45feab4006a0c6a798642295947632d2b92ac75495c33387014667f9e6" +checksum = "3fed17001119742b35ce06b18823b4901313860c5dd495e32bccf070424b2947" dependencies = [ "bincode", "clap 3.2.23", @@ -5533,9 +5533,9 @@ dependencies = [ [[package]] name = "solana-perf" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3950864d7f38cfe7d4c800101b22784c04db29fd9e154f28e983e46cb6d980cb" +checksum = "8c2a6d77ead9c96aa2a84afd0662d01c55abec61b514d8c9e2dc5627a1d74c7b" dependencies = [ "ahash 0.8.5", "bincode", @@ -5562,9 +5562,9 @@ dependencies = [ [[package]] name = "solana-program" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e6f6bf27bf9e16803bfe6a2fe01b2431258ec9b4d6ea17b801717480995aaa0" +checksum = "9dd3bcc37b433d7e8d45236a0f5aa68df462c4d5c6a709a6efd916988ce3ac08" dependencies = [ "ark-bn254", "ark-ec", @@ -5616,9 +5616,9 @@ dependencies = [ [[package]] name = "solana-program-runtime" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a92f2a945295cdc782e5a9223b96982755e32babc6e7992ca3f73ccccd111ce" +checksum = "618fb4dc2238daa2737805659c4ad380fb61dd27a40cfd14e63d890d1e4335b0" dependencies = [ "base64 0.21.7", "bincode", @@ -5644,9 +5644,9 @@ dependencies = [ [[package]] name = "solana-program-test" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee70dfdbb935266d7d85adcf957eec196bd033a7b8fbce16db21611cbf91d582" +checksum = "0d04f60ba923ba30072e31cd347b2792aea40738d93fb7c12426d1a5957cf13b" dependencies = [ "assert_matches", "async-trait", @@ -5674,9 +5674,9 @@ dependencies = [ [[package]] name = "solana-pubsub-client" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01c9090c2938ee4e02ac09528e2fc03897ef6645310cf8ba340baa8324eb1796" +checksum = "0daf3d4daa67ef7550fe1a4b88dad32164263c9b7b7f0477caacae6b0220ceb5" dependencies = [ "crossbeam-channel", "futures-util", @@ -5699,9 +5699,9 @@ dependencies = [ [[package]] name = "solana-quic-client" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25be026b8fe02dbef50af9f0942a306d8b2b536e407c8caf8947ef39e8ca1001" +checksum = "39f1c28340a1845d18ab85f96c57f283a588745f4f334a77a0cc7a13a6f2eae4" dependencies = [ "async-mutex", "async-trait", @@ -5726,9 +5726,9 @@ dependencies = [ [[package]] name = "solana-rayon-threadlimit" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce88200cc41f31414d149d2c9753512ecf746ac60da1e22631684fdfe99cf5c9" +checksum = "1c8f657c79b681bd49b4106242890225ba0df190cc83109394a1fcc8e3c54819" dependencies = [ "lazy_static", "num_cpus", @@ -5736,9 +5736,9 @@ dependencies = [ [[package]] name = "solana-remote-wallet" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5ca14a3dbc4a608698bba5fef23456072cee476592bf00f44dec0bff19417d4" +checksum = "e8d8bc9c75495fcf301a85bda5c921213dbff9dc8d6e7708c74eaa9d06e8e395" dependencies = [ "console", "dialoguer", @@ -5756,9 +5756,9 @@ dependencies = [ [[package]] name = "solana-rpc-client" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45106dab6a4b406ddfd6c0e6f4b4dea2c1cac5d1dbaf11ed644fc102f7293a9b" +checksum = "f050027aff888d96c5a659dc164998d6ec25aadde649f1474d2cbb73b2a72de8" dependencies = [ "async-trait", "base64 0.21.7", @@ -5782,9 +5782,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-api" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0190bf789cc7a1f3508928f01051381cc15bda16120a2a080ff10aa311388970" +checksum = "a273e98835985e15e3774267af94a0631b1e27ae187b242e7fbacf1c1fad29fb" dependencies = [ "base64 0.21.7", "bs58 0.4.0", @@ -5804,9 +5804,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-nonce-utils" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0959c952240cf1cf07de24c8a40ac8531ba545640558f7634c492ce8cf4a5005" +checksum = "458fc8f9d14e42d397e7867288fdff47de6ca9f949b1f11217e807a65bf17c43" dependencies = [ "clap 2.34.0", "solana-clap-utils", @@ -5817,9 +5817,9 @@ dependencies = [ [[package]] name = "solana-runtime" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ca87344dfc2b5e1058b4d528b736076d9b335a1cf69a3de2bb3807f8c72594" +checksum = "da0c4ebc4711eaf1507728e3d80883dc6233ce19a0c290932f52065688f8fc3e" dependencies = [ "arrayref", "base64 0.21.7", @@ -5894,9 +5894,9 @@ dependencies = [ [[package]] name = "solana-sdk" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa149a29cb505742bca6bce7447d979e746452ec40e9b1eb3e50d51a0f0510cd" +checksum = "a1de78b8c4fa09e4b90d720b2aa3ef3c80c4b956aa3d14616261a7f4bdf64c04" dependencies = [ "assert_matches", "base64 0.21.7", @@ -5948,9 +5948,9 @@ dependencies = [ [[package]] name = "solana-sdk-macro" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd8ad88355cf03e34b60ba12f65dffc44054e453aa1113a50169ee42ab6ad7a3" +checksum = "9b5055c4b785cf3e5f2f52d687bdd1a795755105fe4365182396bc8b6bb41cd5" dependencies = [ "bs58 0.4.0", "proc-macro2", @@ -5967,9 +5967,9 @@ checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" [[package]] name = "solana-send-transaction-service" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97189214ed892e0b1159b066e1a2f69f0414610959e5ac39272dd9c4a4575b6a" +checksum = "b9774fd9effd1cdccbd1e5dff9f3ee1a806643939be215a44aeac3982d15bdfc" dependencies = [ "crossbeam-channel", "log", @@ -5983,9 +5983,9 @@ dependencies = [ [[package]] name = "solana-stake-program" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2f190c96ebe38627c135cf32593c5981faa621fda571372ac44a3e5cb2eaa53" +checksum = "624f4287174fab61b21ac1c185c31bc575dd65f7f11600cb483dbe8e25da7531" dependencies = [ "bincode", "log", @@ -5998,9 +5998,9 @@ dependencies = [ [[package]] name = "solana-streamer" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df7b1d9cfdfa37d3940ca6c20fa75e989e12432a430ebcb0e4ab316eb0e437b" +checksum = "05a31fb5a63f80318a5b03148d9132e3bb1f2125e0bebe9bedfc095d1b16753c" dependencies = [ "async-channel", "bytes", @@ -6030,9 +6030,9 @@ dependencies = [ [[package]] name = "solana-system-program" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec764e30a69176a680591f1b4e24af91df7c5a3923804c994bb2f11310264f18" +checksum = "7e9a95bc33e2e62c4b3d029f0cfe3b1ce6308dd82bc247fdfcf388f984a8cc49" dependencies = [ "bincode", "log", @@ -6044,9 +6044,9 @@ dependencies = [ [[package]] name = "solana-thin-client" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00c98d10503361d23f2146a42d87639d7b58081d84b8c3b3cc7958db9434b655" +checksum = "4b19c4e6d850b0b8598f84513b4b5cdcc36d095df1b99725704c087d4df7e9eb" dependencies = [ "bincode", "log", @@ -6059,9 +6059,9 @@ dependencies = [ [[package]] name = "solana-tpu-client" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e82965ce39184e2618f0c38f5aed625cdaf2aac1d6fe0d665ddcc9771d6313f" +checksum = "91e6cb310a96dad1a34e7cacd9344800206df21c5f891459240621c96e13c6ee" dependencies = [ "async-trait", "bincode", @@ -6083,9 +6083,9 @@ dependencies = [ [[package]] name = "solana-transaction-status" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a4107eac6b20f3349c49af21eaca73cd3d92a2c1b03118531349415ab4e7f84" +checksum = "fd87fd7b4164cb7cbe047e6376e9585668923ed8072ea32b7e878f25c90fd056" dependencies = [ "Inflector", "base64 0.21.7", @@ -6108,9 +6108,9 @@ dependencies = [ [[package]] name = "solana-udp-client" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "def72d6f0b3d9f67a6a4ad4407abe318e31f816dd76d8bc6c410bacb6de68aad" +checksum = "4886959ef4094af0d9ceda93dc468fa7088f46b22cc7d0c8c18086389e8d63e7" dependencies = [ "async-trait", "solana-connection-cache", @@ -6123,9 +6123,9 @@ dependencies = [ [[package]] name = "solana-version" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67f6b247004ce32a78a3e441f7d90f07cb4ade51e07ac32bccbb493ab41f6261" +checksum = "310500e993127ea009a2c41daf2e004d436d3041cdee6673112804c574a41eda" dependencies = [ "log", "rustc_version", @@ -6139,9 +6139,9 @@ dependencies = [ [[package]] name = "solana-vote" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34a426bb298693984bd7e224468d64dc0244906262fd5c623c413bd85775a2f" +checksum = "ccb5e4854105e8fe8172bd379d6d0689bba28109ba39a001430e13c75c3ba034" dependencies = [ "crossbeam-channel", "itertools 0.10.5", @@ -6158,9 +6158,9 @@ dependencies = [ [[package]] name = "solana-vote-program" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ea6ab44f5f52fba9daa7455686e516c4fde9004503503f6ecbd1975e5875226" +checksum = "04079fab6e48794ec194c9bb44422672fa66594b9979dfc97d62c1556434ee7a" dependencies = [ "bincode", "log", @@ -6180,9 +6180,9 @@ dependencies = [ [[package]] name = "solana-zk-token-proof-program" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e517ac4c61fb4bee20fb24ac0d0b938be4ef307cc500d4c4c253d241b147d231" +checksum = "c266a0aad5d82e8b8423616506e07025ddf42acec5c00e55a85a55841dffc7fe" dependencies = [ "bytemuck", "num-derive 0.3.3", @@ -6194,9 +6194,9 @@ dependencies = [ [[package]] name = "solana-zk-token-sdk" -version = "1.17.24" +version = "1.17.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7845f8390725707661732fb4df99c5c82eb3f7549c187160c317706e839c5702" +checksum = "d9e0b222c3aad3df370ae87e993b32419906f00827a1677b7c814c65c9682909" dependencies = [ "aes-gcm-siv", "base64 0.21.7", diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index c3d9cd375..534ba094c 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -8,8 +8,8 @@ edition = "2021" [dependencies] clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } -solana-sdk = "=1.17.24" -solana-client = "=1.17.24" +solana-sdk = "=1.17.25" +solana-client = "=1.17.25" serde = "1.0.186" serde_json = { version = "1.0.114", features = ["preserve_order"] } ethnum = { version = "1.5", default-features = false, features = ["serde"] } diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index ce6537a44..6ce867c1d 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -8,10 +8,10 @@ edition = "2021" [dependencies] clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } -solana-sdk = "=1.17.24" -solana-client = "=1.17.24" -solana-clap-utils = "=1.17.24" -solana-cli-config = "=1.17.24" +solana-sdk = "=1.17.25" +solana-client = "=1.17.25" +solana-clap-utils = "=1.17.25" +solana-cli-config = "=1.17.25" hex = "0.4.2" serde = "1.0.186" serde_json = { version = "1.0.114", features = ["preserve_order"] } diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index b08bb133b..a33410f5f 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -10,13 +10,13 @@ thiserror = "1.0" anyhow = "1.0" bincode = "1.3.1" evm-loader = { path = "../program", default-features = false, features = ["log", "async-trait"] } -solana-sdk = "=1.17.24" -solana-client = "=1.17.24" -solana-clap-utils = "=1.17.24" -solana-cli-config = "=1.17.24" -solana-cli = "=1.17.24" -solana-transaction-status = "=1.17.24" -solana-program-test = "=1.17.24" +solana-sdk = "=1.17.25" +solana-client = "=1.17.25" +solana-clap-utils = "=1.17.25" +solana-cli-config = "=1.17.25" +solana-cli = "=1.17.25" +solana-transaction-status = "=1.17.25" +solana-program-test = "=1.17.25" spl-token = { version = "~4.0", default-features = false, features = ["no-entrypoint"] } spl-associated-token-account = { version = "~2.3", default-features = false, features = ["no-entrypoint"] } bs58 = "0.5.0" diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index ac6927396..4508ab2d3 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -37,7 +37,7 @@ default = ["custom-heap"] [dependencies] linked_list_allocator = { version = "0.10", default-features = false } evm-loader-macro = { path = "../program-macro" } -solana-program = { version = "=1.17.24", default-features = false } +solana-program = { version = "=1.17.25", default-features = false } spl-token = { version = "~4.0", default-features = false, features = ["no-entrypoint"] } spl-associated-token-account = { version = "~2.3", default-features = false, features = ["no-entrypoint"] } mpl-token-metadata = { version = "~4.1", default-features = false } From 99ded0b5a0868e017ef8f8113f90a52f31fa8bad Mon Sep 17 00:00:00 2001 From: Vitali Date: Thu, 14 Mar 2024 11:03:33 +0200 Subject: [PATCH 133/318] NDEV-2749 Update devnet.toml (#336) * Update devnet.toml Add config for USDC token --- evm_loader/program/config/devnet.toml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/evm_loader/program/config/devnet.toml b/evm_loader/program/config/devnet.toml index 57f8f233d..00f47003c 100644 --- a/evm_loader/program/config/devnet.toml +++ b/evm_loader/program/config/devnet.toml @@ -396,4 +396,8 @@ token = "89dre8rZjLNft7HoupGiyxu3MNftR577ZYu8bHe2kK7g" [chain.sol] id = 245022927 -token = "So11111111111111111111111111111111111111112" \ No newline at end of file +token = "So11111111111111111111111111111111111111112" + +[chain.usdc] +id = 245022928 +token = "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU" From 775a43a9b6380cd5f9ab42758d86c757b93b719d Mon Sep 17 00:00:00 2001 From: Kristina Nikolaeva <112946046+kristinaNikolaevaa@users.noreply.github.com> Date: Thu, 14 Mar 2024 10:48:19 +0100 Subject: [PATCH 134/318] ci action checkout version up (#342) --- .buildkite/pipeline.yml | 7 ------- .github/workflows/deploy.py | 2 +- .github/workflows/github_api_client.py | 5 ----- .github/workflows/pipeline.yml | 8 ++++---- 4 files changed, 5 insertions(+), 17 deletions(-) delete mode 100644 .buildkite/pipeline.yml diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml deleted file mode 100644 index 6504ce060..000000000 --- a/.buildkite/pipeline.yml +++ /dev/null @@ -1,7 +0,0 @@ -steps: - - - label: "Dummy workflow" - commands: - - echo "Dummy step" - agents: - queue: "testing" diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index 94bf327b0..b7bfd5e10 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -193,7 +193,7 @@ def trigger_proxy_action(head_ref_branch, base_ref_branch, github_ref, github_sh github = GithubClient(token) - if head_ref_branch in github.get_branches_list(PROXY_ENDPOINT): + if GithubClient.is_branch_exist(PROXY_ENDPOINT, head_ref_branch): proxy_branch = head_ref_branch elif re.match(VERSION_BRANCH_TEMPLATE, base_ref_branch): proxy_branch = base_ref_branch diff --git a/.github/workflows/github_api_client.py b/.github/workflows/github_api_client.py index 3aa3fd850..352e53b82 100644 --- a/.github/workflows/github_api_client.py +++ b/.github/workflows/github_api_client.py @@ -38,11 +38,6 @@ def run_proxy_dispatches(self, proxy_branch, github_ref, github_sha, test_set, i raise RuntimeError("proxy-model.py action is not triggered") @staticmethod - def get_branches_list(endpoint): - proxy_branches_obj = requests.get( - f"{endpoint}/branches?per_page=100").json() - return [item["name"] for item in proxy_branches_obj] - @staticmethod def is_branch_exist(endpoint, branch): if branch: response = requests.get(f"{endpoint}/branches/{branch}") diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index ba86f7d2a..42109142b 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -27,7 +27,7 @@ jobs: build-neon-evm: runs-on: neon-evm-1 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 @@ -45,7 +45,7 @@ jobs: needs: - build-neon-evm steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Define base branch if the action is tag creation @@ -82,7 +82,7 @@ jobs: needs: - build-neon-evm steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Trigger proxy build @@ -103,7 +103,7 @@ jobs: - trigger-proxy-tests - run-neon-evm-tests steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Finalize image From e95110129240a7eb551261e3ff7bb2686443c5ce Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Mar 2024 17:26:17 +0100 Subject: [PATCH 135/318] Bump proc-macro2 from 1.0.78 to 1.0.79 in /evm_loader (#341) Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.78 to 1.0.79. - [Release notes](https://github.com/dtolnay/proc-macro2/releases) - [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.78...1.0.79) --- updated-dependencies: - dependency-name: proc-macro2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index c8a9e6c05..33f582ccc 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -4038,9 +4038,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] From 22df282653641e060487f503eb5d79ba7e69500a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 15 Mar 2024 09:37:38 +0100 Subject: [PATCH 136/318] Bump strum from 0.26.1 to 0.26.2 in /evm_loader (#344) Bumps [strum](https://github.com/Peternator7/strum) from 0.26.1 to 0.26.2. - [Release notes](https://github.com/Peternator7/strum/releases) - [Changelog](https://github.com/Peternator7/strum/blob/master/CHANGELOG.md) - [Commits](https://github.com/Peternator7/strum/compare/v0.26.1...v0.26.2) --- updated-dependencies: - dependency-name: strum dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 6 +++--- evm_loader/lib/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 33f582ccc..64cdbaeab 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -3391,7 +3391,7 @@ dependencies = [ "solana-transaction-status", "spl-associated-token-account", "spl-token", - "strum 0.26.1", + "strum 0.26.2", "strum_macros 0.26.2", "thiserror", "tokio", @@ -6492,9 +6492,9 @@ dependencies = [ [[package]] name = "strum" -version = "0.26.1" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "723b93e8addf9aa965ebe2d11da6d7540fa2283fcea14b3371ff055f7ba13f5f" +checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" [[package]] name = "strum_macros" diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index a33410f5f..a4ffe5745 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -40,7 +40,7 @@ web3 = "0.19.0" neon-lib-interface = { path = "../lib-interface" } abi_stable = "0.11.2" async-ffi = { version = "0.5.0", features = ["abi_stable"] } -strum = "0.26.1" +strum = "0.26.2" strum_macros = "0.26.2" clap = "2.33.3" lazy_static = "1.4.0" From 72bb9cbe4aa9c8ef25401c4dfbd4901dc484ec36 Mon Sep 17 00:00:00 2001 From: Denis Date: Fri, 15 Mar 2024 11:10:03 +0200 Subject: [PATCH 137/318] NDEV-2764: Update Solana dependencies to 1.17.26 (#346) --- .github/workflows/deploy.py | 4 +- evm_loader/Cargo.lock | 208 +++++++++++++++++----------------- evm_loader/api/Cargo.toml | 4 +- evm_loader/cli/Cargo.toml | 8 +- evm_loader/lib/Cargo.toml | 14 +-- evm_loader/program/Cargo.toml | 2 +- 6 files changed, 120 insertions(+), 120 deletions(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index b7bfd5e10..203df3a76 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -32,8 +32,8 @@ IMAGE_NAME = os.environ.get("IMAGE_NAME") RUN_LINK_REPO = os.environ.get("RUN_LINK_REPO") DOCKERHUB_ORG_NAME = os.environ.get("DOCKERHUB_ORG_NAME") -SOLANA_NODE_VERSION = 'v1.17.25' -SOLANA_BPF_VERSION = 'v1.17.25' +SOLANA_NODE_VERSION = 'v1.17.26' +SOLANA_BPF_VERSION = 'v1.17.26' VERSION_BRANCH_TEMPLATE = r"[vt]{1}\d{1,2}\.\d{1,2}\.x.*" docker_client = docker.APIClient() diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 64cdbaeab..4cfcd1e89 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -4992,9 +4992,9 @@ dependencies = [ [[package]] name = "solana-account-decoder" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b6faa78521915895cbe52f62c5ba29e0962fff976271ec983a68a6e6b9f6a" +checksum = "9cc86b525b20c20fd43a6c663641397e040b303601236f906af9e6d1a4cf4b03" dependencies = [ "Inflector", "base64 0.21.7", @@ -5017,9 +5017,9 @@ dependencies = [ [[package]] name = "solana-accounts-db" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd6a1553b26a656730428fcb9d888ae67f9459e0d11d344224ad110f894f58e" +checksum = "a6008537ca7281b564406832512ccc54eb709a71686ba1f47240f585ca1cd26e" dependencies = [ "arrayref", "bincode", @@ -5076,9 +5076,9 @@ dependencies = [ [[package]] name = "solana-address-lookup-table-program" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00cfecfcf82ce18010a93fca9b1225c8fc2aed50b39687b83131e115477987b3" +checksum = "57b47fd167574c2b8c9e8d4083d273b21a93563199ecf06538e18d69b180deaa" dependencies = [ "bincode", "bytemuck", @@ -5097,9 +5097,9 @@ dependencies = [ [[package]] name = "solana-banks-client" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7ab648b93dc07615d9fa2f08a5881b04a4da1de1add36f510c5115ffd17768e" +checksum = "99d9c1363cc52897701c7941314e2dc324dfdb3a8f116a96fa27a3bc0161486f" dependencies = [ "borsh 0.10.3", "futures", @@ -5114,9 +5114,9 @@ dependencies = [ [[package]] name = "solana-banks-interface" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a98467b41a47e933f37ec322aca24548ff8673af8760857d864d99a4ad7143f" +checksum = "6e80947f83db9141ee3926aaa9e15dc2979a6fdfc69b46fe55cb15a8e4f45230" dependencies = [ "serde", "solana-sdk", @@ -5125,9 +5125,9 @@ dependencies = [ [[package]] name = "solana-banks-server" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175dfcce508944095b3ed6c9638c4f9b4384335a434c84d038279d84a101a447" +checksum = "056fa81be1fd095471736aca928ea883caaefb02c667371c6c16319965cb3c2f" dependencies = [ "bincode", "crossbeam-channel", @@ -5145,9 +5145,9 @@ dependencies = [ [[package]] name = "solana-bpf-loader-program" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942697980093d9b974493386d4739c8dca13411ffcaede34fa9de116715ea6b6" +checksum = "3f9f1daa9d799b1f8cf78e3e83161962f242622b96cdb66886327eb5fd5aad61" dependencies = [ "bincode", "byteorder", @@ -5164,9 +5164,9 @@ dependencies = [ [[package]] name = "solana-bucket-map" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "873df2da0e84f56a2c488188da8a6723969cd183be3a79bc8108d0061be1c9d6" +checksum = "c08ab4bd4fad305447a8528b2ce39e2ae6a1324b69a2eac109673bbdfd0b9de3" dependencies = [ "bv", "bytemuck", @@ -5182,9 +5182,9 @@ dependencies = [ [[package]] name = "solana-clap-utils" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4b76f277d3c922d15ffcb30e0aab0919fe5691017278038a5d0935481607fc9" +checksum = "72605419dff177e918f399c2c0843ea74b7fb0316821beedcf86a35a313ffeda" dependencies = [ "chrono", "clap 2.34.0", @@ -5199,9 +5199,9 @@ dependencies = [ [[package]] name = "solana-cli" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f574acb2d3cba2c0751efe2d59ab06a7dddd7c3368ff057d2f7faf59f06e94ec" +checksum = "42a31ecea3a674341823ae3fd09fe3b31b86ece5ced2dc7113e14cdf29b4bcf0" dependencies = [ "bincode", "bs58 0.4.0", @@ -5250,9 +5250,9 @@ dependencies = [ [[package]] name = "solana-cli-config" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd2e387f55b824a56c9f5d969ff2262bdc354125f00b85d9f9a9d42f8186fbf6" +checksum = "3f357772ec92837b02c0d30220f8f220f23bb4c31377cbc36ec48bc007a47917" dependencies = [ "dirs-next", "lazy_static", @@ -5266,9 +5266,9 @@ dependencies = [ [[package]] name = "solana-cli-output" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad011b611f8d783fb80eabfc4815304e878e300b2e32179e0cd3ebb890a2ece9" +checksum = "98172e363fc102c8049ae2f867ba6e292f415a7d5c8e933ffc1f78c1e2e99a72" dependencies = [ "Inflector", "base64 0.21.7", @@ -5293,9 +5293,9 @@ dependencies = [ [[package]] name = "solana-client" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab357a45351eeab99539eed5af638af9d577a32fdefa25baf2504fccfb97cab9" +checksum = "f72cf0b6a5ed6039eed9e5afae0b7c5e669a8798c1b639c11441fbf492782ea0" dependencies = [ "async-trait", "bincode", @@ -5326,9 +5326,9 @@ dependencies = [ [[package]] name = "solana-compute-budget-program" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75ae20a4b7848724ba315ef67c2090f738a41e2ddbc08eecdd406313b8cb7f9" +checksum = "5d3276b8678aa0cbbf9c2d668e93e7c0b6388fe5a9d77da68686891f06157d4c" dependencies = [ "solana-program-runtime", "solana-sdk", @@ -5336,9 +5336,9 @@ dependencies = [ [[package]] name = "solana-config-program" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677b61fe38df5db47589d6d09085baf8792006a268447b8fe0542b462a127f2f" +checksum = "5767bbda019740220815229fa9219bfe8314ad9f221fd4b77708679780581c26" dependencies = [ "bincode", "chrono", @@ -5350,9 +5350,9 @@ dependencies = [ [[package]] name = "solana-connection-cache" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a3f6a921263f29e0a7f808fe9659a3fc7e6dfbd42ce4811ca95436a95aee89b" +checksum = "ce205152869fd375d8c26bc88ffa4e21ee2f4d9cd708ff0387e178b19bbc1709" dependencies = [ "async-trait", "bincode", @@ -5372,9 +5372,9 @@ dependencies = [ [[package]] name = "solana-cost-model" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa1e9853c0511e9730a1dca659d064012003053d35ceefe33f779c1c9496bab8" +checksum = "5fe61bc1ff78eed9c4b6a87b0e1cdaea5944beca27d686c2deb28d61ff40022d" dependencies = [ "lazy_static", "log", @@ -5396,9 +5396,9 @@ dependencies = [ [[package]] name = "solana-faucet" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ff31c13459aacb78360cdb53d575d4daf6d33a1bf4d19677b5a0b721f1d7e67" +checksum = "89e687b60ed60f29e9aeef0612fe68315c3d8e41e1527a548aae1aa3956c142e" dependencies = [ "bincode", "byteorder", @@ -5420,9 +5420,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de577bb681dfc3afeda6247dbc381f8c74a31eeed141883e6a9a36e93fdcf784" +checksum = "fd9fcb543a2863fd99eda14789263dfc67f79cde4abbb6d318d1c267436c6154" dependencies = [ "ahash 0.8.5", "blake3", @@ -5450,9 +5450,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi-macro" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6373184605334be54d85564b657e7b4d88bdf4e3c011abccce4fd2712c96caf" +checksum = "a3b1c19e03e4fa240591fe3e61802b76a44d28bb595e309a670a3041db85e244" dependencies = [ "proc-macro2", "quote", @@ -5462,9 +5462,9 @@ dependencies = [ [[package]] name = "solana-loader-v4-program" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "770ace194d2c96f8d99315db722d20dcbf330c46e3c6bcef60c47d5d45252184" +checksum = "0634a0245496f717329a68af0d5664cf7813ddf7e61afd215aa99c5eb5c9c4f6" dependencies = [ "log", "solana-measure", @@ -5475,9 +5475,9 @@ dependencies = [ [[package]] name = "solana-logger" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6959774302d4407c77d5fbdd4d5e31c2696f5ac1c74bf0cdcac704b474bc6fd" +checksum = "e77721492babad3cd266ce3f2809c5d515d503583191ff116df1c2e736b33710" dependencies = [ "env_logger", "lazy_static", @@ -5486,9 +5486,9 @@ dependencies = [ [[package]] name = "solana-measure" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9327e70f9cb17094077531449f7487677c4d380bd99b9494dca85af5ea5f5e19" +checksum = "0204c343635074ca71a9488a644afaa95c6c09c3430d0a97274a21ccb49a15d9" dependencies = [ "log", "solana-sdk", @@ -5496,9 +5496,9 @@ dependencies = [ [[package]] name = "solana-metrics" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca5e3931823a9bdaee5d65d27195804127911578abddaddda3025f6af6647c08" +checksum = "1bec1c75e8f8bfe6479aaebbcdb65d54070381d5d8a852a270d3abc9208b4563" dependencies = [ "crossbeam-channel", "gethostname", @@ -5511,9 +5511,9 @@ dependencies = [ [[package]] name = "solana-net-utils" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fed17001119742b35ce06b18823b4901313860c5dd495e32bccf070424b2947" +checksum = "7fb3d97ee43499ef48dc756a6a6f4b26f26ae33d4abed9aa2277e836d51ce8ee" dependencies = [ "bincode", "clap 3.2.23", @@ -5533,9 +5533,9 @@ dependencies = [ [[package]] name = "solana-perf" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c2a6d77ead9c96aa2a84afd0662d01c55abec61b514d8c9e2dc5627a1d74c7b" +checksum = "c42e6a5e7e5a8e8e40f9fd5641c6020875c245ad3d8a204c91a3b3f1a3ba104a" dependencies = [ "ahash 0.8.5", "bincode", @@ -5562,9 +5562,9 @@ dependencies = [ [[package]] name = "solana-program" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd3bcc37b433d7e8d45236a0f5aa68df462c4d5c6a709a6efd916988ce3ac08" +checksum = "c0c7604cda91c5d6202fbe1191675e34134d065bc0659e0457c7ac04a79e4a11" dependencies = [ "ark-bn254", "ark-ec", @@ -5616,9 +5616,9 @@ dependencies = [ [[package]] name = "solana-program-runtime" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "618fb4dc2238daa2737805659c4ad380fb61dd27a40cfd14e63d890d1e4335b0" +checksum = "7a21bdfe76128836db0bf6227e6e7f4f2b87e496ce35da5c01ba95a888323a89" dependencies = [ "base64 0.21.7", "bincode", @@ -5644,9 +5644,9 @@ dependencies = [ [[package]] name = "solana-program-test" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d04f60ba923ba30072e31cd347b2792aea40738d93fb7c12426d1a5957cf13b" +checksum = "e14452c00783802b3a74fb6413073b434a0a27b527b717e566cb7dcae3ab79e5" dependencies = [ "assert_matches", "async-trait", @@ -5674,9 +5674,9 @@ dependencies = [ [[package]] name = "solana-pubsub-client" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0daf3d4daa67ef7550fe1a4b88dad32164263c9b7b7f0477caacae6b0220ceb5" +checksum = "0ca065a3e2edfff5013ed174ba2d5f4c7a337cce4d38ded431a346c99be9951a" dependencies = [ "crossbeam-channel", "futures-util", @@ -5699,9 +5699,9 @@ dependencies = [ [[package]] name = "solana-quic-client" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39f1c28340a1845d18ab85f96c57f283a588745f4f334a77a0cc7a13a6f2eae4" +checksum = "bce18b1ed4819df7024e22a04c8f9acf1241b7de216338791281d64d0caebfeb" dependencies = [ "async-mutex", "async-trait", @@ -5726,9 +5726,9 @@ dependencies = [ [[package]] name = "solana-rayon-threadlimit" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c8f657c79b681bd49b4106242890225ba0df190cc83109394a1fcc8e3c54819" +checksum = "489beb480ab72ad82852542424c628f0d3d277d499b1258d6dc0cc77e7c0eb25" dependencies = [ "lazy_static", "num_cpus", @@ -5736,9 +5736,9 @@ dependencies = [ [[package]] name = "solana-remote-wallet" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8d8bc9c75495fcf301a85bda5c921213dbff9dc8d6e7708c74eaa9d06e8e395" +checksum = "4725d4067126576e38598763bce86f5eedf8afe79db7cfc25ece8aa5b456289d" dependencies = [ "console", "dialoguer", @@ -5756,9 +5756,9 @@ dependencies = [ [[package]] name = "solana-rpc-client" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f050027aff888d96c5a659dc164998d6ec25aadde649f1474d2cbb73b2a72de8" +checksum = "09aff1fc674359a6b07b52b922377e4cfce10a8079ff808454b9e13514823952" dependencies = [ "async-trait", "base64 0.21.7", @@ -5782,9 +5782,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-api" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a273e98835985e15e3774267af94a0631b1e27ae187b242e7fbacf1c1fad29fb" +checksum = "f50f21cc5fe22ff5d6d119dca54449dda572a9e2571762a01bcd3ace0d94123e" dependencies = [ "base64 0.21.7", "bs58 0.4.0", @@ -5804,9 +5804,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-nonce-utils" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458fc8f9d14e42d397e7867288fdff47de6ca9f949b1f11217e807a65bf17c43" +checksum = "490f14d7b2d02075081cc6aa3bcdebbaa95c819cf3da070d0795bebcb09eee19" dependencies = [ "clap 2.34.0", "solana-clap-utils", @@ -5817,9 +5817,9 @@ dependencies = [ [[package]] name = "solana-runtime" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0c4ebc4711eaf1507728e3d80883dc6233ce19a0c290932f52065688f8fc3e" +checksum = "500cabeb6ee14d6eb7facd6ac7b06770fd308babf7a3ff2687ef90612a2a8b81" dependencies = [ "arrayref", "base64 0.21.7", @@ -5894,9 +5894,9 @@ dependencies = [ [[package]] name = "solana-sdk" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1de78b8c4fa09e4b90d720b2aa3ef3c80c4b956aa3d14616261a7f4bdf64c04" +checksum = "9e4be7f1c6c16b238cf978352e896c8e21aab7dfb500f296e346018486627cc8" dependencies = [ "assert_matches", "base64 0.21.7", @@ -5948,9 +5948,9 @@ dependencies = [ [[package]] name = "solana-sdk-macro" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b5055c4b785cf3e5f2f52d687bdd1a795755105fe4365182396bc8b6bb41cd5" +checksum = "422b14d1918e67c18ff03f2d9435512fa679b6ece653929be4967d9196cf7fa3" dependencies = [ "bs58 0.4.0", "proc-macro2", @@ -5967,9 +5967,9 @@ checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" [[package]] name = "solana-send-transaction-service" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9774fd9effd1cdccbd1e5dff9f3ee1a806643939be215a44aeac3982d15bdfc" +checksum = "d718605132cad6cef1c921867f471eb3a4bdd549047f887688622807790445f8" dependencies = [ "crossbeam-channel", "log", @@ -5983,9 +5983,9 @@ dependencies = [ [[package]] name = "solana-stake-program" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624f4287174fab61b21ac1c185c31bc575dd65f7f11600cb483dbe8e25da7531" +checksum = "6a55c7f8e7d82a19cf3e850b273f3dddd0a4b5775fddf7e5cbe5650d0d142aec" dependencies = [ "bincode", "log", @@ -5998,9 +5998,9 @@ dependencies = [ [[package]] name = "solana-streamer" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05a31fb5a63f80318a5b03148d9132e3bb1f2125e0bebe9bedfc095d1b16753c" +checksum = "93d296461ef55ae177490256f743e020e83400634aa5c88946331b36abdca89e" dependencies = [ "async-channel", "bytes", @@ -6030,9 +6030,9 @@ dependencies = [ [[package]] name = "solana-system-program" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e9a95bc33e2e62c4b3d029f0cfe3b1ce6308dd82bc247fdfcf388f984a8cc49" +checksum = "ab20ec734339b64f0c77c60a0657cff567753069225ebd5aec1d967a7f7597ee" dependencies = [ "bincode", "log", @@ -6044,9 +6044,9 @@ dependencies = [ [[package]] name = "solana-thin-client" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b19c4e6d850b0b8598f84513b4b5cdcc36d095df1b99725704c087d4df7e9eb" +checksum = "69dab2fbd46683f590403e02a42f8f70825b516f073d02c7ebf3b56fcdf9b7fc" dependencies = [ "bincode", "log", @@ -6059,9 +6059,9 @@ dependencies = [ [[package]] name = "solana-tpu-client" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e6cb310a96dad1a34e7cacd9344800206df21c5f891459240621c96e13c6ee" +checksum = "bab3c608ffefc39b80659c469569751a2d92887d55d2e7da1cac3676f6323993" dependencies = [ "async-trait", "bincode", @@ -6083,9 +6083,9 @@ dependencies = [ [[package]] name = "solana-transaction-status" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd87fd7b4164cb7cbe047e6376e9585668923ed8072ea32b7e878f25c90fd056" +checksum = "d70f8c51e706b52a9ea067305f989e0c85baabc259c388d929aa77b521a09c94" dependencies = [ "Inflector", "base64 0.21.7", @@ -6108,9 +6108,9 @@ dependencies = [ [[package]] name = "solana-udp-client" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4886959ef4094af0d9ceda93dc468fa7088f46b22cc7d0c8c18086389e8d63e7" +checksum = "b54fb59fdc12787401898968bc90cb0abd839536a1159d33ff5c667c244fb711" dependencies = [ "async-trait", "solana-connection-cache", @@ -6123,9 +6123,9 @@ dependencies = [ [[package]] name = "solana-version" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "310500e993127ea009a2c41daf2e004d436d3041cdee6673112804c574a41eda" +checksum = "876718d1e3b48cb12a2a4a0726a8274c3e2205d890c11e462c05a97fb20cb15d" dependencies = [ "log", "rustc_version", @@ -6139,9 +6139,9 @@ dependencies = [ [[package]] name = "solana-vote" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccb5e4854105e8fe8172bd379d6d0689bba28109ba39a001430e13c75c3ba034" +checksum = "d75b36690e2fe3c72fc894d03b362fec45c0c99edad28b68de12e1a5548f258b" dependencies = [ "crossbeam-channel", "itertools 0.10.5", @@ -6158,9 +6158,9 @@ dependencies = [ [[package]] name = "solana-vote-program" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04079fab6e48794ec194c9bb44422672fa66594b9979dfc97d62c1556434ee7a" +checksum = "82c7dfb9a13f0399eaedfe07d3b61515c39837514206722c98f0319cfc65ffab" dependencies = [ "bincode", "log", @@ -6180,9 +6180,9 @@ dependencies = [ [[package]] name = "solana-zk-token-proof-program" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c266a0aad5d82e8b8423616506e07025ddf42acec5c00e55a85a55841dffc7fe" +checksum = "7e1984585d8abcec686c4a8ecba58c90ec70922c291ce3d75da5bf5248c79ed8" dependencies = [ "bytemuck", "num-derive 0.3.3", @@ -6194,9 +6194,9 @@ dependencies = [ [[package]] name = "solana-zk-token-sdk" -version = "1.17.25" +version = "1.17.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9e0b222c3aad3df370ae87e993b32419906f00827a1677b7c814c65c9682909" +checksum = "70d9376861d6061f6e79c935706a4241e2195a066c8cf9a33ae61de0eb0670e9" dependencies = [ "aes-gcm-siv", "base64 0.21.7", diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 534ba094c..b629812c3 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -8,8 +8,8 @@ edition = "2021" [dependencies] clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } -solana-sdk = "=1.17.25" -solana-client = "=1.17.25" +solana-sdk = "=1.17.26" +solana-client = "=1.17.26" serde = "1.0.186" serde_json = { version = "1.0.114", features = ["preserve_order"] } ethnum = { version = "1.5", default-features = false, features = ["serde"] } diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index 6ce867c1d..15081be81 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -8,10 +8,10 @@ edition = "2021" [dependencies] clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } -solana-sdk = "=1.17.25" -solana-client = "=1.17.25" -solana-clap-utils = "=1.17.25" -solana-cli-config = "=1.17.25" +solana-sdk = "=1.17.26" +solana-client = "=1.17.26" +solana-clap-utils = "=1.17.26" +solana-cli-config = "=1.17.26" hex = "0.4.2" serde = "1.0.186" serde_json = { version = "1.0.114", features = ["preserve_order"] } diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index a4ffe5745..9499fe012 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -10,13 +10,13 @@ thiserror = "1.0" anyhow = "1.0" bincode = "1.3.1" evm-loader = { path = "../program", default-features = false, features = ["log", "async-trait"] } -solana-sdk = "=1.17.25" -solana-client = "=1.17.25" -solana-clap-utils = "=1.17.25" -solana-cli-config = "=1.17.25" -solana-cli = "=1.17.25" -solana-transaction-status = "=1.17.25" -solana-program-test = "=1.17.25" +solana-sdk = "=1.17.26" +solana-client = "=1.17.26" +solana-clap-utils = "=1.17.26" +solana-cli-config = "=1.17.26" +solana-cli = "=1.17.26" +solana-transaction-status = "=1.17.26" +solana-program-test = "=1.17.26" spl-token = { version = "~4.0", default-features = false, features = ["no-entrypoint"] } spl-associated-token-account = { version = "~2.3", default-features = false, features = ["no-entrypoint"] } bs58 = "0.5.0" diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 4508ab2d3..2433fd991 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -37,7 +37,7 @@ default = ["custom-heap"] [dependencies] linked_list_allocator = { version = "0.10", default-features = false } evm-loader-macro = { path = "../program-macro" } -solana-program = { version = "=1.17.25", default-features = false } +solana-program = { version = "=1.17.26", default-features = false } spl-token = { version = "~4.0", default-features = false, features = ["no-entrypoint"] } spl-associated-token-account = { version = "~2.3", default-features = false, features = ["no-entrypoint"] } mpl-token-metadata = { version = "~4.1", default-features = false } From 50e6b1cd73ec95ebbbf4b0b7fcc8edb7e107245b Mon Sep 17 00:00:00 2001 From: Oleg Date: Fri, 15 Mar 2024 16:19:44 +0300 Subject: [PATCH 138/318] NDEV-2710 Change multitoken settings for stand (#340) Add usdt and eth networks for our stands --- Dockerfile | 1 + ci/deploy-multi-tokens.sh | 20 ++++++++++++++++++++ ci/keys/eth_token_keypair.json | 1 + ci/keys/usdt_token_keypair.json | 1 + ci/solana-run-neon.sh | 1 + evm_loader/program/config/default.toml | 8 ++++---- 6 files changed, 28 insertions(+), 4 deletions(-) create mode 100755 ci/deploy-multi-tokens.sh create mode 100644 ci/keys/eth_token_keypair.json create mode 100644 ci/keys/usdt_token_keypair.json diff --git a/Dockerfile b/Dockerfile index 636b6c3fb..66594c001 100644 --- a/Dockerfile +++ b/Dockerfile @@ -49,6 +49,7 @@ COPY ci/wait-for-solana.sh \ ci/wait-for-neon.sh \ ci/solana-run-neon.sh \ ci/deploy-evm.sh \ + ci/deploy-multi-tokens.sh \ ci/create-test-accounts.sh \ ci/evm_loader-keypair.json \ /opt/ diff --git a/ci/deploy-multi-tokens.sh b/ci/deploy-multi-tokens.sh new file mode 100755 index 000000000..bb2f9db96 --- /dev/null +++ b/ci/deploy-multi-tokens.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +set -em + +echo "Deploy USDT token" + +USDT_ADDRESS=$(solana address -k /opt/keys/usdt_token_keypair.json) + +spl-token -u http://localhost:8899 create-token --decimals 6 /opt/keys/usdt_token_keypair.json +spl-token -u http://localhost:8899 create-account $USDT_ADDRESS +spl-token -u http://localhost:8899 mint $USDT_ADDRESS 100000000000 + + +echo "Deploy ETH token" + +ETH_ADDRESS=$(solana address -k /opt/keys/eth_token_keypair.json) + +spl-token -u http://localhost:8899 create-token --decimals 8 /opt/keys/eth_token_keypair.json +spl-token -u http://localhost:8899 create-account $ETH_ADDRESS +spl-token -u http://localhost:8899 mint $ETH_ADDRESS 100000000000 \ No newline at end of file diff --git a/ci/keys/eth_token_keypair.json b/ci/keys/eth_token_keypair.json new file mode 100644 index 000000000..c5ecbf397 --- /dev/null +++ b/ci/keys/eth_token_keypair.json @@ -0,0 +1 @@ +[149,157,253,18,79,248,207,190,171,37,143,234,67,148,65,17,143,170,213,176,108,59,151,135,190,16,136,132,66,83,171,245,207,17,33,212,150,94,60,140,151,21,192,215,8,4,188,12,177,162,122,143,210,29,168,72,15,167,83,22,57,55,216,224] \ No newline at end of file diff --git a/ci/keys/usdt_token_keypair.json b/ci/keys/usdt_token_keypair.json new file mode 100644 index 000000000..7c3449f27 --- /dev/null +++ b/ci/keys/usdt_token_keypair.json @@ -0,0 +1 @@ +[69,155,233,42,154,80,125,187,83,175,85,62,77,186,55,98,247,62,182,65,77,158,146,42,242,167,167,161,140,231,54,161,24,80,108,149,163,214,41,81,196,6,86,50,237,190,104,217,0,12,98,124,40,30,211,87,149,74,225,39,48,7,131,80] \ No newline at end of file diff --git a/ci/solana-run-neon.sh b/ci/solana-run-neon.sh index 496970eba..b7b35527b 100755 --- a/ci/solana-run-neon.sh +++ b/ci/solana-run-neon.sh @@ -38,6 +38,7 @@ fi export RUST_LOG=solana_runtime::system_instruction_processor=trace,solana_runtime::message_processor=debug,solana_bpf_loader=debug,solana_rbpf=debug solana-test-validator "${VALIDATOR_ARGS[@]}" > /dev/null & ./wait-for-solana.sh ${SOLANA_WAIT_TIMEOUT:-60} +./deploy-multi-tokens.sh neon-cli --url http://localhost:8899 --evm_loader $EVM_LOADER \ --commitment confirmed \ diff --git a/evm_loader/program/config/default.toml b/evm_loader/program/config/default.toml index e334b68db..986667357 100644 --- a/evm_loader/program/config/default.toml +++ b/evm_loader/program/config/default.toml @@ -41,10 +41,10 @@ token = "HPsV9Deocecw3GeZv1FkAPNCBRfuVyfw9MMwjwRe1xaU" id = 112 token = "So11111111111111111111111111111111111111112" -[chain.abc] +[chain.usdt] id = 113 -token = "HPsV9Deocecw3GeZv1FkAPNCBRfuVyfw9MMwjwRe1xaU" +token = "2duuuuhNJHUYqcnZ7LKfeufeeTBgSJdftf2zM3cZV6ym" -[chain.def] +[chain.eth] id = 114 -token = "HPsV9Deocecw3GeZv1FkAPNCBRfuVyfw9MMwjwRe1xaU" \ No newline at end of file +token = "EwJYd3UAFAgzodVeHprB2gMQ68r4ZEbbvpoVzCZ1dGq5" \ No newline at end of file From 9aecb98862bd816f49376a34a1c7629d934a2aad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Mar 2024 09:50:20 +0100 Subject: [PATCH 139/318] Bump thiserror from 1.0.57 to 1.0.58 in /evm_loader (#345) Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.57 to 1.0.58. - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](https://github.com/dtolnay/thiserror/compare/1.0.57...1.0.58) --- updated-dependencies: - dependency-name: thiserror dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 8 ++++---- evm_loader/rpc-client/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 4cfcd1e89..7db3a0a50 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -6691,18 +6691,18 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", diff --git a/evm_loader/rpc-client/Cargo.toml b/evm_loader/rpc-client/Cargo.toml index ee34bd506..cc68d5925 100644 --- a/evm_loader/rpc-client/Cargo.toml +++ b/evm_loader/rpc-client/Cargo.toml @@ -10,7 +10,7 @@ serde = "1.0.189" serde_json = "1.0.107" jsonrpc-v2 = "0.13.0" neon-lib = { path = "../lib" } -thiserror = "1.0.49" +thiserror = "1.0.58" async-trait = "0.1.77" jsonrpsee-core = "0.20.2" jsonrpsee-http-client = "0.20.2" From 70d57f9e45f92f90e7bcf4f80873d03bbb8772bc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Mar 2024 12:49:02 +0100 Subject: [PATCH 140/318] Bump async-trait from 0.1.77 to 0.1.78 in /evm_loader (#349) Bumps [async-trait](https://github.com/dtolnay/async-trait) from 0.1.77 to 0.1.78. - [Release notes](https://github.com/dtolnay/async-trait/releases) - [Commits](https://github.com/dtolnay/async-trait/compare/0.1.77...0.1.78) --- updated-dependencies: - dependency-name: async-trait dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- evm_loader/lib/Cargo.toml | 2 +- evm_loader/program/Cargo.toml | 2 +- evm_loader/rpc-client/Cargo.toml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 7db3a0a50..b053fa59b 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -622,9 +622,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.77" +version = "0.1.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" +checksum = "461abc97219de0eaaf81fe3ef974a540158f3d079c2ab200f891f1a2ef201e85" dependencies = [ "proc-macro2", "quote", diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 9499fe012..0ca4e9acd 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -33,7 +33,7 @@ scroll = "0.11.0" tokio = { version = "1", features = ["full"] } clickhouse = "0.11.6" tracing = "0.1" -async-trait = "0.1.77" +async-trait = "0.1.78" build-info = { version = "0.0.31", features = ["serde"] } enum_dispatch = "0.3.12" web3 = "0.19.0" diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 2433fd991..1a802fc06 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -55,7 +55,7 @@ ethnum = { version = "1.5", default-features = false, features = ["serde"] } cfg-if = { version = "1.0" } log = { version = "0.4", default-features = false, optional = true } maybe-async = "0.2.10" -async-trait = { version = "0.1.77", optional = true } +async-trait = { version = "0.1.78", optional = true } [target.'cfg(target_os = "solana")'.dependencies.maybe-async] version = "0.2.7" diff --git a/evm_loader/rpc-client/Cargo.toml b/evm_loader/rpc-client/Cargo.toml index cc68d5925..898390ebb 100644 --- a/evm_loader/rpc-client/Cargo.toml +++ b/evm_loader/rpc-client/Cargo.toml @@ -11,7 +11,7 @@ serde_json = "1.0.107" jsonrpc-v2 = "0.13.0" neon-lib = { path = "../lib" } thiserror = "1.0.58" -async-trait = "0.1.77" +async-trait = "0.1.78" jsonrpsee-core = "0.20.2" jsonrpsee-http-client = "0.20.2" jsonrpsee-types = "0.22.2" From 09759ed8cb9e360f25ea0777344ee657873b5d4b Mon Sep 17 00:00:00 2001 From: Kristina Nikolaeva <112946046+kristinaNikolaevaa@users.noreply.github.com> Date: Mon, 18 Mar 2024 14:38:42 +0100 Subject: [PATCH 141/318] CI refactoring (#347) * label refactoring * fix name --- .github/workflows/deploy.py | 18 ++++++++---------- .github/workflows/github_api_client.py | 4 ++-- .github/workflows/pipeline.yml | 7 ++++++- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index 203df3a76..f53d5e0eb 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -172,24 +172,22 @@ def stop_containers(project_name): @click.option('--github_ref') @click.option('--github_sha') @click.option('--token') -@click.option('--is_draft') @click.option('--labels') @click.option('--pr_url') @click.option('--pr_number') -def trigger_proxy_action(head_ref_branch, base_ref_branch, github_ref, github_sha, token, is_draft, labels, +def trigger_proxy_action(head_ref_branch, base_ref_branch, github_ref, github_sha, token, labels, pr_url, pr_number): is_develop_branch = github_ref in ['refs/heads/develop', 'refs/heads/master'] is_tag_creating = 'refs/tags/' in github_ref is_version_branch = re.match(VERSION_BRANCH_TEMPLATE, github_ref.replace("refs/heads/", "")) is not None - is_FTS_labeled_not_draft = 'fullTestSuit' in labels and is_draft != "true" - is_extended_FTS_labeled_not_draft = 'extendedFullTestSuit' in labels and is_draft != "true" + is_FTS_labeled = 'fullTestSuit' in labels - if is_extended_FTS_labeled_not_draft: - test_set = "extendedFullTestSuite" - elif is_develop_branch or is_tag_creating or is_version_branch or is_FTS_labeled_not_draft: - test_set = "fullTestSuite" + + if is_develop_branch or is_tag_creating or is_version_branch or is_FTS_labeled: + full_test_suite = True else: - test_set = "basic" + full_test_suite = False + github = GithubClient(token) @@ -210,7 +208,7 @@ def trigger_proxy_action(head_ref_branch, base_ref_branch, github_ref, github_sh runs_before = github.get_proxy_runs_list(proxy_branch) runs_count_before = github.get_proxy_runs_count(proxy_branch) - github.run_proxy_dispatches(proxy_branch, github_ref, github_sha, test_set, initial_pr) + github.run_proxy_dispatches(proxy_branch, github_ref, github_sha, full_test_suite, initial_pr) wait_condition(lambda: github.get_proxy_runs_count(proxy_branch) > runs_count_before) runs_after = github.get_proxy_runs_list(proxy_branch) diff --git a/.github/workflows/github_api_client.py b/.github/workflows/github_api_client.py index 352e53b82..3a9ee7b6a 100644 --- a/.github/workflows/github_api_client.py +++ b/.github/workflows/github_api_client.py @@ -23,9 +23,9 @@ def get_proxy_runs_count(self, proxy_branch): f"{self.proxy_endpoint}/actions/workflows/pipeline.yml/runs?branch={proxy_branch}", headers=self.headers) return int(response.json()["total_count"]) - def run_proxy_dispatches(self, proxy_branch, github_ref, github_sha, test_set, initial_pr): + def run_proxy_dispatches(self, proxy_branch, github_ref, github_sha, full_test_suite, initial_pr): data = {"ref": proxy_branch, - "inputs": {"test_set": test_set, + "inputs": {"full_test_suite": full_test_suite, "neon_evm_commit": github_sha, "neon_evm_branch": github_ref, "initial_pr": initial_pr} diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index 42109142b..ad3fe313c 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -77,6 +77,9 @@ jobs: --github_sha=${GITHUB_SHA} \ --neon_test_branch=${{ steps.neon_test_branch.outputs.value }} \ --base_ref_branch=${{ github.base_ref }} + - name: Cancel the build if job failed + if: "failure()" + uses: "andymckay/cancel-action@0.4" trigger-proxy-tests: runs-on: trigger-runner needs: @@ -93,10 +96,12 @@ jobs: --base_ref_branch=${{ github.base_ref }} \ --github_ref=${{ github.ref }} \ --token=${{secrets.GHTOKEN }} \ - --is_draft=${{github.event.pull_request.draft}} \ --labels='${{ toJson(github.event.pull_request.labels.*.name) }}' \ --pr_url="${{ github.api_url }}/repos/${{ github.repository }}/issues" \ --pr_number="${{ github.event.pull_request.number }}" + - name: Cancel the build if job failed + if: "failure()" + uses: "andymckay/cancel-action@0.4" finalize-image: runs-on: neon-evm-1 needs: From 400f8a42b22218dacf90220a48dd2db4387a5274 Mon Sep 17 00:00:00 2001 From: Kristina Nikolaeva <112946046+kristinaNikolaevaa@users.noreply.github.com> Date: Mon, 18 Mar 2024 17:11:07 +0100 Subject: [PATCH 142/318] fix trigger proxy step (#350) --- .github/workflows/github_api_client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/github_api_client.py b/.github/workflows/github_api_client.py index 3a9ee7b6a..5fd9daafa 100644 --- a/.github/workflows/github_api_client.py +++ b/.github/workflows/github_api_client.py @@ -25,7 +25,7 @@ def get_proxy_runs_count(self, proxy_branch): def run_proxy_dispatches(self, proxy_branch, github_ref, github_sha, full_test_suite, initial_pr): data = {"ref": proxy_branch, - "inputs": {"full_test_suite": full_test_suite, + "inputs": {"full_test_suite": f"{full_test_suite}".lower(), "neon_evm_commit": github_sha, "neon_evm_branch": github_ref, "initial_pr": initial_pr} @@ -35,7 +35,7 @@ def run_proxy_dispatches(self, proxy_branch, github_ref, github_sha, full_test_s click.echo(f"Sent data: {data}") click.echo(f"Status code: {response.status_code}") if response.status_code != 204: - raise RuntimeError("proxy-model.py action is not triggered") + raise RuntimeError("proxy-model.py action is not triggered, error: {response.text}") @staticmethod def is_branch_exist(endpoint, branch): From db78eb94164524d866cda4afb6a33acb0056ad9f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Mar 2024 12:34:20 +0100 Subject: [PATCH 143/318] Bump serde_with from 3.6.1 to 3.7.0 in /evm_loader (#351) Bumps [serde_with](https://github.com/jonasbb/serde_with) from 3.6.1 to 3.7.0. - [Release notes](https://github.com/jonasbb/serde_with/releases) - [Commits](https://github.com/jonasbb/serde_with/compare/v3.6.1...v3.7.0) --- updated-dependencies: - dependency-name: serde_with dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 12 ++++++------ evm_loader/lib/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index b053fa59b..7a3330929 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -3381,7 +3381,7 @@ dependencies = [ "scroll", "serde", "serde_json", - "serde_with 3.6.1", + "serde_with 3.7.0", "solana-clap-utils", "solana-cli", "solana-cli-config", @@ -4771,9 +4771,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.6.1" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15d167997bd841ec232f5b2b8e0e26606df2e7caa4c31b95ea9ca52b200bd270" +checksum = "ee80b0e361bbf88fd2f6e242ccd19cfda072cb0faa6ae694ecee08199938569a" dependencies = [ "base64 0.21.7", "chrono", @@ -4783,7 +4783,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "serde_with_macros 3.6.1", + "serde_with_macros 3.7.0", "time", ] @@ -4801,9 +4801,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.6.1" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "865f9743393e638991566a8b7a479043c2c8da94a33e0a31f18214c9cae0a64d" +checksum = "6561dc161a9224638a31d876ccdfefbc1df91d3f3a8342eddb35f055d48c7655" dependencies = [ "darling", "proc-macro2", diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 0ca4e9acd..cc722f6bd 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -24,7 +24,7 @@ base64 = "0.22" hex = { version = "0.4", features = ["serde"] } serde = "1.0" serde_json = { version = "1.0", features = ["preserve_order"] } -serde_with = { version = "3.6", features = ["hex"] } +serde_with = { version = "3.7", features = ["hex"] } log = "0.4.21" rand = "0.8" ethnum = { version = "1.5", default-features = false, features = ["serde"] } From c18324d91d75f6217b694b2aeba9f5fffab0f33a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Mar 2024 13:42:12 +0100 Subject: [PATCH 144/318] Bump anyhow from 1.0.80 to 1.0.81 in /evm_loader (#353) Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.80 to 1.0.81. - [Release notes](https://github.com/dtolnay/anyhow/releases) - [Commits](https://github.com/dtolnay/anyhow/compare/1.0.80...1.0.81) --- updated-dependencies: - dependency-name: anyhow dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 7a3330929..20117e160 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -381,9 +381,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.80" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" [[package]] name = "ark-bn254" From 4bb497f3c2cf7b8130c57b0285507fb13530daba Mon Sep 17 00:00:00 2001 From: Kristina Nikolaeva <112946046+kristinaNikolaevaa@users.noreply.github.com> Date: Wed, 20 Mar 2024 16:31:40 +0100 Subject: [PATCH 145/318] fixed run_proxy_dispatches (#352) --- .github/workflows/deploy.py | 4 ++-- .github/workflows/github_api_client.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index f53d5e0eb..a3edc75fe 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -188,7 +188,6 @@ def trigger_proxy_action(head_ref_branch, base_ref_branch, github_ref, github_sh else: full_test_suite = False - github = GithubClient(token) if GithubClient.is_branch_exist(PROXY_ENDPOINT, head_ref_branch): @@ -208,7 +207,8 @@ def trigger_proxy_action(head_ref_branch, base_ref_branch, github_ref, github_sh runs_before = github.get_proxy_runs_list(proxy_branch) runs_count_before = github.get_proxy_runs_count(proxy_branch) - github.run_proxy_dispatches(proxy_branch, github_ref, github_sha, full_test_suite, initial_pr) + neon_evm_branch = head_ref_branch if head_ref_branch else github_ref + github.run_proxy_dispatches(proxy_branch, neon_evm_branch, github_sha, full_test_suite, initial_pr) wait_condition(lambda: github.get_proxy_runs_count(proxy_branch) > runs_count_before) runs_after = github.get_proxy_runs_list(proxy_branch) diff --git a/.github/workflows/github_api_client.py b/.github/workflows/github_api_client.py index 5fd9daafa..eb62a9a04 100644 --- a/.github/workflows/github_api_client.py +++ b/.github/workflows/github_api_client.py @@ -23,11 +23,11 @@ def get_proxy_runs_count(self, proxy_branch): f"{self.proxy_endpoint}/actions/workflows/pipeline.yml/runs?branch={proxy_branch}", headers=self.headers) return int(response.json()["total_count"]) - def run_proxy_dispatches(self, proxy_branch, github_ref, github_sha, full_test_suite, initial_pr): + def run_proxy_dispatches(self, proxy_branch, neon_evm_branch, github_sha, full_test_suite, initial_pr): data = {"ref": proxy_branch, "inputs": {"full_test_suite": f"{full_test_suite}".lower(), "neon_evm_commit": github_sha, - "neon_evm_branch": github_ref, + "neon_evm_branch": neon_evm_branch, "initial_pr": initial_pr} } response = requests.post( From 791bc3a6fb588e02853560d819ee853b5953bc28 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Wed, 20 Mar 2024 17:48:04 +0100 Subject: [PATCH 146/318] NDEV-2785: Update Solana to v1.17.27 (#354) --- .github/workflows/deploy.py | 5 +- evm_loader/Cargo.lock | 208 +++++++++++++++++----------------- evm_loader/api/Cargo.toml | 4 +- evm_loader/cli/Cargo.toml | 8 +- evm_loader/lib/Cargo.toml | 14 +-- evm_loader/program/Cargo.toml | 2 +- 6 files changed, 120 insertions(+), 121 deletions(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index a3edc75fe..fc86833e1 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -32,8 +32,8 @@ IMAGE_NAME = os.environ.get("IMAGE_NAME") RUN_LINK_REPO = os.environ.get("RUN_LINK_REPO") DOCKERHUB_ORG_NAME = os.environ.get("DOCKERHUB_ORG_NAME") -SOLANA_NODE_VERSION = 'v1.17.26' -SOLANA_BPF_VERSION = 'v1.17.26' +SOLANA_NODE_VERSION = 'v1.17.27' +SOLANA_BPF_VERSION = 'v1.17.27' VERSION_BRANCH_TEMPLATE = r"[vt]{1}\d{1,2}\.\d{1,2}\.x.*" docker_client = docker.APIClient() @@ -182,7 +182,6 @@ def trigger_proxy_action(head_ref_branch, base_ref_branch, github_ref, github_sh is_version_branch = re.match(VERSION_BRANCH_TEMPLATE, github_ref.replace("refs/heads/", "")) is not None is_FTS_labeled = 'fullTestSuit' in labels - if is_develop_branch or is_tag_creating or is_version_branch or is_FTS_labeled: full_test_suite = True else: diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 20117e160..3bc83303f 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -4992,9 +4992,9 @@ dependencies = [ [[package]] name = "solana-account-decoder" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cc86b525b20c20fd43a6c663641397e040b303601236f906af9e6d1a4cf4b03" +checksum = "000a712668d60791d2afb65dfa32fa6a6016428d55e84303add68cd0fa3f27bc" dependencies = [ "Inflector", "base64 0.21.7", @@ -5017,9 +5017,9 @@ dependencies = [ [[package]] name = "solana-accounts-db" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6008537ca7281b564406832512ccc54eb709a71686ba1f47240f585ca1cd26e" +checksum = "095176015524ebc68ca79f677921645044e85812d3d02a1a21f36a0a25b1ebfa" dependencies = [ "arrayref", "bincode", @@ -5076,9 +5076,9 @@ dependencies = [ [[package]] name = "solana-address-lookup-table-program" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57b47fd167574c2b8c9e8d4083d273b21a93563199ecf06538e18d69b180deaa" +checksum = "e23bfeb01d426539fad6cc73335bbee9e2b246855e202e8ffd6e3fe132cb9be0" dependencies = [ "bincode", "bytemuck", @@ -5097,9 +5097,9 @@ dependencies = [ [[package]] name = "solana-banks-client" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9c1363cc52897701c7941314e2dc324dfdb3a8f116a96fa27a3bc0161486f" +checksum = "167e1472163f6180593e9a9275d6a31170f9f46cf5126476799f5a06c8d9c5fe" dependencies = [ "borsh 0.10.3", "futures", @@ -5114,9 +5114,9 @@ dependencies = [ [[package]] name = "solana-banks-interface" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e80947f83db9141ee3926aaa9e15dc2979a6fdfc69b46fe55cb15a8e4f45230" +checksum = "a708379e78ddd115b538308e1c25e91663978fce6ffd14f65370ce0c5cf12235" dependencies = [ "serde", "solana-sdk", @@ -5125,9 +5125,9 @@ dependencies = [ [[package]] name = "solana-banks-server" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "056fa81be1fd095471736aca928ea883caaefb02c667371c6c16319965cb3c2f" +checksum = "bc563229d69feddc49cc71880a2d81057e9de231bee60967b53064953042d255" dependencies = [ "bincode", "crossbeam-channel", @@ -5145,9 +5145,9 @@ dependencies = [ [[package]] name = "solana-bpf-loader-program" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9f1daa9d799b1f8cf78e3e83161962f242622b96cdb66886327eb5fd5aad61" +checksum = "c0126a69c7ba1f401af0a33095a7bd363de3d7b2c521ad6c13aca6ba00c0851c" dependencies = [ "bincode", "byteorder", @@ -5164,9 +5164,9 @@ dependencies = [ [[package]] name = "solana-bucket-map" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08ab4bd4fad305447a8528b2ce39e2ae6a1324b69a2eac109673bbdfd0b9de3" +checksum = "95a2aefae721ae726e25a1998511fb142116f16ae546fcebe82ada52110ffaa6" dependencies = [ "bv", "bytemuck", @@ -5182,9 +5182,9 @@ dependencies = [ [[package]] name = "solana-clap-utils" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72605419dff177e918f399c2c0843ea74b7fb0316821beedcf86a35a313ffeda" +checksum = "9cca59b1f979071a5b22acfddfdbc829acbc2dd468313755cbc5713e2c308741" dependencies = [ "chrono", "clap 2.34.0", @@ -5199,9 +5199,9 @@ dependencies = [ [[package]] name = "solana-cli" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42a31ecea3a674341823ae3fd09fe3b31b86ece5ced2dc7113e14cdf29b4bcf0" +checksum = "63e5ed14cbbd7534c47212e4093100ef015935ef85becc449c980a8029e71637" dependencies = [ "bincode", "bs58 0.4.0", @@ -5250,9 +5250,9 @@ dependencies = [ [[package]] name = "solana-cli-config" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f357772ec92837b02c0d30220f8f220f23bb4c31377cbc36ec48bc007a47917" +checksum = "82baf62be637fe750291ea2a2d262f439eb694ae0a514f2f884ee80e2aa4eb71" dependencies = [ "dirs-next", "lazy_static", @@ -5266,9 +5266,9 @@ dependencies = [ [[package]] name = "solana-cli-output" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98172e363fc102c8049ae2f867ba6e292f415a7d5c8e933ffc1f78c1e2e99a72" +checksum = "0a3c66492de638f33d8cc731a50b8d24da5c89724fce9db92bbb66b64c017b19" dependencies = [ "Inflector", "base64 0.21.7", @@ -5293,9 +5293,9 @@ dependencies = [ [[package]] name = "solana-client" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f72cf0b6a5ed6039eed9e5afae0b7c5e669a8798c1b639c11441fbf492782ea0" +checksum = "ba29752cc3dcc705c70fd3620e30c2dfbff57348ebdb46e3fc3f214242b7edc7" dependencies = [ "async-trait", "bincode", @@ -5326,9 +5326,9 @@ dependencies = [ [[package]] name = "solana-compute-budget-program" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d3276b8678aa0cbbf9c2d668e93e7c0b6388fe5a9d77da68686891f06157d4c" +checksum = "7f99656d2acb96efcc29e8aa8b2e084c1e9040449a40f4352d6c02333787b3ff" dependencies = [ "solana-program-runtime", "solana-sdk", @@ -5336,9 +5336,9 @@ dependencies = [ [[package]] name = "solana-config-program" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5767bbda019740220815229fa9219bfe8314ad9f221fd4b77708679780581c26" +checksum = "26221b3d87b47fc426c169471ed2722e2c03fd8f47546289fc00fbe3a9ff9ad3" dependencies = [ "bincode", "chrono", @@ -5350,9 +5350,9 @@ dependencies = [ [[package]] name = "solana-connection-cache" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce205152869fd375d8c26bc88ffa4e21ee2f4d9cd708ff0387e178b19bbc1709" +checksum = "06b4c885f24b4a354839bd0686eda350841ddc8483a81169a1872cfe75fe371f" dependencies = [ "async-trait", "bincode", @@ -5372,9 +5372,9 @@ dependencies = [ [[package]] name = "solana-cost-model" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fe61bc1ff78eed9c4b6a87b0e1cdaea5944beca27d686c2deb28d61ff40022d" +checksum = "5ac32ab26fda3defcbd9278f255b92d7ec84e98c62c6d65d329bf6e8a108fcae" dependencies = [ "lazy_static", "log", @@ -5396,9 +5396,9 @@ dependencies = [ [[package]] name = "solana-faucet" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e687b60ed60f29e9aeef0612fe68315c3d8e41e1527a548aae1aa3956c142e" +checksum = "9dca7464b78849ecab461d2d896c24c5b642f1e2f3f3024ceba85fc45a075c9a" dependencies = [ "bincode", "byteorder", @@ -5420,9 +5420,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd9fcb543a2863fd99eda14789263dfc67f79cde4abbb6d318d1c267436c6154" +checksum = "25b50d076362ec5b25050f4580025a782d5b49f80a6e38043cf322c878790315" dependencies = [ "ahash 0.8.5", "blake3", @@ -5450,9 +5450,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi-macro" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3b1c19e03e4fa240591fe3e61802b76a44d28bb595e309a670a3041db85e244" +checksum = "f67a7773015fd0e2beade69741927472e4b03fc894460ebf349f892fe9a87402" dependencies = [ "proc-macro2", "quote", @@ -5462,9 +5462,9 @@ dependencies = [ [[package]] name = "solana-loader-v4-program" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0634a0245496f717329a68af0d5664cf7813ddf7e61afd215aa99c5eb5c9c4f6" +checksum = "784ea38b9a3caaa02b1007bffc5bd3625ae19e93d07af81633fdda22c59e18ff" dependencies = [ "log", "solana-measure", @@ -5475,9 +5475,9 @@ dependencies = [ [[package]] name = "solana-logger" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e77721492babad3cd266ce3f2809c5d515d503583191ff116df1c2e736b33710" +checksum = "6bd8aa3a397ded89df46c4eb6be69adfe7445a33cc946cb043859f796758172c" dependencies = [ "env_logger", "lazy_static", @@ -5486,9 +5486,9 @@ dependencies = [ [[package]] name = "solana-measure" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0204c343635074ca71a9488a644afaa95c6c09c3430d0a97274a21ccb49a15d9" +checksum = "9d57d8ccddb1139d6bca8ef85a7f90a3177cdc294f2cadaa30feb4de92bd2610" dependencies = [ "log", "solana-sdk", @@ -5496,9 +5496,9 @@ dependencies = [ [[package]] name = "solana-metrics" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1c75e8f8bfe6479aaebbcdb65d54070381d5d8a852a270d3abc9208b4563" +checksum = "fe8dcc8789dd18a9687dea4304fbf1f68a67a1f5e8fd5107eade8397b7644a67" dependencies = [ "crossbeam-channel", "gethostname", @@ -5511,9 +5511,9 @@ dependencies = [ [[package]] name = "solana-net-utils" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fb3d97ee43499ef48dc756a6a6f4b26f26ae33d4abed9aa2277e836d51ce8ee" +checksum = "92c53bf0d6488a819c56796568703783838596bc2a2dbbf197a04b6536427d7e" dependencies = [ "bincode", "clap 3.2.23", @@ -5533,9 +5533,9 @@ dependencies = [ [[package]] name = "solana-perf" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42e6a5e7e5a8e8e40f9fd5641c6020875c245ad3d8a204c91a3b3f1a3ba104a" +checksum = "24724764df0c138d2618467259281f239bb658bf3aebf1bd58957ae4237242ac" dependencies = [ "ahash 0.8.5", "bincode", @@ -5562,9 +5562,9 @@ dependencies = [ [[package]] name = "solana-program" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0c7604cda91c5d6202fbe1191675e34134d065bc0659e0457c7ac04a79e4a11" +checksum = "d81f09286957de73aaa11af607bdc3de04d222dbd2c8776884c02b1c7ade2b5e" dependencies = [ "ark-bn254", "ark-ec", @@ -5616,9 +5616,9 @@ dependencies = [ [[package]] name = "solana-program-runtime" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a21bdfe76128836db0bf6227e6e7f4f2b87e496ce35da5c01ba95a888323a89" +checksum = "8995a3ce3f8a38225895ec345cf129ee2a9ee15b032cb5eb3780b3277be5559e" dependencies = [ "base64 0.21.7", "bincode", @@ -5644,9 +5644,9 @@ dependencies = [ [[package]] name = "solana-program-test" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14452c00783802b3a74fb6413073b434a0a27b527b717e566cb7dcae3ab79e5" +checksum = "401b817611841292a326fc4b6074d7dc46a02d64ab31fda4072969acda12ebf0" dependencies = [ "assert_matches", "async-trait", @@ -5674,9 +5674,9 @@ dependencies = [ [[package]] name = "solana-pubsub-client" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca065a3e2edfff5013ed174ba2d5f4c7a337cce4d38ded431a346c99be9951a" +checksum = "c1c7a83a919a57654e8f5716506acee0f9c0bbaa93d09d3b2651cc5e4dc89074" dependencies = [ "crossbeam-channel", "futures-util", @@ -5699,9 +5699,9 @@ dependencies = [ [[package]] name = "solana-quic-client" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bce18b1ed4819df7024e22a04c8f9acf1241b7de216338791281d64d0caebfeb" +checksum = "0f795c49cd9a85bd737ba4228fc9c02fd55f776770e60ff314c6c1e7c81548bb" dependencies = [ "async-mutex", "async-trait", @@ -5726,9 +5726,9 @@ dependencies = [ [[package]] name = "solana-rayon-threadlimit" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "489beb480ab72ad82852542424c628f0d3d277d499b1258d6dc0cc77e7c0eb25" +checksum = "63658c9d8dabd1fa1b2315f00be960d29a9ba5877f3afd8caa7d17ba338acda0" dependencies = [ "lazy_static", "num_cpus", @@ -5736,9 +5736,9 @@ dependencies = [ [[package]] name = "solana-remote-wallet" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4725d4067126576e38598763bce86f5eedf8afe79db7cfc25ece8aa5b456289d" +checksum = "bc740030027003b0fcd364e7476a13c216b4e8c5402cda885963f4507b8814d2" dependencies = [ "console", "dialoguer", @@ -5756,9 +5756,9 @@ dependencies = [ [[package]] name = "solana-rpc-client" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09aff1fc674359a6b07b52b922377e4cfce10a8079ff808454b9e13514823952" +checksum = "345a21ee0f723449a55a8507e33753b1d5d2dd7799c31c08f55d24fb0326f1ad" dependencies = [ "async-trait", "base64 0.21.7", @@ -5782,9 +5782,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-api" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f50f21cc5fe22ff5d6d119dca54449dda572a9e2571762a01bcd3ace0d94123e" +checksum = "a61173bd29ca2b26aef3511f5b8fc22724c46b3b539224f84e9bbd0dc4d943fe" dependencies = [ "base64 0.21.7", "bs58 0.4.0", @@ -5804,9 +5804,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-nonce-utils" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490f14d7b2d02075081cc6aa3bcdebbaa95c819cf3da070d0795bebcb09eee19" +checksum = "9943ea158e08d772cad536a0a5a4085f4b07e7416a2a2bf6cdccc57e27fc9f1a" dependencies = [ "clap 2.34.0", "solana-clap-utils", @@ -5817,9 +5817,9 @@ dependencies = [ [[package]] name = "solana-runtime" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cabeb6ee14d6eb7facd6ac7b06770fd308babf7a3ff2687ef90612a2a8b81" +checksum = "ca63fbabef285ce45d27a21a6b7c09069dd45789277a314a5f072d4ef1c3fc75" dependencies = [ "arrayref", "base64 0.21.7", @@ -5894,9 +5894,9 @@ dependencies = [ [[package]] name = "solana-sdk" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e4be7f1c6c16b238cf978352e896c8e21aab7dfb500f296e346018486627cc8" +checksum = "76ed26f2b83dac865e598f2c0f636b7c780fd0bf4f947ed98134dc2df396e1e8" dependencies = [ "assert_matches", "base64 0.21.7", @@ -5948,9 +5948,9 @@ dependencies = [ [[package]] name = "solana-sdk-macro" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "422b14d1918e67c18ff03f2d9435512fa679b6ece653929be4967d9196cf7fa3" +checksum = "44797b0a69e6b051e2f782a31a798b8e911fcf2d9ac4b0be98a35bf9e213c94f" dependencies = [ "bs58 0.4.0", "proc-macro2", @@ -5967,9 +5967,9 @@ checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" [[package]] name = "solana-send-transaction-service" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d718605132cad6cef1c921867f471eb3a4bdd549047f887688622807790445f8" +checksum = "8aab8f63c52874d13e50f7ef3a943a35bd1c21f3b29380742abab7f648881405" dependencies = [ "crossbeam-channel", "log", @@ -5983,9 +5983,9 @@ dependencies = [ [[package]] name = "solana-stake-program" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a55c7f8e7d82a19cf3e850b273f3dddd0a4b5775fddf7e5cbe5650d0d142aec" +checksum = "ec05d0fb7dc873e755d07e9066cfe8b69273d320f9c5ed2763daaa832666552b" dependencies = [ "bincode", "log", @@ -5998,9 +5998,9 @@ dependencies = [ [[package]] name = "solana-streamer" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d296461ef55ae177490256f743e020e83400634aa5c88946331b36abdca89e" +checksum = "75ed88a041f07009a4a929ed49b3ed5aa72b29c10c080d588fbaa2e2892597cc" dependencies = [ "async-channel", "bytes", @@ -6030,9 +6030,9 @@ dependencies = [ [[package]] name = "solana-system-program" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab20ec734339b64f0c77c60a0657cff567753069225ebd5aec1d967a7f7597ee" +checksum = "e724de3ecbae67e76ebc11136ec84a02a519e084812fb06c316fe6186e536e5f" dependencies = [ "bincode", "log", @@ -6044,9 +6044,9 @@ dependencies = [ [[package]] name = "solana-thin-client" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69dab2fbd46683f590403e02a42f8f70825b516f073d02c7ebf3b56fcdf9b7fc" +checksum = "0e3998c9045a7b9f53f35263ee2724086c00f28e98e655310c198048eef610b5" dependencies = [ "bincode", "log", @@ -6059,9 +6059,9 @@ dependencies = [ [[package]] name = "solana-tpu-client" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab3c608ffefc39b80659c469569751a2d92887d55d2e7da1cac3676f6323993" +checksum = "af4794d61c61f0ee9907e48bbe1ee7eb555899a9741aa64dbe8341f0f7466f18" dependencies = [ "async-trait", "bincode", @@ -6083,9 +6083,9 @@ dependencies = [ [[package]] name = "solana-transaction-status" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d70f8c51e706b52a9ea067305f989e0c85baabc259c388d929aa77b521a09c94" +checksum = "0610e42c5b28f658fbca0b0a101a31dc1685ba476f094aa869664fb149d16b41" dependencies = [ "Inflector", "base64 0.21.7", @@ -6108,9 +6108,9 @@ dependencies = [ [[package]] name = "solana-udp-client" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b54fb59fdc12787401898968bc90cb0abd839536a1159d33ff5c667c244fb711" +checksum = "9fbce1b6506094a14ad499b298e50faabd6a0f63244b77837fe9dd44440b4bbc" dependencies = [ "async-trait", "solana-connection-cache", @@ -6123,9 +6123,9 @@ dependencies = [ [[package]] name = "solana-version" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876718d1e3b48cb12a2a4a0726a8274c3e2205d890c11e462c05a97fb20cb15d" +checksum = "debc4e54260063f4a40a8b44d3d5d9be9710510b59fe0c81f3087eaebbb03533" dependencies = [ "log", "rustc_version", @@ -6139,9 +6139,9 @@ dependencies = [ [[package]] name = "solana-vote" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75b36690e2fe3c72fc894d03b362fec45c0c99edad28b68de12e1a5548f258b" +checksum = "9a0408495ec6ac9533deab7a58567bd3fff21261e2740682595b64d8ae46866c" dependencies = [ "crossbeam-channel", "itertools 0.10.5", @@ -6158,9 +6158,9 @@ dependencies = [ [[package]] name = "solana-vote-program" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82c7dfb9a13f0399eaedfe07d3b61515c39837514206722c98f0319cfc65ffab" +checksum = "babbc36d468faca2e1a8358d9231bdb6b9ed7ef61da4a90a8a4a59a1394abbd5" dependencies = [ "bincode", "log", @@ -6180,9 +6180,9 @@ dependencies = [ [[package]] name = "solana-zk-token-proof-program" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e1984585d8abcec686c4a8ecba58c90ec70922c291ce3d75da5bf5248c79ed8" +checksum = "06a26d562efcf47e288260410013183905fc752296a873897c5ce135d7d0554b" dependencies = [ "bytemuck", "num-derive 0.3.3", @@ -6194,9 +6194,9 @@ dependencies = [ [[package]] name = "solana-zk-token-sdk" -version = "1.17.26" +version = "1.17.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d9376861d6061f6e79c935706a4241e2195a066c8cf9a33ae61de0eb0670e9" +checksum = "8fa5ab24546ef1876e6db09c6e9d22054d58b9cda11553405d399b36683d3241" dependencies = [ "aes-gcm-siv", "base64 0.21.7", diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index b629812c3..65d3b9d16 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -8,8 +8,8 @@ edition = "2021" [dependencies] clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } -solana-sdk = "=1.17.26" -solana-client = "=1.17.26" +solana-sdk = "=1.17.27" +solana-client = "=1.17.27" serde = "1.0.186" serde_json = { version = "1.0.114", features = ["preserve_order"] } ethnum = { version = "1.5", default-features = false, features = ["serde"] } diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index 15081be81..a893f92bc 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -8,10 +8,10 @@ edition = "2021" [dependencies] clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } -solana-sdk = "=1.17.26" -solana-client = "=1.17.26" -solana-clap-utils = "=1.17.26" -solana-cli-config = "=1.17.26" +solana-sdk = "=1.17.27" +solana-client = "=1.17.27" +solana-clap-utils = "=1.17.27" +solana-cli-config = "=1.17.27" hex = "0.4.2" serde = "1.0.186" serde_json = { version = "1.0.114", features = ["preserve_order"] } diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index cc722f6bd..01ec9acee 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -10,13 +10,13 @@ thiserror = "1.0" anyhow = "1.0" bincode = "1.3.1" evm-loader = { path = "../program", default-features = false, features = ["log", "async-trait"] } -solana-sdk = "=1.17.26" -solana-client = "=1.17.26" -solana-clap-utils = "=1.17.26" -solana-cli-config = "=1.17.26" -solana-cli = "=1.17.26" -solana-transaction-status = "=1.17.26" -solana-program-test = "=1.17.26" +solana-sdk = "=1.17.27" +solana-client = "=1.17.27" +solana-clap-utils = "=1.17.27" +solana-cli-config = "=1.17.27" +solana-cli = "=1.17.27" +solana-transaction-status = "=1.17.27" +solana-program-test = "=1.17.27" spl-token = { version = "~4.0", default-features = false, features = ["no-entrypoint"] } spl-associated-token-account = { version = "~2.3", default-features = false, features = ["no-entrypoint"] } bs58 = "0.5.0" diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 1a802fc06..f79e35d8e 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -37,7 +37,7 @@ default = ["custom-heap"] [dependencies] linked_list_allocator = { version = "0.10", default-features = false } evm-loader-macro = { path = "../program-macro" } -solana-program = { version = "=1.17.26", default-features = false } +solana-program = { version = "=1.17.27", default-features = false } spl-token = { version = "~4.0", default-features = false, features = ["no-entrypoint"] } spl-associated-token-account = { version = "~2.3", default-features = false, features = ["no-entrypoint"] } mpl-token-metadata = { version = "~4.1", default-features = false } From 5818cc4866e8b9e5a7c648c414c5cd121199c2ef Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Thu, 21 Mar 2024 13:33:47 +0300 Subject: [PATCH 147/318] NDEV-2750 Print information about completed EVM steps (#355) --- evm_loader/lib/src/commands/get_holder.rs | 3 +++ evm_loader/program/src/account/state.rs | 22 +++++++++++++++++++ .../src/instruction/transaction_execute.rs | 12 +++++++--- .../src/instruction/transaction_step.rs | 9 ++++++++ 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/evm_loader/lib/src/commands/get_holder.rs b/evm_loader/lib/src/commands/get_holder.rs index fd7ae2d28..4fe77e84e 100644 --- a/evm_loader/lib/src/commands/get_holder.rs +++ b/evm_loader/lib/src/commands/get_holder.rs @@ -46,6 +46,8 @@ pub struct GetHolderResponse { #[serde_as(as = "Option>")] pub accounts: Option>, + + pub steps_executed: u64, } impl GetHolderResponse { @@ -119,6 +121,7 @@ pub fn read_holder(program_id: &Pubkey, info: AccountInfo) -> NeonResult Err(ProgramError::InvalidAccountData.into()), diff --git a/evm_loader/program/src/account/state.rs b/evm_loader/program/src/account/state.rs index 0c6184f84..b27a904ff 100644 --- a/evm_loader/program/src/account/state.rs +++ b/evm_loader/program/src/account/state.rs @@ -33,6 +33,8 @@ struct Data { /// Ethereum transaction gas used and paid #[serde(with = "ethnum::serde::bytes::le")] pub gas_used: U256, + /// Steps executed in the transaction + pub steps_executed: u64, } #[repr(C, packed)] @@ -112,6 +114,7 @@ impl<'a> StateAccount<'a> { origin, revisions, gas_used: U256::ZERO, + steps_executed: 0_u64, }; super::set_tag(program_id, &info, TAG_STATE, Header::VERSION)?; @@ -289,4 +292,23 @@ impl<'a> StateAccount<'a> { let unused_gas = self.gas_available(); self.consume_gas(unused_gas, origin) } + + #[must_use] + pub fn steps_executed(&self) -> u64 { + self.data.steps_executed + } + + pub fn reset_steps_executed(&mut self) { + self.data.steps_executed = 0; + } + + pub fn increment_steps_executed(&mut self, steps: u64) -> Result<()> { + self.data.steps_executed = self + .data + .steps_executed + .checked_add(steps) + .ok_or(Error::IntegerOverflow)?; + + Ok(()) + } } diff --git a/evm_loader/program/src/instruction/transaction_execute.rs b/evm_loader/program/src/instruction/transaction_execute.rs index 85dbed504..cf790ae97 100644 --- a/evm_loader/program/src/instruction/transaction_execute.rs +++ b/evm_loader/program/src/instruction/transaction_execute.rs @@ -25,17 +25,23 @@ pub fn execute( account_storage.origin(origin, &trx)?.increment_nonce()?; - let (exit_reason, apply_state) = { + let (exit_reason, apply_state, steps_executed) = { let mut backend = ExecutorState::new(&account_storage); let mut evm = Machine::new(&trx, origin, &mut backend, None::)?; - let (result, _, _) = evm.execute(u64::MAX, &mut backend)?; + let (result, steps_executed, _) = evm.execute(u64::MAX, &mut backend)?; let actions = backend.into_actions(); - (result, actions) + (result, actions, steps_executed) }; + log_data(&[ + b"STEPS", + &steps_executed.to_le_bytes(), // Iteration steps + &steps_executed.to_le_bytes(), // Total steps is the same as iteration steps + ]); + let allocate_result = account_storage.allocate(&apply_state)?; if allocate_result != AllocateResult::Ready { return Err(Error::AccountSpaceAllocationFailure); diff --git a/evm_loader/program/src/instruction/transaction_step.rs b/evm_loader/program/src/instruction/transaction_step.rs index aa377f6db..ca56888bb 100644 --- a/evm_loader/program/src/instruction/transaction_step.rs +++ b/evm_loader/program/src/instruction/transaction_step.rs @@ -62,6 +62,8 @@ pub fn do_continue<'a>( let account_storage = ProgramAccountStorage::new(accounts)?; let (mut backend, mut evm) = if reset { + storage.reset_steps_executed(); + let mut backend = ExecutorState::new(&account_storage); let evm = Machine::new(storage.trx(), storage.trx_origin(), &mut backend, None)?; (backend, evm) @@ -98,6 +100,13 @@ fn finalize<'a>( ) -> Result<()> { debug_print!("finalize"); + storage.increment_steps_executed(steps_executed)?; + log_data(&[ + b"STEPS", + &steps_executed.to_le_bytes(), + &storage.steps_executed().to_le_bytes(), + ]); + if steps_executed > 0 { accounts.transfer_treasury_payment()?; } From 8a4ced8352d68076281d3917dd53b877da57b872 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Thu, 21 Mar 2024 15:32:35 +0300 Subject: [PATCH 148/318] NDEV-1853 Add opcodes TLOAD and TSTORE (#357) --- evm_loader/lib/src/account_storage.rs | 8 + .../program/src/account_storage/apply.rs | 3 + evm_loader/program/src/evm/database.rs | 229 +----------------- evm_loader/program/src/evm/opcode.rs | 28 +++ evm_loader/program/src/evm/opcode_table.rs | 3 + evm_loader/program/src/executor/action.rs | 8 + evm_loader/program/src/executor/state.rs | 33 +++ 7 files changed, 91 insertions(+), 221 deletions(-) diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index 432361b38..2d2997fee 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -279,6 +279,14 @@ impl EmulatorAccountStorage<'_, T> { self.gas = self.gas.saturating_add(gas); } } + Action::EvmSetTransientStorage { + address, + index, + value, + } => { + let value = hex::encode(value); + info!("set transient storage {address} -> {index} = {value}"); + } Action::EvmIncrementNonce { address, chain_id } => { info!("nonce increment {address}"); diff --git a/evm_loader/program/src/account_storage/apply.rs b/evm_loader/program/src/account_storage/apply.rs index 74c26698c..2ed31111e 100644 --- a/evm_loader/program/src/account_storage/apply.rs +++ b/evm_loader/program/src/account_storage/apply.rs @@ -99,6 +99,9 @@ impl<'a> ProgramAccountStorage<'a> { .or_insert_with(|| HashMap::with_capacity(64)) .insert(index, value); } + Action::EvmSetTransientStorage { .. } => { + // do nothing, transient storage is discarded at the end of the transaction + } Action::EvmIncrementNonce { address, chain_id } => { let mut account = self.create_balance_account(address, chain_id)?; account.increment_nonce()?; diff --git a/evm_loader/program/src/evm/database.rs b/evm_loader/program/src/evm/database.rs index 827bee83f..d22eb11b8 100644 --- a/evm_loader/program/src/evm/database.rs +++ b/evm_loader/program/src/evm/database.rs @@ -29,6 +29,14 @@ pub trait Database { async fn storage(&self, address: Address, index: U256) -> Result<[u8; 32]>; fn set_storage(&mut self, address: Address, index: U256, value: [u8; 32]) -> Result<()>; + async fn transient_storage(&self, address: Address, index: U256) -> Result<[u8; 32]>; + fn set_transient_storage( + &mut self, + address: Address, + index: U256, + value: [u8; 32], + ) -> Result<()>; + async fn block_hash(&self, number: U256) -> Result<[u8; 32]>; fn block_number(&self) -> Result; fn block_timestamp(&self) -> Result; @@ -92,224 +100,3 @@ impl DatabaseExt for T { })) } } - -#[cfg(test)] -mod tests { - use std::collections::HashMap; - - use super::*; - - struct TestDatabaseEntry { - balance: U256, - nonce: u64, - code: Vec, - } - - impl TestDatabaseEntry { - fn empty() -> Self { - Self { - balance: U256::from(0u8), - nonce: 0, - code: Vec::default(), - } - } - - fn without_code() -> Self { - Self { - balance: U256::from(1u8), - nonce: 1, - code: Vec::default(), - } - } - - fn with_code(code: Vec) -> Self { - assert!(!code.is_empty()); - Self { - balance: U256::from_words(0, 1), - nonce: 1, - code, - } - } - } - - #[derive(Default)] - struct TestDatabase(HashMap); - - impl FromIterator<(Address, TestDatabaseEntry)> for TestDatabase { - fn from_iter>(iter: T) -> Self { - Self(iter.into_iter().collect()) - } - } - - #[maybe_async(?Send)] - #[allow(unused_variables)] - impl Database for TestDatabase { - fn default_chain_id(&self) -> u64 { - unimplemented!(); - } - - fn is_valid_chain_id(&self, chain_id: u64) -> bool { - unimplemented!(); - } - - async fn contract_chain_id(&self, address: Address) -> Result { - unimplemented!(); - } - - async fn nonce(&self, address: Address, chain_id: u64) -> Result { - Ok(self - .0 - .get(&address) - .map(|entry| entry.nonce) - .unwrap_or_default()) - } - - fn increment_nonce(&mut self, address: Address, chain_id: u64) -> Result<()> { - unimplemented!(); - } - - async fn balance(&self, address: Address, chain_id: u64) -> Result { - Ok(self - .0 - .get(&address) - .map(|entry| entry.balance) - .unwrap_or_default()) - } - - async fn transfer( - &mut self, - source: Address, - target: Address, - chain_id: u64, - value: U256, - ) -> Result<()> { - unimplemented!(); - } - - async fn code_size(&self, address: Address) -> Result { - unimplemented!(); - } - - async fn code(&self, address: Address) -> Result { - Ok(self - .0 - .get(&address) - .map(|entry| Buffer::from_slice(&entry.code)) - .unwrap_or_default()) - } - - fn set_code(&mut self, address: Address, chain_id: u64, code: Vec) -> Result<()> { - unimplemented!(); - } - - fn selfdestruct(&mut self, address: Address) -> Result<()> { - unimplemented!(); - } - - async fn storage(&self, address: Address, index: U256) -> Result<[u8; 32]> { - unimplemented!(); - } - - fn set_storage(&mut self, address: Address, index: U256, value: [u8; 32]) -> Result<()> { - unimplemented!(); - } - - async fn block_hash(&self, number: U256) -> Result<[u8; 32]> { - unimplemented!(); - } - - fn block_number(&self) -> Result { - unimplemented!(); - } - - fn block_timestamp(&self) -> Result { - unimplemented!(); - } - - fn rent(&self) -> &Rent { - unimplemented!(); - } - - fn return_data(&self) -> Option<(Pubkey, Vec)> { - unimplemented!(); - } - - async fn map_solana_account(&self, address: &Pubkey, action: F) -> R - where - F: FnOnce(&AccountInfo) -> R, - { - unimplemented!(); - } - - fn snapshot(&mut self) { - unimplemented!(); - } - - fn revert_snapshot(&mut self) { - unimplemented!(); - } - - fn commit_snapshot(&mut self) { - unimplemented!(); - } - - async fn precompile_extension( - &mut self, - context: &Context, - address: &Address, - data: &[u8], - is_static: bool, - ) -> Option>> { - unimplemented!(); - } - } - - #[maybe_async] - async fn code_hash(database_entry: Option) -> [u8; 32] { - let address = Address::default(); - let database: TestDatabase = database_entry - .map(|entry| (address, entry)) - .into_iter() - .collect(); - database - .code_hash(address, crate::config::DEFAULT_CHAIN_ID) - .await - .unwrap() - } - - #[tokio::test] - async fn code_hash_of_non_existing_account() { - let actual = code_hash(None).await; - assert_eq!(actual, [0; 32]); - } - - #[tokio::test] - async fn code_hash_of_empty_account() { - let actual = code_hash(Some(TestDatabaseEntry::empty())).await; - assert_eq!(actual, [0; 32]); - } - - #[tokio::test] - async fn code_hash_of_existing_account_without_code() { - let actual = code_hash(Some(TestDatabaseEntry::without_code())).await; - assert_eq!( - actual, - [ - 197, 210, 70, 1, 134, 247, 35, 60, 146, 126, 125, 178, 220, 199, 3, 192, 229, 0, - 182, 83, 202, 130, 39, 59, 123, 250, 216, 4, 93, 133, 164, 112, - ] - ); - } - - #[tokio::test] - async fn code_hash_of_existing_account_with_code() { - let actual = code_hash(Some(TestDatabaseEntry::with_code(vec![0; 10]))).await; - assert_eq!( - actual, - [ - 107, 210, 221, 107, 212, 8, 203, 238, 51, 66, 147, 88, 191, 36, 253, 198, 70, 18, - 251, 248, 177, 180, 219, 96, 69, 24, 244, 15, 253, 52, 182, 7 - ] - ); - } -} diff --git a/evm_loader/program/src/evm/opcode.rs b/evm_loader/program/src/evm/opcode.rs index 892c5800a..fa0768360 100644 --- a/evm_loader/program/src/evm/opcode.rs +++ b/evm_loader/program/src/evm/opcode.rs @@ -823,6 +823,34 @@ impl Machine { Ok(Action::Continue) } + /// reads a (u)int256 from transient storage + #[maybe_async] + pub async fn opcode_tload(&mut self, backend: &mut B) -> Result { + let index = self.stack.pop_u256()?; + let value = backend + .transient_storage(self.context.contract, index) + .await?; + + self.stack.push_array(&value)?; + + Ok(Action::Continue) + } + + /// writes a (u)int256 to transient storage + #[maybe_async] + pub async fn opcode_tstore(&mut self, backend: &mut B) -> Result { + if self.is_static { + return Err(Error::StaticModeViolation(self.context.contract)); + } + + let index = self.stack.pop_u256()?; + let value = *self.stack.pop_array()?; + + backend.set_transient_storage(self.context.contract, index, value)?; + + Ok(Action::Continue) + } + /// unconditional jump #[maybe_async] pub async fn opcode_jump(&mut self, _backend: &mut B) -> Result { diff --git a/evm_loader/program/src/evm/opcode_table.rs b/evm_loader/program/src/evm/opcode_table.rs index 5f1730951..95e75f08a 100644 --- a/evm_loader/program/src/evm/opcode_table.rs +++ b/evm_loader/program/src/evm/opcode_table.rs @@ -140,6 +140,9 @@ opcode_table![ 0x5A, GAS, Self::opcode_gas; 0x5B, JUMPDEST, Self::opcode_jumpdest; + 0x5C, TLOAD, Self::opcode_tload; + 0x5D, TSTORE, Self::opcode_tstore; + 0x5F, PUSH0, Self::opcode_push_0; 0x60, PUSH1, Self::opcode_push_1; 0x61, PUSH2, Self::opcode_push_2_31::<2>; diff --git a/evm_loader/program/src/executor/action.rs b/evm_loader/program/src/executor/action.rs index d98eaf922..33fcee932 100644 --- a/evm_loader/program/src/executor/action.rs +++ b/evm_loader/program/src/executor/action.rs @@ -34,6 +34,13 @@ pub enum Action { #[serde(with = "bytes_32")] value: [u8; 32], }, + EvmSetTransientStorage { + address: Address, + #[serde(with = "ethnum::serde::bytes::le")] + index: U256, + #[serde(with = "bytes_32")] + value: [u8; 32], + }, EvmIncrementNonce { address: Address, chain_id: u64, @@ -70,6 +77,7 @@ pub fn filter_selfdestruct(actions: Vec) -> Vec { | Action::Burn { .. } => true, // We remove EvmSetStorage|EvmIncrementNonce|EvmSetCode if account is scheduled for destroy Action::EvmSetStorage { address, .. } + | Action::EvmSetTransientStorage { address, .. } | Action::EvmSetCode { address, .. } | Action::EvmIncrementNonce { address, .. } => { !accounts_to_destroy.contains(address) diff --git a/evm_loader/program/src/executor/state.rs b/evm_loader/program/src/executor/state.rs index 2f0601445..4e6eb37f6 100644 --- a/evm_loader/program/src/executor/state.rs +++ b/evm_loader/program/src/executor/state.rs @@ -362,6 +362,39 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { Ok(()) } + async fn transient_storage(&self, from_address: Address, from_index: U256) -> Result<[u8; 32]> { + for action in self.actions.iter().rev() { + if let Action::EvmSetTransientStorage { + address, + index, + value, + } = action + { + if (&from_address == address) && (&from_index == index) { + return Ok(*value); + } + } + } + + Ok(<[u8; 32]>::default()) + } + + fn set_transient_storage( + &mut self, + address: Address, + index: U256, + value: [u8; 32], + ) -> Result<()> { + let set_storage = Action::EvmSetTransientStorage { + address, + index, + value, + }; + self.actions.push(set_storage); + + Ok(()) + } + async fn block_hash(&self, number: U256) -> Result<[u8; 32]> { // geth: // - checks the overflow From 018ba6cf3ed675e93d534e09e0263c9cfa2aa5f2 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Thu, 21 Mar 2024 16:11:08 +0300 Subject: [PATCH 149/318] NDEV-2761 Add opcode MCOPY (#356) --- evm_loader/program/src/evm/memory.rs | 26 +++++++++++++++++++++- evm_loader/program/src/evm/opcode.rs | 12 ++++++++++ evm_loader/program/src/evm/opcode_table.rs | 1 + 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/evm_loader/program/src/evm/memory.rs b/evm_loader/program/src/evm/memory.rs index bff80dd62..0e95034e1 100644 --- a/evm_loader/program/src/evm/memory.rs +++ b/evm_loader/program/src/evm/memory.rs @@ -1,7 +1,7 @@ use std::alloc::{GlobalAlloc, Layout}; use std::ops::Range; -use solana_program::program_memory::{sol_memcpy, sol_memset}; +use solana_program::program_memory::{sol_memcpy, sol_memmove, sol_memset}; use crate::error::Error; @@ -210,6 +210,30 @@ impl Memory { let slice = self.read(offset, length)?; Ok(Buffer::from_slice(slice)) } + + pub fn copy_within( + &mut self, + source: usize, + destination: usize, + length: usize, + ) -> Result<(), Error> { + if length == 0_usize { + return Ok(()); + } + + // If length > 0 and (src + length or dst + length) is beyond the current memory length, the memory is extended + self.realloc(std::cmp::max(source, destination), length)?; + + // SAFETY: self.realloc ensures that the memory is large enough to perform the memmove without out of bounds access + unsafe { + let src_ptr: *mut u8 = self.data.add(source); + let dest_ptr: *mut u8 = self.data.add(destination); + + sol_memmove(dest_ptr, src_ptr, length); + } + + Ok(()) + } } impl Drop for Memory { diff --git a/evm_loader/program/src/evm/opcode.rs b/evm_loader/program/src/evm/opcode.rs index fa0768360..e238a807e 100644 --- a/evm_loader/program/src/evm/opcode.rs +++ b/evm_loader/program/src/evm/opcode.rs @@ -797,6 +797,18 @@ impl Machine { Ok(Action::Continue) } + /// copying memory areas + #[maybe_async] + pub async fn opcode_mcopy(&mut self, _backend: &mut B) -> Result { + let target = self.stack.pop_usize()?; + let source = self.stack.pop_usize()?; + let length = self.stack.pop_usize()?; + + self.memory.copy_within(source, target, length)?; + + Ok(Action::Continue) + } + /// reads a (u)int256 from storage #[maybe_async] pub async fn opcode_sload(&mut self, backend: &mut B) -> Result { diff --git a/evm_loader/program/src/evm/opcode_table.rs b/evm_loader/program/src/evm/opcode_table.rs index 95e75f08a..6b3bbf4fe 100644 --- a/evm_loader/program/src/evm/opcode_table.rs +++ b/evm_loader/program/src/evm/opcode_table.rs @@ -142,6 +142,7 @@ opcode_table![ 0x5C, TLOAD, Self::opcode_tload; 0x5D, TSTORE, Self::opcode_tstore; + 0x5E, MCOPY, Self::opcode_mcopy; 0x5F, PUSH0, Self::opcode_push_0; 0x60, PUSH1, Self::opcode_push_1; From 1808f718025a4b87aa56a3451b8d86901ad9512b Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Thu, 21 Mar 2024 16:34:21 +0300 Subject: [PATCH 150/318] Fix CALLCODE context (#359) --- evm_loader/program/src/evm/opcode.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/evm_loader/program/src/evm/opcode.rs b/evm_loader/program/src/evm/opcode.rs index e238a807e..71707af9a 100644 --- a/evm_loader/program/src/evm/opcode.rs +++ b/evm_loader/program/src/evm/opcode.rs @@ -1211,6 +1211,7 @@ impl Machine { let context = Context { value, code_address: Some(address), + caller: self.context.contract, ..self.context }; From 9561a1f57b0c7968e915b7bfe2799e400cef9901 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 22 Mar 2024 10:17:34 +0100 Subject: [PATCH 151/318] Bump syn from 2.0.52 to 2.0.53 in /evm_loader (#358) Bumps [syn](https://github.com/dtolnay/syn) from 2.0.52 to 2.0.53. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.52...2.0.53) --- updated-dependencies: - dependency-name: syn dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 84 +++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 3bc83303f..5575fbc7b 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -123,7 +123,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -247,7 +247,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -628,7 +628,7 @@ checksum = "461abc97219de0eaaf81fe3ef974a540158f3d079c2ab200f891f1a2ef201e85" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -982,7 +982,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.52", + "syn 2.0.53", "xz2", ] @@ -1025,7 +1025,7 @@ checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -1561,7 +1561,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -1578,7 +1578,7 @@ checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -1602,7 +1602,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -1613,7 +1613,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -1785,7 +1785,7 @@ checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -1879,7 +1879,7 @@ checksum = "eecf8589574ce9b895052fa12d69af7a233f99e6107f5cb8dd1044f2a17bfdcb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -1892,7 +1892,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -1904,7 +1904,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -2042,7 +2042,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.52", + "syn 2.0.53", "toml 0.8.2", ] @@ -2217,7 +2217,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -3165,7 +3165,7 @@ checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -3557,7 +3557,7 @@ checksum = "cfb77679af88f8b125209d354a202862602672222e7f2313fdd6dc349bad4712" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -3639,7 +3639,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -3651,7 +3651,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -3713,7 +3713,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -3902,7 +3902,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -4062,7 +4062,7 @@ checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -4712,7 +4712,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -4796,7 +4796,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -4808,7 +4808,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -5457,7 +5457,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -5956,7 +5956,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -6291,7 +6291,7 @@ checksum = "fadbefec4f3c678215ca72bd71862697bb06b41fd77c0088902dd3203354387b" dependencies = [ "quote", "spl-discriminator-syn", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -6303,7 +6303,7 @@ dependencies = [ "proc-macro2", "quote", "sha2 0.10.8", - "syn 2.0.52", + "syn 2.0.53", "thiserror", ] @@ -6351,7 +6351,7 @@ dependencies = [ "proc-macro2", "quote", "sha2 0.10.8", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -6519,7 +6519,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -6547,9 +6547,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.52" +version = "2.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" dependencies = [ "proc-macro2", "quote", @@ -6659,7 +6659,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -6670,7 +6670,7 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", "test-case-core", ] @@ -6706,7 +6706,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -6823,7 +6823,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -7032,7 +7032,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -7342,7 +7342,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", "wasm-bindgen-shared", ] @@ -7376,7 +7376,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -7818,7 +7818,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] @@ -7838,7 +7838,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.53", ] [[package]] From e9ee01c3f83fec22cb7fbbf19e3d2f625ff7a1d0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 22 Mar 2024 11:28:38 +0100 Subject: [PATCH 152/318] Bump bs58 from 0.5.0 to 0.5.1 in /evm_loader (#361) Bumps [bs58](https://github.com/Nullus157/bs58-rs) from 0.5.0 to 0.5.1. - [Changelog](https://github.com/Nullus157/bs58-rs/blob/main/CHANGELOG.md) - [Commits](https://github.com/Nullus157/bs58-rs/compare/0.5.0...0.5.1) --- updated-dependencies: - dependency-name: bs58 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 8 ++++---- evm_loader/lib/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 5575fbc7b..22b5476f6 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -905,9 +905,9 @@ checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" [[package]] name = "bs58" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" dependencies = [ "tinyvec", ] @@ -2037,7 +2037,7 @@ dependencies = [ name = "evm-loader-macro" version = "1.0.0" dependencies = [ - "bs58 0.5.0", + "bs58 0.5.1", "itertools 0.12.1", "proc-macro2", "quote", @@ -3364,7 +3364,7 @@ dependencies = [ "async-trait", "base64 0.22.0", "bincode", - "bs58 0.5.0", + "bs58 0.5.1", "build-info", "build-info-build", "clap 2.34.0", diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 01ec9acee..44b281ee5 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -19,7 +19,7 @@ solana-transaction-status = "=1.17.27" solana-program-test = "=1.17.27" spl-token = { version = "~4.0", default-features = false, features = ["no-entrypoint"] } spl-associated-token-account = { version = "~2.3", default-features = false, features = ["no-entrypoint"] } -bs58 = "0.5.0" +bs58 = "0.5.1" base64 = "0.22" hex = { version = "0.4", features = ["serde"] } serde = "1.0" From e439ff307d745b78b6e506eba340e4888d765de6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 25 Mar 2024 08:39:13 +0200 Subject: [PATCH 153/318] Bump jsonrpsee-types from 0.22.2 to 0.22.3 in /evm_loader (#362) Bumps [jsonrpsee-types](https://github.com/paritytech/jsonrpsee) from 0.22.2 to 0.22.3. - [Release notes](https://github.com/paritytech/jsonrpsee/releases) - [Changelog](https://github.com/paritytech/jsonrpsee/blob/v0.22.3/CHANGELOG.md) - [Commits](https://github.com/paritytech/jsonrpsee/compare/v0.22.2...v0.22.3) --- updated-dependencies: - dependency-name: jsonrpsee-types dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 6 +++--- evm_loader/rpc-client/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 22b5476f6..371d7c857 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -2922,9 +2922,9 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.22.2" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467fd35feeee179f71ab294516bdf3a81139e7aeebdd860e46897c12e1a3368" +checksum = "1e53c72de6cd2ad6ac1aa6e848206ef8b736f92ed02354959130373dfa5b3cbd" dependencies = [ "anyhow", "beef", @@ -3440,7 +3440,7 @@ dependencies = [ "jsonrpc-v2", "jsonrpsee-core", "jsonrpsee-http-client", - "jsonrpsee-types 0.22.2", + "jsonrpsee-types 0.22.3", "neon-lib", "serde", "serde_json", diff --git a/evm_loader/rpc-client/Cargo.toml b/evm_loader/rpc-client/Cargo.toml index 898390ebb..281981bd5 100644 --- a/evm_loader/rpc-client/Cargo.toml +++ b/evm_loader/rpc-client/Cargo.toml @@ -14,6 +14,6 @@ thiserror = "1.0.58" async-trait = "0.1.78" jsonrpsee-core = "0.20.2" jsonrpsee-http-client = "0.20.2" -jsonrpsee-types = "0.22.2" +jsonrpsee-types = "0.22.3" tokio = { version = "1", features = ["full"] } build-info = { version = "0.0.31", features = ["serde"] } From 89ff4cc7a75a8e80a35e729654d475bc6797af01 Mon Sep 17 00:00:00 2001 From: Stanislav Tkach Date: Tue, 26 Mar 2024 11:27:50 +0100 Subject: [PATCH 154/318] NDEV-2807: Update Solana to 1.17.28 (#364) --- .github/workflows/deploy.py | 4 +- evm_loader/Cargo.lock | 208 +++++++++++++++++----------------- evm_loader/Cargo.toml | 10 ++ evm_loader/api/Cargo.toml | 4 +- evm_loader/cli/Cargo.toml | 8 +- evm_loader/lib/Cargo.toml | 14 +-- evm_loader/program/Cargo.toml | 2 +- 7 files changed, 130 insertions(+), 120 deletions(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index fc86833e1..25ec2b212 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -32,8 +32,8 @@ IMAGE_NAME = os.environ.get("IMAGE_NAME") RUN_LINK_REPO = os.environ.get("RUN_LINK_REPO") DOCKERHUB_ORG_NAME = os.environ.get("DOCKERHUB_ORG_NAME") -SOLANA_NODE_VERSION = 'v1.17.27' -SOLANA_BPF_VERSION = 'v1.17.27' +SOLANA_NODE_VERSION = 'v1.17.28' +SOLANA_BPF_VERSION = 'v1.17.28' VERSION_BRANCH_TEMPLATE = r"[vt]{1}\d{1,2}\.\d{1,2}\.x.*" docker_client = docker.APIClient() diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 371d7c857..c207a1fdd 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -4992,9 +4992,9 @@ dependencies = [ [[package]] name = "solana-account-decoder" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "000a712668d60791d2afb65dfa32fa6a6016428d55e84303add68cd0fa3f27bc" +checksum = "8d76c43ef61f527d719b5c6bfa5a62ebba60839739125da9e8a00fb82349afd2" dependencies = [ "Inflector", "base64 0.21.7", @@ -5017,9 +5017,9 @@ dependencies = [ [[package]] name = "solana-accounts-db" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "095176015524ebc68ca79f677921645044e85812d3d02a1a21f36a0a25b1ebfa" +checksum = "36d5bd37de55b19efecc842f48f465edc588b107acf0c9f94d79b1182147e299" dependencies = [ "arrayref", "bincode", @@ -5076,9 +5076,9 @@ dependencies = [ [[package]] name = "solana-address-lookup-table-program" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e23bfeb01d426539fad6cc73335bbee9e2b246855e202e8ffd6e3fe132cb9be0" +checksum = "99d143225217baaf524eac490475802eb095a563833735a4dc0f1e84d5f57e03" dependencies = [ "bincode", "bytemuck", @@ -5097,9 +5097,9 @@ dependencies = [ [[package]] name = "solana-banks-client" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167e1472163f6180593e9a9275d6a31170f9f46cf5126476799f5a06c8d9c5fe" +checksum = "0de7daee8af1a4555236d6537ce9d5c10bc945f65e6468382699ad91d020a592" dependencies = [ "borsh 0.10.3", "futures", @@ -5114,9 +5114,9 @@ dependencies = [ [[package]] name = "solana-banks-interface" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a708379e78ddd115b538308e1c25e91663978fce6ffd14f65370ce0c5cf12235" +checksum = "cab9eec320b5202c44693cdfdda3b674c92d95def8b0fe5ff2857108d5a81918" dependencies = [ "serde", "solana-sdk", @@ -5125,9 +5125,9 @@ dependencies = [ [[package]] name = "solana-banks-server" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc563229d69feddc49cc71880a2d81057e9de231bee60967b53064953042d255" +checksum = "bbaf48c1c27ae104b7aefdac5f2a024007cb24f01d1f50e3ea4a97588dc29056" dependencies = [ "bincode", "crossbeam-channel", @@ -5145,9 +5145,9 @@ dependencies = [ [[package]] name = "solana-bpf-loader-program" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0126a69c7ba1f401af0a33095a7bd363de3d7b2c521ad6c13aca6ba00c0851c" +checksum = "2ce801a3dc8a060446a0d4545e882f07635ef1ff57503917c7d3a8769dc5fed6" dependencies = [ "bincode", "byteorder", @@ -5164,9 +5164,9 @@ dependencies = [ [[package]] name = "solana-bucket-map" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a2aefae721ae726e25a1998511fb142116f16ae546fcebe82ada52110ffaa6" +checksum = "2977fbe89d8edd3f15ec06bd8d4d518017456ee2a8636972e5eb4b2b0a5e76e5" dependencies = [ "bv", "bytemuck", @@ -5182,9 +5182,9 @@ dependencies = [ [[package]] name = "solana-clap-utils" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cca59b1f979071a5b22acfddfdbc829acbc2dd468313755cbc5713e2c308741" +checksum = "eb19b9bbd92eee2d8f637026559a9fb48bd98aba534caedf070498a50c91fce8" dependencies = [ "chrono", "clap 2.34.0", @@ -5199,9 +5199,9 @@ dependencies = [ [[package]] name = "solana-cli" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63e5ed14cbbd7534c47212e4093100ef015935ef85becc449c980a8029e71637" +checksum = "72783963ea5eb41c67ba730e6dc9511a9747bb0286d476aa0e184f97a483b834" dependencies = [ "bincode", "bs58 0.4.0", @@ -5250,9 +5250,9 @@ dependencies = [ [[package]] name = "solana-cli-config" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82baf62be637fe750291ea2a2d262f439eb694ae0a514f2f884ee80e2aa4eb71" +checksum = "677c2b5da3a4788e2eb04c35f947c2f23754244177ae24db38344675c67ca825" dependencies = [ "dirs-next", "lazy_static", @@ -5266,9 +5266,9 @@ dependencies = [ [[package]] name = "solana-cli-output" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a3c66492de638f33d8cc731a50b8d24da5c89724fce9db92bbb66b64c017b19" +checksum = "ddbf06ae70f42263d7ee251f0481e150300c08678a08ae8a2c6ad02f2a80d3ae" dependencies = [ "Inflector", "base64 0.21.7", @@ -5293,9 +5293,9 @@ dependencies = [ [[package]] name = "solana-client" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba29752cc3dcc705c70fd3620e30c2dfbff57348ebdb46e3fc3f214242b7edc7" +checksum = "9538e3db584a8b1e70060f1f24222b8e0429f18b607f531fb45eb826f4917265" dependencies = [ "async-trait", "bincode", @@ -5326,9 +5326,9 @@ dependencies = [ [[package]] name = "solana-compute-budget-program" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f99656d2acb96efcc29e8aa8b2e084c1e9040449a40f4352d6c02333787b3ff" +checksum = "afbb8cfc7f4448db4c766e97b9175f96b73f947df8cf27dbbad8f1b9d40d9069" dependencies = [ "solana-program-runtime", "solana-sdk", @@ -5336,9 +5336,9 @@ dependencies = [ [[package]] name = "solana-config-program" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26221b3d87b47fc426c169471ed2722e2c03fd8f47546289fc00fbe3a9ff9ad3" +checksum = "e3afd4e309d304e296765cab716fb1fd66c66ec300465c8b26f8cce763275132" dependencies = [ "bincode", "chrono", @@ -5350,9 +5350,9 @@ dependencies = [ [[package]] name = "solana-connection-cache" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06b4c885f24b4a354839bd0686eda350841ddc8483a81169a1872cfe75fe371f" +checksum = "92716758e8c0e1c0bc2a5ac2eb3df443a0337fd3991cd38a3b02b12c3fbd18ce" dependencies = [ "async-trait", "bincode", @@ -5372,9 +5372,9 @@ dependencies = [ [[package]] name = "solana-cost-model" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ac32ab26fda3defcbd9278f255b92d7ec84e98c62c6d65d329bf6e8a108fcae" +checksum = "ab342bd6a42e6c2fa21fe1d72801fbd98858eef44b1b8c1ecdf54f82c58dd496" dependencies = [ "lazy_static", "log", @@ -5396,9 +5396,9 @@ dependencies = [ [[package]] name = "solana-faucet" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dca7464b78849ecab461d2d896c24c5b642f1e2f3f3024ceba85fc45a075c9a" +checksum = "e001d384576317028fd682943ae9321eadd25a17c50e59d71f387e67c6a22266" dependencies = [ "bincode", "byteorder", @@ -5420,9 +5420,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b50d076362ec5b25050f4580025a782d5b49f80a6e38043cf322c878790315" +checksum = "fb1b8230474ae9f7c841060c299999124582e8d2a0448d7847720792e98cc64e" dependencies = [ "ahash 0.8.5", "blake3", @@ -5450,9 +5450,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi-macro" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f67a7773015fd0e2beade69741927472e4b03fc894460ebf349f892fe9a87402" +checksum = "793910ab733b113b80c357f8f492dda2fabd5671c4ea03db3aa4e46b938fdbe3" dependencies = [ "proc-macro2", "quote", @@ -5462,9 +5462,9 @@ dependencies = [ [[package]] name = "solana-loader-v4-program" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784ea38b9a3caaa02b1007bffc5bd3625ae19e93d07af81633fdda22c59e18ff" +checksum = "99507b87522b861b164673a127c5a291c2837ecf04b7466a3b5201053c1c267a" dependencies = [ "log", "solana-measure", @@ -5475,9 +5475,9 @@ dependencies = [ [[package]] name = "solana-logger" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bd8aa3a397ded89df46c4eb6be69adfe7445a33cc946cb043859f796758172c" +checksum = "6d3f819af39632dc538a566c937253bf46256e4c0e60f621c6db448bc7c76294" dependencies = [ "env_logger", "lazy_static", @@ -5486,9 +5486,9 @@ dependencies = [ [[package]] name = "solana-measure" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d57d8ccddb1139d6bca8ef85a7f90a3177cdc294f2cadaa30feb4de92bd2610" +checksum = "cb045f0235b16f7d926f6e0338db822747d61559a1368c3cb017ba6e02c516d0" dependencies = [ "log", "solana-sdk", @@ -5496,9 +5496,9 @@ dependencies = [ [[package]] name = "solana-metrics" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe8dcc8789dd18a9687dea4304fbf1f68a67a1f5e8fd5107eade8397b7644a67" +checksum = "1af84362ad5804dc64ca88b1ca5c35bd41321e12d42c798ac06a6fbb60dd0e70" dependencies = [ "crossbeam-channel", "gethostname", @@ -5511,9 +5511,9 @@ dependencies = [ [[package]] name = "solana-net-utils" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92c53bf0d6488a819c56796568703783838596bc2a2dbbf197a04b6536427d7e" +checksum = "f8e640a95d317cad1322015c5a2b6a71697fd8dabebcb8dd33ed7f5a22869d12" dependencies = [ "bincode", "clap 3.2.23", @@ -5533,9 +5533,9 @@ dependencies = [ [[package]] name = "solana-perf" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24724764df0c138d2618467259281f239bb658bf3aebf1bd58957ae4237242ac" +checksum = "4266c4bd46620a925b8d508c26578d5559e97fcff6735fd22e39f369c3996ee1" dependencies = [ "ahash 0.8.5", "bincode", @@ -5562,9 +5562,9 @@ dependencies = [ [[package]] name = "solana-program" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d81f09286957de73aaa11af607bdc3de04d222dbd2c8776884c02b1c7ade2b5e" +checksum = "581f38a870bffbe623d900c68579984671f8dfa35bbfb3309d7134de22ce8652" dependencies = [ "ark-bn254", "ark-ec", @@ -5616,9 +5616,9 @@ dependencies = [ [[package]] name = "solana-program-runtime" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8995a3ce3f8a38225895ec345cf129ee2a9ee15b032cb5eb3780b3277be5559e" +checksum = "490b6f65aced077e0c5e57c20f151a134458fc350905c20d7dcf3f2162eaa6f6" dependencies = [ "base64 0.21.7", "bincode", @@ -5644,9 +5644,9 @@ dependencies = [ [[package]] name = "solana-program-test" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "401b817611841292a326fc4b6074d7dc46a02d64ab31fda4072969acda12ebf0" +checksum = "3756bfd3a7e55711c7042fbd63b27651f16ae9a2e780cc2c6d7128cefb0fb763" dependencies = [ "assert_matches", "async-trait", @@ -5674,9 +5674,9 @@ dependencies = [ [[package]] name = "solana-pubsub-client" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1c7a83a919a57654e8f5716506acee0f9c0bbaa93d09d3b2651cc5e4dc89074" +checksum = "c0dc2b26a7a9860f180ce11f69b0ff2a8bea0d4b9e97daee741b1e76565b3c82" dependencies = [ "crossbeam-channel", "futures-util", @@ -5699,9 +5699,9 @@ dependencies = [ [[package]] name = "solana-quic-client" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f795c49cd9a85bd737ba4228fc9c02fd55f776770e60ff314c6c1e7c81548bb" +checksum = "727474945d51be37ffe03e7b1d6c9630da41228c7b298a8f45098c203a78ac89" dependencies = [ "async-mutex", "async-trait", @@ -5726,9 +5726,9 @@ dependencies = [ [[package]] name = "solana-rayon-threadlimit" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63658c9d8dabd1fa1b2315f00be960d29a9ba5877f3afd8caa7d17ba338acda0" +checksum = "853794cccf3bd1984419a594040dfed19666e5a9ad33b0906d4174bc394b22af" dependencies = [ "lazy_static", "num_cpus", @@ -5736,9 +5736,9 @@ dependencies = [ [[package]] name = "solana-remote-wallet" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc740030027003b0fcd364e7476a13c216b4e8c5402cda885963f4507b8814d2" +checksum = "b368f270526a5f92ec47c45a6b74ac304b62b08c169b45cf91e0d2f1703889bd" dependencies = [ "console", "dialoguer", @@ -5756,9 +5756,9 @@ dependencies = [ [[package]] name = "solana-rpc-client" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345a21ee0f723449a55a8507e33753b1d5d2dd7799c31c08f55d24fb0326f1ad" +checksum = "71b766876b0c56950ab530d8495ef7eeaeb79e162f03dadaffc0d6852de9e844" dependencies = [ "async-trait", "base64 0.21.7", @@ -5782,9 +5782,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-api" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a61173bd29ca2b26aef3511f5b8fc22724c46b3b539224f84e9bbd0dc4d943fe" +checksum = "876b2e410cc2403ea3216893f05034b02a180431100eb831d0b67b14fca4d29f" dependencies = [ "base64 0.21.7", "bs58 0.4.0", @@ -5804,9 +5804,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-nonce-utils" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9943ea158e08d772cad536a0a5a4085f4b07e7416a2a2bf6cdccc57e27fc9f1a" +checksum = "ebdb3f02fb3cce3c967f718bc77b79433c24aa801b63dc70f374e8759b2424e4" dependencies = [ "clap 2.34.0", "solana-clap-utils", @@ -5817,9 +5817,9 @@ dependencies = [ [[package]] name = "solana-runtime" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca63fbabef285ce45d27a21a6b7c09069dd45789277a314a5f072d4ef1c3fc75" +checksum = "35b7851486b7b3deb2a6efee81cd1466b77beff914cb5cc93940d9f7f0430b7d" dependencies = [ "arrayref", "base64 0.21.7", @@ -5894,9 +5894,9 @@ dependencies = [ [[package]] name = "solana-sdk" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76ed26f2b83dac865e598f2c0f636b7c780fd0bf4f947ed98134dc2df396e1e8" +checksum = "0d70ab837cc79ed67df6fdb145f1ffd544f1eaa60b0757b750f4864b90498bad" dependencies = [ "assert_matches", "base64 0.21.7", @@ -5948,9 +5948,9 @@ dependencies = [ [[package]] name = "solana-sdk-macro" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44797b0a69e6b051e2f782a31a798b8e911fcf2d9ac4b0be98a35bf9e213c94f" +checksum = "5f9d0433c4084a3260a32ec67f6b4272c4232d15e732be542cd5dfdf0ae1e784" dependencies = [ "bs58 0.4.0", "proc-macro2", @@ -5967,9 +5967,9 @@ checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" [[package]] name = "solana-send-transaction-service" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8aab8f63c52874d13e50f7ef3a943a35bd1c21f3b29380742abab7f648881405" +checksum = "e01a0ac42573098147bf1d1dc8d4455fa2756757cd58435ffc75951e3d4858c1" dependencies = [ "crossbeam-channel", "log", @@ -5983,9 +5983,9 @@ dependencies = [ [[package]] name = "solana-stake-program" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec05d0fb7dc873e755d07e9066cfe8b69273d320f9c5ed2763daaa832666552b" +checksum = "c695b516f57e0291cdb18e994c22d9478e7f49be631782c352327ba5bee46a88" dependencies = [ "bincode", "log", @@ -5998,9 +5998,9 @@ dependencies = [ [[package]] name = "solana-streamer" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75ed88a041f07009a4a929ed49b3ed5aa72b29c10c080d588fbaa2e2892597cc" +checksum = "d70eda40efb5bc57ad50b1ac8452485065c1adae0e701a0348b397db054e2ab5" dependencies = [ "async-channel", "bytes", @@ -6030,9 +6030,9 @@ dependencies = [ [[package]] name = "solana-system-program" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e724de3ecbae67e76ebc11136ec84a02a519e084812fb06c316fe6186e536e5f" +checksum = "4f0b104dc8b94642988324a291c70f1c728be2276761e5523da1b4aa940b0f7a" dependencies = [ "bincode", "log", @@ -6044,9 +6044,9 @@ dependencies = [ [[package]] name = "solana-thin-client" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e3998c9045a7b9f53f35263ee2724086c00f28e98e655310c198048eef610b5" +checksum = "ca3c510144695c3d1ee1f84dd9975af7f7d35c168447c484bbd35c21e903c515" dependencies = [ "bincode", "log", @@ -6059,9 +6059,9 @@ dependencies = [ [[package]] name = "solana-tpu-client" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af4794d61c61f0ee9907e48bbe1ee7eb555899a9741aa64dbe8341f0f7466f18" +checksum = "44f27c8fec609179a7dfc287060df2a926c8cd89329235c4b8d78bd019a72462" dependencies = [ "async-trait", "bincode", @@ -6083,9 +6083,9 @@ dependencies = [ [[package]] name = "solana-transaction-status" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0610e42c5b28f658fbca0b0a101a31dc1685ba476f094aa869664fb149d16b41" +checksum = "29f58f2f864d900eddf2e21a99ebe445b6be525d597e44952f075d8237035b8e" dependencies = [ "Inflector", "base64 0.21.7", @@ -6108,9 +6108,9 @@ dependencies = [ [[package]] name = "solana-udp-client" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fbce1b6506094a14ad499b298e50faabd6a0f63244b77837fe9dd44440b4bbc" +checksum = "27ead118c5d549e4345dc59cbc5d9b282164f3e5334707f186e3aa10d40e3b30" dependencies = [ "async-trait", "solana-connection-cache", @@ -6123,9 +6123,9 @@ dependencies = [ [[package]] name = "solana-version" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "debc4e54260063f4a40a8b44d3d5d9be9710510b59fe0c81f3087eaebbb03533" +checksum = "532f5d631562587facc5fe88abd2e31c0d1f29012b6766c664db9f05a39fb05b" dependencies = [ "log", "rustc_version", @@ -6139,9 +6139,9 @@ dependencies = [ [[package]] name = "solana-vote" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a0408495ec6ac9533deab7a58567bd3fff21261e2740682595b64d8ae46866c" +checksum = "94ee806a47c6b1a3790e7d49f57a2037e631fee6b83e608e3315fdfc485c5826" dependencies = [ "crossbeam-channel", "itertools 0.10.5", @@ -6158,9 +6158,9 @@ dependencies = [ [[package]] name = "solana-vote-program" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "babbc36d468faca2e1a8358d9231bdb6b9ed7ef61da4a90a8a4a59a1394abbd5" +checksum = "c684430058b0a2e733936a8851c8843a3a6316ccd5c969d39411a479d6489642" dependencies = [ "bincode", "log", @@ -6180,9 +6180,9 @@ dependencies = [ [[package]] name = "solana-zk-token-proof-program" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06a26d562efcf47e288260410013183905fc752296a873897c5ce135d7d0554b" +checksum = "3b04ec720b6cf2d852f7aac4153e1f2b9eb4b88e7d6653a169989b2e4bcbd050" dependencies = [ "bytemuck", "num-derive 0.3.3", @@ -6194,9 +6194,9 @@ dependencies = [ [[package]] name = "solana-zk-token-sdk" -version = "1.17.27" +version = "1.17.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fa5ab24546ef1876e6db09c6e9d22054d58b9cda11553405d399b36683d3241" +checksum = "5aef1b48d9fdb2619349d2d15942d83c99aabe995ff945d9b418176373aa823c" dependencies = [ "aes-gcm-siv", "base64 0.21.7", diff --git a/evm_loader/Cargo.toml b/evm_loader/Cargo.toml index c52ac9726..8bf6737ff 100644 --- a/evm_loader/Cargo.toml +++ b/evm_loader/Cargo.toml @@ -10,3 +10,13 @@ members = [ 'program', 'program-macro', ] + +[workspace.dependencies] +solana-clap-utils = "=1.17.28" +solana-cli = "=1.17.28" +solana-cli-config = "=1.17.28" +solana-client = "=1.17.28" +solana-program = { version = "=1.17.28", default-features = false } +solana-program-test = "=1.17.28" +solana-transaction-status = "=1.17.28" +solana-sdk = "=1.17.28" diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 65d3b9d16..c5bb950e3 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -8,8 +8,8 @@ edition = "2021" [dependencies] clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } -solana-sdk = "=1.17.27" -solana-client = "=1.17.27" +solana-sdk.workspace = true +solana-client.workspace = true serde = "1.0.186" serde_json = { version = "1.0.114", features = ["preserve_order"] } ethnum = { version = "1.5", default-features = false, features = ["serde"] } diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index a893f92bc..0fc9369d6 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -8,10 +8,10 @@ edition = "2021" [dependencies] clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } -solana-sdk = "=1.17.27" -solana-client = "=1.17.27" -solana-clap-utils = "=1.17.27" -solana-cli-config = "=1.17.27" +solana-sdk.workspace = true +solana-client.workspace = true +solana-clap-utils.workspace = true +solana-cli-config.workspace = true hex = "0.4.2" serde = "1.0.186" serde_json = { version = "1.0.114", features = ["preserve_order"] } diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 44b281ee5..d9cfc287f 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -10,13 +10,13 @@ thiserror = "1.0" anyhow = "1.0" bincode = "1.3.1" evm-loader = { path = "../program", default-features = false, features = ["log", "async-trait"] } -solana-sdk = "=1.17.27" -solana-client = "=1.17.27" -solana-clap-utils = "=1.17.27" -solana-cli-config = "=1.17.27" -solana-cli = "=1.17.27" -solana-transaction-status = "=1.17.27" -solana-program-test = "=1.17.27" +solana-sdk.workspace = true +solana-client.workspace = true +solana-clap-utils.workspace = true +solana-cli-config.workspace = true +solana-cli.workspace = true +solana-transaction-status.workspace = true +solana-program-test.workspace = true spl-token = { version = "~4.0", default-features = false, features = ["no-entrypoint"] } spl-associated-token-account = { version = "~2.3", default-features = false, features = ["no-entrypoint"] } bs58 = "0.5.1" diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index f79e35d8e..3afc9d3ca 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -37,7 +37,7 @@ default = ["custom-heap"] [dependencies] linked_list_allocator = { version = "0.10", default-features = false } evm-loader-macro = { path = "../program-macro" } -solana-program = { version = "=1.17.27", default-features = false } +solana-program.workspace = true spl-token = { version = "~4.0", default-features = false, features = ["no-entrypoint"] } spl-associated-token-account = { version = "~2.3", default-features = false, features = ["no-entrypoint"] } mpl-token-metadata = { version = "~4.1", default-features = false } From bfea9211a9aee8b499f8790a21c0de4613f537ae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 27 Mar 2024 18:05:21 +0200 Subject: [PATCH 155/318] Bump syn from 2.0.53 to 2.0.55 in /evm_loader (#363) Bumps [syn](https://github.com/dtolnay/syn) from 2.0.53 to 2.0.55. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.53...2.0.55) --- updated-dependencies: - dependency-name: syn dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 84 +++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index c207a1fdd..79ad544cb 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -123,7 +123,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -247,7 +247,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -628,7 +628,7 @@ checksum = "461abc97219de0eaaf81fe3ef974a540158f3d079c2ab200f891f1a2ef201e85" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -982,7 +982,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.53", + "syn 2.0.55", "xz2", ] @@ -1025,7 +1025,7 @@ checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -1561,7 +1561,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -1578,7 +1578,7 @@ checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -1602,7 +1602,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -1613,7 +1613,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -1785,7 +1785,7 @@ checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -1879,7 +1879,7 @@ checksum = "eecf8589574ce9b895052fa12d69af7a233f99e6107f5cb8dd1044f2a17bfdcb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -1892,7 +1892,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -1904,7 +1904,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -2042,7 +2042,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.53", + "syn 2.0.55", "toml 0.8.2", ] @@ -2217,7 +2217,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -3165,7 +3165,7 @@ checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -3557,7 +3557,7 @@ checksum = "cfb77679af88f8b125209d354a202862602672222e7f2313fdd6dc349bad4712" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -3639,7 +3639,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -3651,7 +3651,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -3713,7 +3713,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -3902,7 +3902,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -4062,7 +4062,7 @@ checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -4712,7 +4712,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -4796,7 +4796,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -4808,7 +4808,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -5457,7 +5457,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -5956,7 +5956,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -6291,7 +6291,7 @@ checksum = "fadbefec4f3c678215ca72bd71862697bb06b41fd77c0088902dd3203354387b" dependencies = [ "quote", "spl-discriminator-syn", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -6303,7 +6303,7 @@ dependencies = [ "proc-macro2", "quote", "sha2 0.10.8", - "syn 2.0.53", + "syn 2.0.55", "thiserror", ] @@ -6351,7 +6351,7 @@ dependencies = [ "proc-macro2", "quote", "sha2 0.10.8", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -6519,7 +6519,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -6547,9 +6547,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.53" +version = "2.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" +checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" dependencies = [ "proc-macro2", "quote", @@ -6659,7 +6659,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -6670,7 +6670,7 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", "test-case-core", ] @@ -6706,7 +6706,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -6823,7 +6823,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -7032,7 +7032,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -7342,7 +7342,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", "wasm-bindgen-shared", ] @@ -7376,7 +7376,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -7818,7 +7818,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -7838,7 +7838,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] From 1879d93091f35b1e63dd78e15b299c88d4178232 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Mar 2024 12:57:55 +0200 Subject: [PATCH 156/318] Bump jsonrpsee-core from 0.20.3 to 0.22.3 in /evm_loader (#367) * Bump jsonrpsee-core from 0.20.3 to 0.22.3 in /evm_loader Bumps [jsonrpsee-core](https://github.com/paritytech/jsonrpsee) from 0.20.3 to 0.22.3. - [Release notes](https://github.com/paritytech/jsonrpsee/releases) - [Changelog](https://github.com/paritytech/jsonrpsee/blob/v0.22.3/CHANGELOG.md) - [Commits](https://github.com/paritytech/jsonrpsee/compare/v0.20.3...v0.22.3) --- updated-dependencies: - dependency-name: jsonrpsee-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Fix build --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrei Silviu Dragnea --- evm_loader/Cargo.lock | 28 +++++++--------------------- evm_loader/rpc-client/Cargo.toml | 4 ++-- evm_loader/rpc-client/src/error.rs | 2 +- 3 files changed, 10 insertions(+), 24 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 79ad544cb..792ac2d0c 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -2869,16 +2869,16 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.20.3" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da2327ba8df2fdbd5e897e2b5ed25ce7f299d345b9736b6828814c3dbd1fd47b" +checksum = "71962a1c49af43adf81d337e4ebc93f3c915faf6eccaa14d74e255107dfd7723" dependencies = [ "anyhow", "async-trait", "beef", "futures-util", "hyper", - "jsonrpsee-types 0.20.3", + "jsonrpsee-types", "serde", "serde_json", "thiserror", @@ -2888,15 +2888,15 @@ dependencies = [ [[package]] name = "jsonrpsee-http-client" -version = "0.20.3" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f80c17f62c7653ce767e3d7288b793dfec920f97067ceb189ebdd3570f2bc20" +checksum = "8c13987da51270bda2c1c9b40c19be0fe9b225c7a0553963d8f17e683a50ce84" dependencies = [ "async-trait", "hyper", "hyper-rustls", "jsonrpsee-core", - "jsonrpsee-types 0.20.3", + "jsonrpsee-types", "serde", "serde_json", "thiserror", @@ -2906,20 +2906,6 @@ dependencies = [ "url", ] -[[package]] -name = "jsonrpsee-types" -version = "0.20.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be0be325642e850ed0bdff426674d2e66b2b7117c9be23a7caef68a2902b7d9" -dependencies = [ - "anyhow", - "beef", - "serde", - "serde_json", - "thiserror", - "tracing", -] - [[package]] name = "jsonrpsee-types" version = "0.22.3" @@ -3440,7 +3426,7 @@ dependencies = [ "jsonrpc-v2", "jsonrpsee-core", "jsonrpsee-http-client", - "jsonrpsee-types 0.22.3", + "jsonrpsee-types", "neon-lib", "serde", "serde_json", diff --git a/evm_loader/rpc-client/Cargo.toml b/evm_loader/rpc-client/Cargo.toml index 281981bd5..414748597 100644 --- a/evm_loader/rpc-client/Cargo.toml +++ b/evm_loader/rpc-client/Cargo.toml @@ -12,8 +12,8 @@ jsonrpc-v2 = "0.13.0" neon-lib = { path = "../lib" } thiserror = "1.0.58" async-trait = "0.1.78" -jsonrpsee-core = "0.20.2" -jsonrpsee-http-client = "0.20.2" +jsonrpsee-core = "0.22.3" +jsonrpsee-http-client = "0.22.3" jsonrpsee-types = "0.22.3" tokio = { version = "1", features = ["full"] } build-info = { version = "0.0.31", features = ["serde"] } diff --git a/evm_loader/rpc-client/src/error.rs b/evm_loader/rpc-client/src/error.rs index 2f6564fe3..9fa8c2f2e 100644 --- a/evm_loader/rpc-client/src/error.rs +++ b/evm_loader/rpc-client/src/error.rs @@ -3,7 +3,7 @@ use thiserror::Error; #[derive(Debug, Error)] pub enum NeonRpcClientError { #[error("Jsonrpc error. {0:?}")] - JsonrpseeError(#[from] jsonrpsee_core::Error), + JsonrpseeError(#[from] jsonrpsee_core::client::Error), #[error("serde json error. {0:?}")] SerdeJsonError(#[from] serde_json::Error), } From 0bc54a52c15259e8a760ab50bd63aaaabd6a3ece Mon Sep 17 00:00:00 2001 From: s-medvedev <40623263+s-medvedev@users.noreply.github.com> Date: Thu, 28 Mar 2024 18:29:21 +0700 Subject: [PATCH 157/318] NDEV-2768 Replace SELFDESTRUCT opcode with SENDALL (#366) Co-authored-by: Semen Medvedev --- evm_loader/lib/src/account_storage.rs | 3 -- .../lib/src/tracing/tracers/state_diff.rs | 2 +- .../program/src/account_storage/apply.rs | 4 --- evm_loader/program/src/evm/database.rs | 1 - evm_loader/program/src/evm/opcode.rs | 5 ++- evm_loader/program/src/evm/opcode_table.rs | 2 +- evm_loader/program/src/executor/action.rs | 36 ------------------- evm_loader/program/src/executor/state.rs | 10 +----- 8 files changed, 5 insertions(+), 58 deletions(-) diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index 2d2997fee..9d99e902a 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -307,9 +307,6 @@ impl EmulatorAccountStorage<'_, T> { let space = ContractAccount::required_account_size(&code); self.gas = self.gas.saturating_add(self.rent.minimum_balance(space)); } - Action::EvmSelfDestruct { address } => { - info!("selfdestruct {address}"); - } Action::ExternalInstruction { program_id, accounts, diff --git a/evm_loader/lib/src/tracing/tracers/state_diff.rs b/evm_loader/lib/src/tracing/tracers/state_diff.rs index 6fd1571af..84caa03e5 100644 --- a/evm_loader/lib/src/tracing/tracers/state_diff.rs +++ b/evm_loader/lib/src/tracing/tracers/state_diff.rs @@ -161,7 +161,7 @@ impl EventListener for StateDiffTracer { | opcode_table::EXTCODEHASH | opcode_table::EXTCODESIZE | opcode_table::BALANCE - | opcode_table::SELFDESTRUCT + | opcode_table::SENDALL if !stack.is_empty() => { let address = Address::from(*array_ref!(stack[stack.len() - 1], 12, 20)); diff --git a/evm_loader/program/src/account_storage/apply.rs b/evm_loader/program/src/account_storage/apply.rs index 2ed31111e..ea11f6403 100644 --- a/evm_loader/program/src/account_storage/apply.rs +++ b/evm_loader/program/src/account_storage/apply.rs @@ -120,10 +120,6 @@ impl<'a> ProgramAccountStorage<'a> { Some(&self.keys), )?; } - Action::EvmSelfDestruct { address: _ } => { - // EIP-6780: SELFDESTRUCT only in the same transaction - // do nothing, balance was already transfered - } Action::ExternalInstruction { program_id, accounts, diff --git a/evm_loader/program/src/evm/database.rs b/evm_loader/program/src/evm/database.rs index d22eb11b8..0aadd4fdd 100644 --- a/evm_loader/program/src/evm/database.rs +++ b/evm_loader/program/src/evm/database.rs @@ -24,7 +24,6 @@ pub trait Database { async fn code_size(&self, address: Address) -> Result; async fn code(&self, address: Address) -> Result; fn set_code(&mut self, address: Address, chain_id: u64, code: Vec) -> Result<()>; - fn selfdestruct(&mut self, address: Address) -> Result<()>; async fn storage(&self, address: Address, index: U256) -> Result<[u8; 32]>; fn set_storage(&mut self, address: Address, index: U256, value: [u8; 32]) -> Result<()>; diff --git a/evm_loader/program/src/evm/opcode.rs b/evm_loader/program/src/evm/opcode.rs index 71707af9a..e06e0b5b3 100644 --- a/evm_loader/program/src/evm/opcode.rs +++ b/evm_loader/program/src/evm/opcode.rs @@ -1458,7 +1458,7 @@ impl Machine { /// Halt execution, destroys the contract and send all funds to address #[maybe_async] - pub async fn opcode_selfdestruct(&mut self, backend: &mut B) -> Result { + pub async fn opcode_sendall(&mut self, backend: &mut B) -> Result { if self.is_static { return Err(Error::StaticModeViolation(self.context.contract)); } @@ -1470,10 +1470,9 @@ impl Machine { backend .transfer(self.context.contract, address, chain_id, value) .await?; - backend.selfdestruct(self.context.contract)?; backend.commit_snapshot(); - log_data(&[b"EXIT", b"SELFDESTRUCT"]); + log_data(&[b"EXIT", b"SENDALL"]); end_vm!(self, backend, super::ExitStatus::Suicide); diff --git a/evm_loader/program/src/evm/opcode_table.rs b/evm_loader/program/src/evm/opcode_table.rs index 6b3bbf4fe..f74e05cb6 100644 --- a/evm_loader/program/src/evm/opcode_table.rs +++ b/evm_loader/program/src/evm/opcode_table.rs @@ -230,5 +230,5 @@ opcode_table![ 0xFD, REVERT, Self::opcode_revert; 0xFE, INVALID, Self::opcode_invalid; - 0xFF, SELFDESTRUCT, Self::opcode_selfdestruct; + 0xFF, SENDALL, Self::opcode_sendall; ]; diff --git a/evm_loader/program/src/executor/action.rs b/evm_loader/program/src/executor/action.rs index 33fcee932..17d8567e1 100644 --- a/evm_loader/program/src/executor/action.rs +++ b/evm_loader/program/src/executor/action.rs @@ -51,40 +51,4 @@ pub enum Action { #[serde(with = "serde_bytes")] code: Vec, }, - EvmSelfDestruct { - address: Address, - }, -} - -pub fn filter_selfdestruct(actions: Vec) -> Vec { - // Find all the account addresses which are scheduled to EvmSelfDestruct - let accounts_to_destroy: std::collections::HashSet<_> = actions - .iter() - .filter_map(|action| match action { - Action::EvmSelfDestruct { address } => Some(*address), - _ => None, - }) - .collect(); - - actions - .into_iter() - .filter(|action| { - match action { - // We always apply ExternalInstruction for Solana accounts - // and NeonTransfer + NeonWithdraw - Action::ExternalInstruction { .. } - | Action::Transfer { .. } - | Action::Burn { .. } => true, - // We remove EvmSetStorage|EvmIncrementNonce|EvmSetCode if account is scheduled for destroy - Action::EvmSetStorage { address, .. } - | Action::EvmSetTransientStorage { address, .. } - | Action::EvmSetCode { address, .. } - | Action::EvmIncrementNonce { address, .. } => { - !accounts_to_destroy.contains(address) - } - // SelfDestruct is only aplied to contracts deployed in the current transaction - Action::EvmSelfDestruct { .. } => false, - } - }) - .collect() } diff --git a/evm_loader/program/src/executor/state.rs b/evm_loader/program/src/executor/state.rs index 4e6eb37f6..5a953d3ad 100644 --- a/evm_loader/program/src/executor/state.rs +++ b/evm_loader/program/src/executor/state.rs @@ -69,8 +69,7 @@ impl<'a, B: AccountStorage> ExecutorState<'a, B> { pub fn into_actions(self) -> Vec { assert!(self.stack.is_empty()); - - crate::executor::action::filter_selfdestruct(self.actions) + self.actions } pub fn exit_status(&self) -> Option<&ExitStatus> { @@ -327,13 +326,6 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { Ok(()) } - fn selfdestruct(&mut self, address: Address) -> Result<()> { - let suicide = Action::EvmSelfDestruct { address }; - self.actions.push(suicide); - - Ok(()) - } - async fn storage(&self, from_address: Address, from_index: U256) -> Result<[u8; 32]> { for action in self.actions.iter().rev() { if let Action::EvmSetStorage { From 93a4694e6cbf89b6ae96bdf24075e84883d8390b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 29 Mar 2024 10:46:15 +0200 Subject: [PATCH 158/318] Bump async-trait from 0.1.78 to 0.1.79 in /evm_loader (#369) Bumps [async-trait](https://github.com/dtolnay/async-trait) from 0.1.78 to 0.1.79. - [Release notes](https://github.com/dtolnay/async-trait/releases) - [Commits](https://github.com/dtolnay/async-trait/compare/0.1.78...0.1.79) --- updated-dependencies: - dependency-name: async-trait dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- evm_loader/lib/Cargo.toml | 2 +- evm_loader/program/Cargo.toml | 2 +- evm_loader/rpc-client/Cargo.toml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 792ac2d0c..3c9ae2f46 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -622,9 +622,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.78" +version = "0.1.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "461abc97219de0eaaf81fe3ef974a540158f3d079c2ab200f891f1a2ef201e85" +checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" dependencies = [ "proc-macro2", "quote", diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index d9cfc287f..cf37903f3 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -33,7 +33,7 @@ scroll = "0.11.0" tokio = { version = "1", features = ["full"] } clickhouse = "0.11.6" tracing = "0.1" -async-trait = "0.1.78" +async-trait = "0.1.79" build-info = { version = "0.0.31", features = ["serde"] } enum_dispatch = "0.3.12" web3 = "0.19.0" diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 3afc9d3ca..d15010b4d 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -55,7 +55,7 @@ ethnum = { version = "1.5", default-features = false, features = ["serde"] } cfg-if = { version = "1.0" } log = { version = "0.4", default-features = false, optional = true } maybe-async = "0.2.10" -async-trait = { version = "0.1.78", optional = true } +async-trait = { version = "0.1.79", optional = true } [target.'cfg(target_os = "solana")'.dependencies.maybe-async] version = "0.2.7" diff --git a/evm_loader/rpc-client/Cargo.toml b/evm_loader/rpc-client/Cargo.toml index 414748597..f7eab8aa5 100644 --- a/evm_loader/rpc-client/Cargo.toml +++ b/evm_loader/rpc-client/Cargo.toml @@ -11,7 +11,7 @@ serde_json = "1.0.107" jsonrpc-v2 = "0.13.0" neon-lib = { path = "../lib" } thiserror = "1.0.58" -async-trait = "0.1.78" +async-trait = "0.1.79" jsonrpsee-core = "0.22.3" jsonrpsee-http-client = "0.22.3" jsonrpsee-types = "0.22.3" From 547b3621347452977e353a00cbe8d320eb8be549 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Mon, 1 Apr 2024 10:35:20 +0300 Subject: [PATCH 159/318] NDEV-2571 Use Solana Banks to simulate iterative transactions (#368) --- evm_loader/Cargo.lock | 275 +----------------- evm_loader/Cargo.toml | 5 +- evm_loader/api/src/api_server/handlers/mod.rs | 1 + .../api_server/handlers/simulate_solana.rs | 32 ++ evm_loader/api/src/main.rs | 2 + evm_loader/lib/Cargo.toml | 6 +- evm_loader/lib/src/abi/mod.rs | 4 + evm_loader/lib/src/abi/simulate_solana.rs | 17 ++ evm_loader/lib/src/commands/get_config.rs | 145 ++------- evm_loader/lib/src/commands/mod.rs | 1 + .../lib/src/commands/simulate_solana.rs | 73 +++++ evm_loader/lib/src/errors.rs | 6 +- evm_loader/lib/src/lib.rs | 3 + evm_loader/lib/src/solana_simulator/error.rs | 21 ++ evm_loader/lib/src/solana_simulator/mod.rs | 246 ++++++++++++++++ evm_loader/lib/src/solana_simulator/utils.rs | 192 ++++++++++++ evm_loader/lib/src/types/mod.rs | 11 + 17 files changed, 651 insertions(+), 389 deletions(-) create mode 100644 evm_loader/api/src/api_server/handlers/simulate_solana.rs create mode 100644 evm_loader/lib/src/abi/simulate_solana.rs create mode 100644 evm_loader/lib/src/commands/simulate_solana.rs create mode 100644 evm_loader/lib/src/solana_simulator/error.rs create mode 100644 evm_loader/lib/src/solana_simulator/mod.rs create mode 100644 evm_loader/lib/src/solana_simulator/utils.rs diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 3c9ae2f46..a8cc19308 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -73,7 +73,7 @@ dependencies = [ "memchr", "pin-project-lite", "tokio", - "tokio-util 0.7.7", + "tokio-util", "tracing", ] @@ -111,7 +111,7 @@ dependencies = [ "sha1", "smallvec", "tokio", - "tokio-util 0.7.7", + "tokio-util", "tracing", "zstd 0.13.0", ] @@ -1152,15 +1152,6 @@ dependencies = [ "windows-targets 0.52.3", ] -[[package]] -name = "chrono-humanize" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799627e6b4d27827a814e837b9d8a504832086081806d45b1afa34dc982b023b" -dependencies = [ - "chrono", -] - [[package]] name = "cipher" version = "0.3.0" @@ -1829,18 +1820,6 @@ dependencies = [ "sha2 0.10.8", ] -[[package]] -name = "educe" -version = "0.4.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f0042ff8246a363dbe77d2ceedb073339e85a804b9a47636c6e016a9a32c05f" -dependencies = [ - "enum-ordinalize", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "either" version = "1.10.0" @@ -1882,19 +1861,6 @@ dependencies = [ "syn 2.0.55", ] -[[package]] -name = "enum-ordinalize" -version = "3.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf1fa3f06bbff1ea5b1a9c7b14aa992a39657db60a2759457328d7e058f49ee" -dependencies = [ - "num-bigint 0.4.4", - "num-traits", - "proc-macro2", - "quote", - "syn 2.0.55", -] - [[package]] name = "enum_dispatch" version = "0.3.12" @@ -2383,7 +2349,7 @@ dependencies = [ "indexmap 2.2.3", "slab", "tokio", - "tokio-util 0.7.7", + "tokio-util", "tracing", ] @@ -3368,13 +3334,13 @@ dependencies = [ "serde", "serde_json", "serde_with 3.7.0", - "solana-clap-utils", + "solana-accounts-db", "solana-cli", "solana-cli-config", "solana-client", - "solana-program-test", + "solana-program-runtime", + "solana-runtime", "solana-sdk", - "solana-transaction-status", "spl-associated-token-account", "spl-token", "strum 0.26.2", @@ -3720,25 +3686,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "opentelemetry" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6105e89802af13fdf48c49d7646d3b533a70e536d818aae7e78ba0433d01acb8" -dependencies = [ - "async-trait", - "crossbeam-channel", - "futures-channel", - "futures-executor", - "futures-util", - "js-sys", - "lazy_static", - "percent-encoding", - "pin-project", - "rand 0.8.5", - "thiserror", -] - [[package]] name = "os_str_bytes" version = "6.5.0" @@ -4381,7 +4328,7 @@ dependencies = [ "tokio", "tokio-native-tls", "tokio-rustls", - "tokio-util 0.7.7", + "tokio-util", "tower-service", "url", "wasm-bindgen", @@ -5081,54 +5028,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "solana-banks-client" -version = "1.17.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de7daee8af1a4555236d6537ce9d5c10bc945f65e6468382699ad91d020a592" -dependencies = [ - "borsh 0.10.3", - "futures", - "solana-banks-interface", - "solana-program", - "solana-sdk", - "tarpc", - "thiserror", - "tokio", - "tokio-serde", -] - -[[package]] -name = "solana-banks-interface" -version = "1.17.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cab9eec320b5202c44693cdfdda3b674c92d95def8b0fe5ff2857108d5a81918" -dependencies = [ - "serde", - "solana-sdk", - "tarpc", -] - -[[package]] -name = "solana-banks-server" -version = "1.17.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaf48c1c27ae104b7aefdac5f2a024007cb24f01d1f50e3ea4a97588dc29056" -dependencies = [ - "bincode", - "crossbeam-channel", - "futures", - "solana-accounts-db", - "solana-banks-interface", - "solana-client", - "solana-runtime", - "solana-sdk", - "solana-send-transaction-service", - "tarpc", - "tokio", - "tokio-serde", -] - [[package]] name = "solana-bpf-loader-program" version = "1.17.28" @@ -5628,36 +5527,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "solana-program-test" -version = "1.17.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3756bfd3a7e55711c7042fbd63b27651f16ae9a2e780cc2c6d7128cefb0fb763" -dependencies = [ - "assert_matches", - "async-trait", - "base64 0.21.7", - "bincode", - "chrono-humanize", - "crossbeam-channel", - "log", - "serde", - "solana-accounts-db", - "solana-banks-client", - "solana-banks-interface", - "solana-banks-server", - "solana-bpf-loader-program", - "solana-logger", - "solana-program-runtime", - "solana-runtime", - "solana-sdk", - "solana-vote-program", - "solana_rbpf", - "test-case", - "thiserror", - "tokio", -] - [[package]] name = "solana-pubsub-client" version = "1.17.28" @@ -5951,22 +5820,6 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" -[[package]] -name = "solana-send-transaction-service" -version = "1.17.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01a0ac42573098147bf1d1dc8d4455fa2756757cd58435ffc75951e3d4858c1" -dependencies = [ - "crossbeam-channel", - "log", - "solana-client", - "solana-measure", - "solana-metrics", - "solana-runtime", - "solana-sdk", - "solana-tpu-client", -] - [[package]] name = "solana-stake-program" version = "1.17.28" @@ -6571,41 +6424,6 @@ dependencies = [ "xattr", ] -[[package]] -name = "tarpc" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38a012bed6fb9681d3bf71ffaa4f88f3b4b9ed3198cda6e4c8462d24d4bb80" -dependencies = [ - "anyhow", - "fnv", - "futures", - "humantime", - "opentelemetry", - "pin-project", - "rand 0.8.5", - "serde", - "static_assertions", - "tarpc-plugins", - "thiserror", - "tokio", - "tokio-serde", - "tokio-util 0.6.10", - "tracing", - "tracing-opentelemetry", -] - -[[package]] -name = "tarpc-plugins" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee42b4e559f17bce0385ebf511a7beb67d5cc33c12c96b7f4e9789919d9c10f" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "tempfile" version = "3.10.0" @@ -6627,39 +6445,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "test-case" -version = "3.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb2550dd13afcd286853192af8601920d959b14c401fcece38071d53bf0768a8" -dependencies = [ - "test-case-macros", -] - -[[package]] -name = "test-case-core" -version = "3.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcb7fd841cd518e279be3d5a3eb0636409487998a4aff22f3de87b81e88384f" -dependencies = [ - "cfg-if", - "proc-macro2", - "quote", - "syn 2.0.55", -] - -[[package]] -name = "test-case-macros" -version = "3.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.55", - "test-case-core", -] - [[package]] name = "textwrap" version = "0.11.0" @@ -6832,22 +6617,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-serde" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "911a61637386b789af998ee23f50aa30d5fd7edcec8d6d3dedae5e5815205466" -dependencies = [ - "bincode", - "bytes", - "educe", - "futures-core", - "futures-sink", - "pin-project", - "serde", - "serde_json", -] - [[package]] name = "tokio-stream" version = "0.1.14" @@ -6874,21 +6643,6 @@ dependencies = [ "webpki-roots 0.25.2", ] -[[package]] -name = "tokio-util" -version = "0.6.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "log", - "pin-project-lite", - "slab", - "tokio", -] - [[package]] name = "tokio-util" version = "0.7.7" @@ -7042,19 +6796,6 @@ dependencies = [ "tracing-core", ] -[[package]] -name = "tracing-opentelemetry" -version = "0.17.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbbe89715c1dbbb790059e2565353978564924ee85017b5fff365c872ff6721f" -dependencies = [ - "once_cell", - "opentelemetry", - "tracing", - "tracing-core", - "tracing-subscriber", -] - [[package]] name = "tracing-subscriber" version = "0.3.18" @@ -7414,7 +7155,7 @@ dependencies = [ "tiny-keccak", "tokio", "tokio-stream", - "tokio-util 0.7.7", + "tokio-util", "url", "web3-async-native-tls", ] diff --git a/evm_loader/Cargo.toml b/evm_loader/Cargo.toml index 8bf6737ff..ec864e037 100644 --- a/evm_loader/Cargo.toml +++ b/evm_loader/Cargo.toml @@ -17,6 +17,7 @@ solana-cli = "=1.17.28" solana-cli-config = "=1.17.28" solana-client = "=1.17.28" solana-program = { version = "=1.17.28", default-features = false } -solana-program-test = "=1.17.28" -solana-transaction-status = "=1.17.28" solana-sdk = "=1.17.28" +solana-program-runtime = "=1.17.28" +solana-runtime = "=1.17.28" +solana-accounts-db = "=1.17.28" \ No newline at end of file diff --git a/evm_loader/api/src/api_server/handlers/mod.rs b/evm_loader/api/src/api_server/handlers/mod.rs index a54447a0c..b8c3ac724 100644 --- a/evm_loader/api/src/api_server/handlers/mod.rs +++ b/evm_loader/api/src/api_server/handlers/mod.rs @@ -16,6 +16,7 @@ pub mod get_config; pub mod get_contract; pub mod get_holder; pub mod get_storage_at; +pub mod simulate_solana; pub mod trace; #[derive(Debug)] diff --git a/evm_loader/api/src/api_server/handlers/simulate_solana.rs b/evm_loader/api/src/api_server/handlers/simulate_solana.rs new file mode 100644 index 000000000..2bdca71e8 --- /dev/null +++ b/evm_loader/api/src/api_server/handlers/simulate_solana.rs @@ -0,0 +1,32 @@ +use actix_request_identifier::RequestId; +use actix_web::{http::StatusCode, post, web::Json, Responder}; +use std::convert::Into; +use tracing::info; + +use crate::api_server::handlers::process_error; +use crate::{ + commands::simulate_solana as SimulateSolanaCommand, types::SimulateSolanaRequest, NeonApiState, +}; + +use super::process_result; + +#[tracing::instrument(skip_all, fields(id = request_id.as_str()))] +#[post("/simulate_solana")] +pub async fn simulate_solana( + state: NeonApiState, + request_id: RequestId, + Json(emulate_request): Json, +) -> impl Responder { + info!("simulate_solana_request={:?}", emulate_request); + + let rpc = match state.build_rpc(None, None).await { + Ok(rpc) => rpc, + Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), + }; + + process_result( + &SimulateSolanaCommand::execute(&rpc, emulate_request) + .await + .map_err(Into::into), + ) +} diff --git a/evm_loader/api/src/main.rs b/evm_loader/api/src/main.rs index 077e7cf7d..1cba065cd 100644 --- a/evm_loader/api/src/main.rs +++ b/evm_loader/api/src/main.rs @@ -27,6 +27,7 @@ use crate::api_server::handlers::get_config::get_config; use crate::api_server::handlers::get_contract::get_contract; use crate::api_server::handlers::get_holder::get_holder_account_data; use crate::api_server::handlers::get_storage_at::get_storage_at; +use crate::api_server::handlers::simulate_solana::simulate_solana; use crate::api_server::handlers::trace::trace; use crate::build_info::get_build_info; pub use config::Config; @@ -77,6 +78,7 @@ async fn main() -> NeonApiResult<()> { .service(get_config) .service(get_holder_account_data) .service(trace) + .service(simulate_solana) .wrap(RequestIdentifier::with_uuid()), ) }) diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index cf37903f3..44f1fb3fc 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -12,11 +12,11 @@ bincode = "1.3.1" evm-loader = { path = "../program", default-features = false, features = ["log", "async-trait"] } solana-sdk.workspace = true solana-client.workspace = true -solana-clap-utils.workspace = true solana-cli-config.workspace = true solana-cli.workspace = true -solana-transaction-status.workspace = true -solana-program-test.workspace = true +solana-program-runtime.workspace = true +solana-runtime.workspace = true +solana-accounts-db.workspace = true spl-token = { version = "~4.0", default-features = false, features = ["no-entrypoint"] } spl-associated-token-account = { version = "~2.3", default-features = false, features = ["no-entrypoint"] } bs58 = "0.5.1" diff --git a/evm_loader/lib/src/abi/mod.rs b/evm_loader/lib/src/abi/mod.rs index 2e8e40e15..6f181fb3f 100644 --- a/evm_loader/lib/src/abi/mod.rs +++ b/evm_loader/lib/src/abi/mod.rs @@ -4,6 +4,7 @@ mod get_config; mod get_contract; mod get_holder; mod get_storage_at; +mod simulate_solana; pub mod state; mod trace; @@ -113,6 +114,9 @@ async fn dispatch(method_str: &str, params_str: &str) -> Result trace::execute(&rpc, config, params_str) .await .map(|v| serde_json::to_string(&v).unwrap()), + LibMethod::SimulateSolana => simulate_solana::execute(&rpc, config, params_str) + .await + .map(|v| serde_json::to_string(&v).unwrap()), // _ => Err(NeonError::IncorrectLibMethod), } } diff --git a/evm_loader/lib/src/abi/simulate_solana.rs b/evm_loader/lib/src/abi/simulate_solana.rs new file mode 100644 index 000000000..d11858c02 --- /dev/null +++ b/evm_loader/lib/src/abi/simulate_solana.rs @@ -0,0 +1,17 @@ +use super::params_to_neon_error; +use crate::commands::simulate_solana::{self, SimulateSolanaResponse}; +use crate::config::APIOptions; +use crate::rpc::Rpc; +use crate::types::SimulateSolanaRequest; +use crate::NeonResult; + +pub async fn execute( + rpc: &impl Rpc, + _config: &APIOptions, + params: &str, +) -> NeonResult { + let params: SimulateSolanaRequest = + serde_json::from_str(params).map_err(|_| params_to_neon_error(params))?; + + simulate_solana::execute(rpc, params).await +} diff --git a/evm_loader/lib/src/commands/get_config.rs b/evm_loader/lib/src/commands/get_config.rs index 019713936..48c01c789 100644 --- a/evm_loader/lib/src/commands/get_config.rs +++ b/evm_loader/lib/src/commands/get_config.rs @@ -1,28 +1,18 @@ use async_trait::async_trait; use base64::Engine; use enum_dispatch::enum_dispatch; +use solana_sdk::signer::Signer; use std::collections::BTreeMap; use serde::{Deserialize, Serialize}; -use solana_program_test::{ProgramTest, ProgramTestContext}; -use solana_sdk::{ - account::{Account, AccountSharedData}, - account_utils::StateMut, - bpf_loader, bpf_loader_deprecated, - bpf_loader_upgradeable::{self, UpgradeableLoaderState}, - instruction::Instruction, - pubkey::Pubkey, - rent::Rent, - signer::Signer, - transaction::Transaction, -}; - -use crate::{rpc::Rpc, NeonError, NeonResult}; +use solana_sdk::{instruction::Instruction, pubkey::Pubkey, transaction::Transaction}; + +use crate::solana_simulator::SolanaSimulator; +use crate::NeonResult; use crate::rpc::{CallDbClient, CloneRpcClient}; use serde_with::{serde_as, DisplayFromStr}; use solana_client::rpc_config::RpcSimulateTransactionConfig; -use tokio::sync::{Mutex, MutexGuard, OnceCell}; #[derive(Debug, Serialize, Deserialize)] pub enum Status { @@ -51,69 +41,6 @@ pub struct GetConfigResponse { pub config: BTreeMap, } -impl CallDbClient { - async fn read_program_data_from_account(&self, program_id: Pubkey) -> NeonResult> { - let Some(account) = self.get_account(&program_id).await?.value else { - return Err(NeonError::AccountNotFound(program_id)); - }; - - if account.owner == bpf_loader::id() || account.owner == bpf_loader_deprecated::id() { - return Ok(account.data); - } - - if account.owner != bpf_loader_upgradeable::id() { - return Err(NeonError::AccountIsNotBpf(program_id)); - } - - if let Ok(UpgradeableLoaderState::Program { - programdata_address: address, - }) = account.state() - { - let Some(programdata_account) = self.get_account(&address).await?.value else { - return Err(NeonError::AssociatedPdaNotFound(address, program_id)); - }; - - let offset = UpgradeableLoaderState::size_of_programdata_metadata(); - let program_data = &programdata_account.data[offset..]; - - Ok(program_data.to_vec()) - } else { - Err(NeonError::AccountIsNotUpgradeable(program_id)) - } - } -} - -async fn program_test_context() -> MutexGuard<'static, ProgramTestContext> { - static PROGRAM_TEST_CONTEXT: OnceCell> = OnceCell::const_new(); - - async fn init_program_test_context() -> Mutex { - Mutex::new(ProgramTest::default().start_with_context().await) - } - - PROGRAM_TEST_CONTEXT - .get_or_init(init_program_test_context) - .await - .lock() - .await -} - -fn set_program_account( - program_test_context: &mut ProgramTestContext, - program_id: Pubkey, - program_data: Vec, -) { - program_test_context.set_account( - &program_id, - &AccountSharedData::from(Account { - lamports: Rent::default().minimum_balance(program_data.len()).max(1), - data: program_data, - owner: bpf_loader::id(), - executable: true, - rent_epoch: 0, - }), - ); -} - pub enum ConfigSimulator<'r> { CloneRpcClient { program_id: Pubkey, @@ -121,7 +48,7 @@ pub enum ConfigSimulator<'r> { }, ProgramTestContext { program_id: Pubkey, - program_test: MutexGuard<'static, ProgramTestContext>, + simulator: SolanaSimulator, }, } @@ -144,23 +71,28 @@ impl BuildConfigSimulator for CloneRpcClient { #[async_trait(?Send)] impl BuildConfigSimulator for CallDbClient { async fn build_config_simulator(&self, program_id: Pubkey) -> NeonResult { - let program_data = self.read_program_data_from_account(program_id).await?; - - let mut program_test = program_test_context().await; - - set_program_account(&mut program_test, program_id, program_data); - program_test.get_new_latest_blockhash().await?; + let mut simulator = SolanaSimulator::new(self).await?; + simulator.sync_accounts(self, &[program_id]).await?; Ok(ConfigSimulator::ProgramTestContext { program_id, - program_test, + simulator, }) } } -impl CloneRpcClient { +#[async_trait(?Send)] +trait ConfigInstructionSimulator { async fn simulate_solana_instruction( - &self, + &mut self, + instruction: Instruction, + ) -> NeonResult>; +} + +#[async_trait(?Send)] +impl ConfigInstructionSimulator for &CloneRpcClient { + async fn simulate_solana_instruction( + &mut self, instruction: Instruction, ) -> NeonResult> { let tx = Transaction::new_with_payer(&[instruction], Some(&self.key_for_config)); @@ -185,37 +117,22 @@ impl CloneRpcClient { } #[async_trait(?Send)] -trait SolanaInstructionSimulator { - async fn simulate_solana_instruction( - &mut self, - instruction: Instruction, - ) -> NeonResult>; -} - -#[async_trait(?Send)] -impl SolanaInstructionSimulator for ProgramTestContext { +impl ConfigInstructionSimulator for SolanaSimulator { async fn simulate_solana_instruction( &mut self, instruction: Instruction, ) -> NeonResult> { - let tx = Transaction::new_signed_with_payer( - &[instruction], - Some(&self.payer.pubkey()), - &[&self.payer], - self.last_blockhash, - ); + let payer_pubkey = self.payer().pubkey(); - // TODO: Fix failure to simulate transaction - // it can come from old NeonEVM program without chain_id support for old tx, when it should return default chain_id info - let result = self - .banks_client - .simulate_transaction(tx) - .await - .map_err(|e| NeonError::from(Box::new(e)))?; + let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer_pubkey)); + transaction.message.recent_blockhash = self.blockhash(); - result.result.unwrap()?; + let r = self.simulate_legacy_transaction(transaction)?; + if let Err(e) = r.result { + return Err(e.into()); + } - Ok(result.simulation_details.unwrap().logs) + Ok(r.logs) } } @@ -266,8 +183,8 @@ impl ConfigSimulator<'_> { ConfigSimulator::CloneRpcClient { rpc, .. } => { rpc.simulate_solana_instruction(instruction).await } - ConfigSimulator::ProgramTestContext { program_test, .. } => { - program_test.simulate_solana_instruction(instruction).await + ConfigSimulator::ProgramTestContext { simulator, .. } => { + simulator.simulate_solana_instruction(instruction).await } } } diff --git a/evm_loader/lib/src/commands/mod.rs b/evm_loader/lib/src/commands/mod.rs index 801b7b7c7..1749e5ddc 100644 --- a/evm_loader/lib/src/commands/mod.rs +++ b/evm_loader/lib/src/commands/mod.rs @@ -21,6 +21,7 @@ pub mod get_holder; pub mod get_neon_elf; pub mod get_storage_at; pub mod init_environment; +pub mod simulate_solana; pub mod trace; mod transaction_executor; diff --git a/evm_loader/lib/src/commands/simulate_solana.rs b/evm_loader/lib/src/commands/simulate_solana.rs new file mode 100644 index 000000000..ae32fbadb --- /dev/null +++ b/evm_loader/lib/src/commands/simulate_solana.rs @@ -0,0 +1,73 @@ +use std::collections::HashSet; + +use bincode::Options; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; +use solana_program_runtime::compute_budget::ComputeBudget; +use solana_runtime::runtime_config::RuntimeConfig; +use solana_sdk::{pubkey::Pubkey, transaction::VersionedTransaction}; + +use crate::{ + rpc::Rpc, solana_simulator::SolanaSimulator, types::SimulateSolanaRequest, NeonResult, +}; + +#[serde_as] +#[derive(Deserialize, Serialize, Debug, Default)] +pub struct SimulateSolanaTransactionResult { + pub error: Option, + pub logs: Vec, + pub executed_units: u64, +} + +#[serde_as] +#[derive(Deserialize, Serialize, Debug, Default)] +pub struct SimulateSolanaResponse { + transactions: Vec, +} + +pub async fn execute( + rpc: &impl Rpc, + request: SimulateSolanaRequest, +) -> NeonResult { + let mut transactions: Vec = vec![]; + for data in request.transactions { + let tx = bincode::options() + .with_fixint_encoding() + .allow_trailing_bytes() + .deserialize(&data)?; + + transactions.push(tx); + } + + let mut accounts: HashSet = HashSet::::new(); + for tx in &transactions { + let keys = tx.message.static_account_keys(); + accounts.extend(keys); + } + + let config = RuntimeConfig { + compute_budget: request.compute_units.map(ComputeBudget::new), + log_messages_bytes_limit: Some(100 * 1024), + transaction_account_lock_limit: request.account_limit, + }; + let mut simulator = SolanaSimulator::new_with_config(rpc, config).await?; + + let accounts: Vec = accounts.into_iter().collect(); + simulator.sync_accounts(rpc, &accounts).await?; + + simulator.replace_blockhash(&request.blockhash.into()); + + let results = simulator + .process_multiple_transactions(transactions)? + .into_iter() + .map(|r| SimulateSolanaTransactionResult { + error: r.status.err(), + logs: r.log_messages.unwrap_or_default(), + executed_units: r.executed_units, + }) + .collect(); + + Ok(SimulateSolanaResponse { + transactions: results, + }) +} diff --git a/evm_loader/lib/src/errors.rs b/evm_loader/lib/src/errors.rs index e6ab476c5..6cc0865d9 100644 --- a/evm_loader/lib/src/errors.rs +++ b/evm_loader/lib/src/errors.rs @@ -105,8 +105,6 @@ pub enum NeonError { EarlySlot(u64, u64), #[error("Json Error. {0}")] SerdeJson(#[from] serde_json::Error), - #[error("BanksClient Error. {0}")] - BanksClientError(#[from] Box), #[error("Transaction Error. {0}")] TransactionError(#[from] TransactionError), #[error("Bincode Error. {0}")] @@ -123,6 +121,8 @@ pub enum NeonError { IncorrectLibMethod, #[error("strum parse error {0:?}")] StrumParseError(#[from] strum::ParseError), + #[error("Solana Simulator error {0:?}")] + SolanaSimulatorError(#[from] crate::solana_simulator::Error), } impl NeonError { @@ -159,7 +159,6 @@ impl NeonError { NeonError::ClickHouse(_) => 252, NeonError::EarlySlot(_, _) => 253, NeonError::SerdeJson(_) => 254, - NeonError::BanksClientError(_) => 255, NeonError::TransactionError(_) => 256, NeonError::BincodeError(_) => 257, NeonError::FromUtf8Error(_) => 258, @@ -169,6 +168,7 @@ impl NeonError { NeonError::LoadingDBConfigError => 262, NeonError::IncorrectLibMethod => 263, NeonError::StrumParseError(_) => 264, + NeonError::SolanaSimulatorError(_) => 265, } } } diff --git a/evm_loader/lib/src/lib.rs b/evm_loader/lib/src/lib.rs index 57d634521..4e5b8d771 100644 --- a/evm_loader/lib/src/lib.rs +++ b/evm_loader/lib/src/lib.rs @@ -7,6 +7,7 @@ pub mod config; pub mod errors; pub mod rpc; +pub mod solana_simulator; pub mod tracing; pub mod types; @@ -43,4 +44,6 @@ pub enum LibMethod { GetHolder, #[strum(serialize = "trace")] Trace, + #[strum(serialize = "simulate_solana")] + SimulateSolana, } diff --git a/evm_loader/lib/src/solana_simulator/error.rs b/evm_loader/lib/src/solana_simulator/error.rs new file mode 100644 index 000000000..405ebf230 --- /dev/null +++ b/evm_loader/lib/src/solana_simulator/error.rs @@ -0,0 +1,21 @@ +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("Unexpected response")] + UnexpectedResponse, + #[error("Program Account error")] + ProgramAccountError, + #[error("Rpc Client error {0:?}")] + RpcClientError(#[from] solana_client::client_error::ClientError), + #[error("IO error {0:?}")] + IoError(#[from] std::io::Error), + #[error("Bincode error {0:?}")] + BincodeError(#[from] bincode::Error), + #[error("TryFromIntError error {0:?}")] + TryFromIntError(#[from] std::num::TryFromIntError), + #[error("Transaction error {0:?}")] + TransactionError(#[from] solana_sdk::transaction::TransactionError), + #[error("Sanitize error {0:?}")] + SanitizeError(#[from] solana_sdk::sanitize::SanitizeError), + #[error("Instruction error {0:?}")] + InstructionError(#[from] solana_sdk::instruction::InstructionError), +} diff --git a/evm_loader/lib/src/solana_simulator/mod.rs b/evm_loader/lib/src/solana_simulator/mod.rs new file mode 100644 index 000000000..151a5bae1 --- /dev/null +++ b/evm_loader/lib/src/solana_simulator/mod.rs @@ -0,0 +1,246 @@ +use std::sync::Arc; + +use solana_accounts_db::transaction_results::{ + TransactionExecutionDetails, TransactionExecutionResult, +}; +use solana_runtime::{ + bank::{Bank, TransactionSimulationResult}, + runtime_config::RuntimeConfig, +}; +use solana_sdk::{ + account::Account, + bpf_loader, bpf_loader_upgradeable, + hash::Hash, + pubkey::Pubkey, + signature::Keypair, + transaction::{ + MessageHash, SanitizedTransaction, TransactionVerificationMode, VersionedTransaction, + }, +}; + +use crate::rpc::Rpc; + +mod error; +mod utils; + +pub use error::Error; + +pub struct SolanaSimulator { + bank: Bank, + runtime_config: Arc, + payer: Keypair, +} + +impl SolanaSimulator { + pub async fn new(rpc: &impl Rpc) -> Result { + Self::new_with_config(rpc, RuntimeConfig::default()).await + } + + pub async fn new_with_config( + rpc: &impl Rpc, + runtime_config: RuntimeConfig, + ) -> Result { + let runtime_config = Arc::new(runtime_config); + + let info = utils::genesis_config_info(rpc, 1_000.0).await?; + let payer = info.mint_keypair; + + let genesis_bank = Arc::new(Bank::new_with_paths( + &info.genesis_config, + Arc::clone(&runtime_config), + Vec::default(), + None, + None, + solana_accounts_db::accounts_index::AccountSecondaryIndexes::default(), + solana_accounts_db::accounts_db::AccountShrinkThreshold::default(), + false, + None, + None, + Arc::default(), + )); + + genesis_bank.set_capitalization(); + + genesis_bank.fill_bank_with_ticks_for_tests(); + let mut bank = Bank::new_from_parent( + Arc::clone(&genesis_bank), + genesis_bank.collector_id(), + genesis_bank.slot() + 1, + ); + + utils::sync_sysvar_accounts(rpc, &mut bank).await?; + + Ok(Self { + bank, + runtime_config, + payer, + }) + } + + pub async fn sync_accounts(&mut self, rpc: &impl Rpc, keys: &[Pubkey]) -> Result<(), Error> { + let mut storable_accounts = vec![]; + + let mut programdata_keys = vec![]; + + let accounts = rpc.get_multiple_accounts(keys).await?; + for (key, account) in keys.iter().zip(&accounts) { + let Some(account) = account else { + continue; + }; + + if account.executable && bpf_loader_upgradeable::check_id(&account.owner) { + let programdata_address = utils::program_data_address(account)?; + programdata_keys.push(programdata_address); + } + + storable_accounts.push((key, account)); + } + + let mut programdata_accounts = rpc.get_multiple_accounts(&programdata_keys).await?; + for (key, account) in programdata_keys.iter().zip(&mut programdata_accounts) { + let Some(account) = account else { + continue; + }; + + utils::reset_program_data_slot(account)?; + storable_accounts.push((key, account)); + } + + self.set_multiple_accounts(&storable_accounts); + + Ok(()) + } + + fn bank(&self) -> &Bank { + &self.bank + } + + pub fn payer(&self) -> &Keypair { + &self.payer + } + + pub fn blockhash(&self) -> Hash { + self.bank().last_blockhash() + } + + pub fn slot(&self) -> u64 { + self.bank().slot() + } + + pub fn replace_blockhash(&mut self, blockhash: &Hash) { + self.bank().register_recent_blockhash(blockhash); + } + + pub fn set_program_account(&mut self, pubkey: &Pubkey, data: Vec) { + let rent = self.bank().rent_collector().rent; + let lamports = rent.minimum_balance(data.len()); + + self.set_account( + pubkey, + &Account { + lamports, + data, + owner: bpf_loader::ID, + executable: true, + rent_epoch: 0, + }, + ); + } + + pub fn set_account(&mut self, pubkey: &Pubkey, account: &Account) { + self.bank().store_account(pubkey, account); + } + + pub fn set_multiple_accounts(&mut self, accounts: &[(&Pubkey, &Account)]) { + let include_slot_in_hash = if self + .bank() + .feature_set + .is_active(&solana_sdk::feature_set::account_hash_ignore_slot::id()) + { + solana_accounts_db::accounts_db::IncludeSlotInHash::RemoveSlot + } else { + solana_accounts_db::accounts_db::IncludeSlotInHash::IncludeSlot + }; + + let storable_accounts = (self.slot(), accounts, include_slot_in_hash); + self.bank().store_accounts(storable_accounts); + } + + pub fn get_account(&self, pubkey: &Pubkey) -> Option { + self.bank() + .get_account_with_fixed_root(pubkey) + .map(Account::from) + } + + pub fn process_transaction( + &mut self, + tx: VersionedTransaction, + ) -> Result { + let mut result = self.process_multiple_transactions(vec![tx])?; + + Ok(result.remove(0)) + } + + pub fn process_multiple_transactions( + &mut self, + txs: Vec, + ) -> Result, Error> { + let bank = self.bank(); + + let mut sanitized_transactions = vec![]; + for tx in txs { + let sanitized = + bank.verify_transaction(tx, TransactionVerificationMode::FullVerification)?; + sanitized_transactions.push(sanitized); + } + + let batch = bank.prepare_sanitized_batch(&sanitized_transactions); + + let ( + solana_accounts_db::transaction_results::TransactionResults { + execution_results, .. + }, + .., + ) = bank.load_execute_and_commit_transactions( + &batch, + solana_sdk::clock::MAX_PROCESSING_AGE, + false, // collect_balances + true, // enable_cpi_recording + true, // enable_log_recording + true, // enable_return_data_recording + &mut solana_program_runtime::timings::ExecuteTimings::default(), + self.runtime_config.log_messages_bytes_limit, + ); + + let mut result = Vec::with_capacity(execution_results.len()); + + for execution_result in execution_results { + match execution_result { + TransactionExecutionResult::Executed { details, .. } => result.push(details), + TransactionExecutionResult::NotExecuted(error) => return Err(error.into()), + } + } + + Ok(result) + } + + pub fn simulate_transaction( + &self, + tx: VersionedTransaction, + ) -> Result { + let sanitized = + SanitizedTransaction::try_create(tx, MessageHash::Compute, None, self.bank())?; + + let simulation_result = self.bank().simulate_transaction_unchecked(sanitized); + + Ok(simulation_result) + } + + pub fn simulate_legacy_transaction( + &self, + tx: solana_sdk::transaction::Transaction, + ) -> Result { + let versioned_transaction = VersionedTransaction::from(tx); + self.simulate_transaction(versioned_transaction) + } +} diff --git a/evm_loader/lib/src/solana_simulator/utils.rs b/evm_loader/lib/src/solana_simulator/utils.rs new file mode 100644 index 000000000..ff751766a --- /dev/null +++ b/evm_loader/lib/src/solana_simulator/utils.rs @@ -0,0 +1,192 @@ +use super::error::Error; +use solana_runtime::{ + bank::Bank, + genesis_utils::{create_genesis_config_with_leader_ex, GenesisConfigInfo}, +}; +use solana_sdk::{ + account::Account, + account_utils::StateMut, + bpf_loader_upgradeable::{self, UpgradeableLoaderState}, + fee_calculator::DEFAULT_TARGET_LAMPORTS_PER_SIGNATURE, + native_token::sol_to_lamports, + pubkey::Pubkey, + signature::Keypair, + signer::Signer, + sysvar, +}; + +use crate::rpc::Rpc; + +pub async fn genesis_config_info( + rpc: &impl Rpc, + mint_sol: f64, +) -> Result { + let rent = sysvar::rent::Rent::default(); + let fee_rate_governor = solana_sdk::fee_calculator::FeeRateGovernor { + // Initialize with a non-zero fee + lamports_per_signature: DEFAULT_TARGET_LAMPORTS_PER_SIGNATURE / 2, + ..solana_sdk::fee_calculator::FeeRateGovernor::default() + }; + let validator_pubkey = Pubkey::new_unique(); + let validator_stake_lamports = rent + .minimum_balance(solana_sdk::vote::state::VoteState::size_of()) + + sol_to_lamports(1_000_000.0); + + let mint_keypair = Keypair::new(); + let voting_keypair = Keypair::new(); + + let mut genesis_config = create_genesis_config_with_leader_ex( + sol_to_lamports(mint_sol), + &mint_keypair.pubkey(), + &validator_pubkey, + &voting_keypair.pubkey(), + &Pubkey::new_unique(), + validator_stake_lamports, + 42, + fee_rate_governor, + rent, + solana_sdk::genesis_config::ClusterType::Development, + vec![], + ); + + for feature in deactivated_features(rpc).await? { + genesis_config.accounts.remove(&feature); + } + + Ok(GenesisConfigInfo { + genesis_config, + mint_keypair, + voting_keypair, + validator_pubkey, + }) +} + +pub async fn deactivated_features(rpc: &impl Rpc) -> Result, Error> { + let feature_keys: Vec = solana_sdk::feature_set::FEATURE_NAMES + .keys() + .copied() + .collect(); + let features = rpc.get_multiple_accounts(&feature_keys).await?; + + let mut result = Vec::with_capacity(feature_keys.len()); + for (pubkey, feature) in feature_keys.iter().zip(features) { + let is_activated = feature + .and_then(|a| solana_sdk::feature::from_account(&a)) + .and_then(|f| f.activated_at) + .is_some(); + + if !is_activated { + result.push(*pubkey); + } + } + + Ok(result) +} + +pub async fn sync_sysvar_accounts(rpc: &impl Rpc, bank: &mut Bank) -> Result<(), Error> { + let keys = sysvar::ALL_IDS.clone(); + let accounts = rpc.get_multiple_accounts(&keys).await?; + + for (key, account) in keys.into_iter().zip(accounts) { + let Some(account) = account else { + continue; + }; + + match key { + sysvar::clock::ID => { + use sysvar::clock::Clock; + + let clock: Clock = bincode::deserialize(&account.data)?; + bank.set_sysvar_for_tests(&clock); + } + sysvar::epoch_schedule::ID => { + use sysvar::epoch_schedule::EpochSchedule; + + let epoch_schedule: EpochSchedule = bincode::deserialize(&account.data)?; + bank.set_sysvar_for_tests(&epoch_schedule); + } + sysvar::rent::ID => { + use sysvar::rent::Rent; + + let rent: Rent = bincode::deserialize(&account.data)?; + bank.set_sysvar_for_tests(&rent); + } + sysvar::rewards::ID => { + use sysvar::rewards::Rewards; + + let rewards: Rewards = bincode::deserialize(&account.data)?; + bank.set_sysvar_for_tests(&rewards); + } + sysvar::slot_hashes::ID => { + use sysvar::slot_hashes::SlotHashes; + + let slot_hashes: SlotHashes = bincode::deserialize(&account.data)?; + bank.set_sysvar_for_tests(&slot_hashes); + } + sysvar::slot_history::ID => { + use sysvar::slot_history::SlotHistory; + + let slot_history: SlotHistory = bincode::deserialize(&account.data)?; + bank.set_sysvar_for_tests(&slot_history); + } + sysvar::stake_history::ID => { + use sysvar::stake_history::StakeHistory; + + let stake_history: StakeHistory = bincode::deserialize(&account.data)?; + bank.set_sysvar_for_tests(&stake_history); + } + #[allow(deprecated)] + id if sysvar::fees::check_id(&id) => { + use sysvar::fees::Fees; + + let fees: Fees = bincode::deserialize(&account.data)?; + bank.set_sysvar_for_tests(&fees); + } + #[allow(deprecated)] + id if sysvar::recent_blockhashes::check_id(&id) => { + use sysvar::recent_blockhashes::RecentBlockhashes; + + let recent_blockhashes: RecentBlockhashes = bincode::deserialize(&account.data)?; + bank.set_sysvar_for_tests(&recent_blockhashes); + } + _ => {} + } + } + + Ok(()) +} + +pub fn program_data_address(account: &Account) -> Result { + assert!(account.executable); + assert!(account.owner == bpf_loader_upgradeable::id()); + + let UpgradeableLoaderState::Program { + programdata_address, + .. + } = account.state()? + else { + return Err(Error::ProgramAccountError); + }; + + Ok(programdata_address) +} + +pub fn reset_program_data_slot(account: &mut Account) -> Result<(), Error> { + assert!(account.owner == bpf_loader_upgradeable::id()); + + let UpgradeableLoaderState::ProgramData { + upgrade_authority_address, + .. + } = account.state()? + else { + return Err(Error::ProgramAccountError); + }; + + let new_state = UpgradeableLoaderState::ProgramData { + slot: 0, + upgrade_authority_address, + }; + account.set_state(&new_state)?; + + Ok(()) +} diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index f60c9d051..28df797fb 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -207,6 +207,17 @@ pub struct GetHolderRequest { pub slot: Option, } +#[serde_as] +#[derive(Deserialize, Serialize, Debug, Default)] +pub struct SimulateSolanaRequest { + pub compute_units: Option, + pub account_limit: Option, + #[serde_as(as = "Hex")] + pub blockhash: [u8; 32], + #[serde_as(as = "Vec")] + pub transactions: Vec>, +} + #[cfg(test)] mod tests { use crate::types::tracer_ch_common::RevisionMap; From 428fa343716b6aa604a898e41ff9341dffc6b14f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Apr 2024 15:20:43 +0300 Subject: [PATCH 160/318] Bump serde_json from 1.0.114 to 1.0.115 in /evm_loader (#372) Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.114 to 1.0.115. - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.114...v1.0.115) --- updated-dependencies: - dependency-name: serde_json dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- evm_loader/api/Cargo.toml | 2 +- evm_loader/cli/Cargo.toml | 2 +- evm_loader/lib-interface/Cargo.toml | 2 +- evm_loader/program/Cargo.toml | 2 +- evm_loader/rpc-client/Cargo.toml | 2 +- evm_loader/rpc/Cargo.toml | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index a8cc19308..14559c61b 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -4661,9 +4661,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" dependencies = [ "indexmap 2.2.3", "itoa", diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index c5bb950e3..f878b793f 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -11,7 +11,7 @@ evm-loader = { path = "../program", default-features = false, features = ["log"] solana-sdk.workspace = true solana-client.workspace = true serde = "1.0.186" -serde_json = { version = "1.0.114", features = ["preserve_order"] } +serde_json = { version = "1.0.115", features = ["preserve_order"] } ethnum = { version = "1.5", default-features = false, features = ["serde"] } tokio = { version = "1", features = ["full"] } tracing = "0.1" diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index 0fc9369d6..e146ca0ca 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -14,7 +14,7 @@ solana-clap-utils.workspace = true solana-cli-config.workspace = true hex = "0.4.2" serde = "1.0.186" -serde_json = { version = "1.0.114", features = ["preserve_order"] } +serde_json = { version = "1.0.115", features = ["preserve_order"] } log = "0.4.21" fern = "0.6" ethnum = { version = "1.5", default-features = false, features = ["serde"] } diff --git a/evm_loader/lib-interface/Cargo.toml b/evm_loader/lib-interface/Cargo.toml index 656320378..9684f5d38 100644 --- a/evm_loader/lib-interface/Cargo.toml +++ b/evm_loader/lib-interface/Cargo.toml @@ -10,4 +10,4 @@ abi_stable = "0.11.1" thiserror = "1" async-ffi = { version = "0.5.0", features = ["abi_stable"] } serde = "1.0.147" -serde_json = "1.0.85" +serde_json = "1.0.115" diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index d15010b4d..713758be2 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -63,7 +63,7 @@ features = ["is_sync"] [dev-dependencies] tokio = { version = "1.0", features = ["full"] } -serde_json = { version = "1.0.114", features = ["preserve_order"] } +serde_json = { version = "1.0.115", features = ["preserve_order"] } [lib] crate-type = ["cdylib", "lib"] diff --git a/evm_loader/rpc-client/Cargo.toml b/evm_loader/rpc-client/Cargo.toml index f7eab8aa5..7eb22c560 100644 --- a/evm_loader/rpc-client/Cargo.toml +++ b/evm_loader/rpc-client/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] serde = "1.0.189" -serde_json = "1.0.107" +serde_json = "1.0.115" jsonrpc-v2 = "0.13.0" neon-lib = { path = "../lib" } thiserror = "1.0.58" diff --git a/evm_loader/rpc/Cargo.toml b/evm_loader/rpc/Cargo.toml index 4bfcf8624..aa6a64581 100644 --- a/evm_loader/rpc/Cargo.toml +++ b/evm_loader/rpc/Cargo.toml @@ -13,7 +13,7 @@ neon-lib-interface = { path = "../lib-interface" } neon-lib = { path = "../lib" } semver = "1.0.18" serde = "1.0.188" -serde_json = "1.0.107" +serde_json = "1.0.115" tokio = { version = "1", features = ["full"] } build-info = { version = "0.0.31", features = ["serde"] } thiserror = "1.0" From 7261fe6476dd41da1159a45f6a809d35b1cf27a2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Apr 2024 09:06:07 +0300 Subject: [PATCH 161/318] Bump enum_dispatch from 0.3.12 to 0.3.13 in /evm_loader (#375) Bumps [enum_dispatch](https://gitlab.com/antonok/enum_dispatch) from 0.3.12 to 0.3.13. - [Changelog](https://gitlab.com/antonok/enum_dispatch/blob/master/CHANGELOG.md) - [Commits](https://gitlab.com/antonok/enum_dispatch/compare/v0.3.12...v0.3.13) --- updated-dependencies: - dependency-name: enum_dispatch dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- evm_loader/lib/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 14559c61b..d88c1e31a 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -1863,9 +1863,9 @@ dependencies = [ [[package]] name = "enum_dispatch" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f33313078bb8d4d05a2733a94ac4c2d8a0df9a2b84424ebf4f33bfc224a890e" +checksum = "aa18ce2bc66555b3218614519ac839ddb759a7d6720732f979ef8d13be147ecd" dependencies = [ "once_cell", "proc-macro2", diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 44f1fb3fc..c012e7334 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -35,7 +35,7 @@ clickhouse = "0.11.6" tracing = "0.1" async-trait = "0.1.79" build-info = { version = "0.0.31", features = ["serde"] } -enum_dispatch = "0.3.12" +enum_dispatch = "0.3.13" web3 = "0.19.0" neon-lib-interface = { path = "../lib-interface" } abi_stable = "0.11.2" From 7c45841b89919d1bdbe6378d7e92ad63d8bd0168 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Apr 2024 13:49:55 +0300 Subject: [PATCH 162/318] Bump syn from 2.0.55 to 2.0.57 in /evm_loader (#376) Bumps [syn](https://github.com/dtolnay/syn) from 2.0.55 to 2.0.57. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.55...2.0.57) --- updated-dependencies: - dependency-name: syn dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 78 +++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index d88c1e31a..e6a424841 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -123,7 +123,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -247,7 +247,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -628,7 +628,7 @@ checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -982,7 +982,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.55", + "syn 2.0.57", "xz2", ] @@ -1025,7 +1025,7 @@ checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -1552,7 +1552,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -1569,7 +1569,7 @@ checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -1593,7 +1593,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -1604,7 +1604,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -1776,7 +1776,7 @@ checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -1858,7 +1858,7 @@ checksum = "eecf8589574ce9b895052fa12d69af7a233f99e6107f5cb8dd1044f2a17bfdcb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -1870,7 +1870,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -2008,7 +2008,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.55", + "syn 2.0.57", "toml 0.8.2", ] @@ -2183,7 +2183,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -3117,7 +3117,7 @@ checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -3509,7 +3509,7 @@ checksum = "cfb77679af88f8b125209d354a202862602672222e7f2313fdd6dc349bad4712" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -3591,7 +3591,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -3603,7 +3603,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -3665,7 +3665,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -3835,7 +3835,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -3995,7 +3995,7 @@ checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -4645,7 +4645,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -4729,7 +4729,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -4741,7 +4741,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -5342,7 +5342,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -5811,7 +5811,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -6130,7 +6130,7 @@ checksum = "fadbefec4f3c678215ca72bd71862697bb06b41fd77c0088902dd3203354387b" dependencies = [ "quote", "spl-discriminator-syn", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -6142,7 +6142,7 @@ dependencies = [ "proc-macro2", "quote", "sha2 0.10.8", - "syn 2.0.55", + "syn 2.0.57", "thiserror", ] @@ -6190,7 +6190,7 @@ dependencies = [ "proc-macro2", "quote", "sha2 0.10.8", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -6358,7 +6358,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -6386,9 +6386,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.55" +version = "2.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" +checksum = "11a6ae1e52eb25aab8f3fb9fca13be982a373b8f1157ca14b897a825ba4a2d35" dependencies = [ "proc-macro2", "quote", @@ -6477,7 +6477,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -6594,7 +6594,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -6772,7 +6772,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -7069,7 +7069,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", "wasm-bindgen-shared", ] @@ -7103,7 +7103,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -7545,7 +7545,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -7565,7 +7565,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] From b337b5953dfd10f741be58764a842f59fcd963bb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Apr 2024 18:56:05 +0300 Subject: [PATCH 163/318] Bump syn from 2.0.57 to 2.0.58 in /evm_loader (#378) Bumps [syn](https://github.com/dtolnay/syn) from 2.0.57 to 2.0.58. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.57...2.0.58) --- updated-dependencies: - dependency-name: syn dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 78 +++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index e6a424841..e651cf723 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -123,7 +123,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -247,7 +247,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -628,7 +628,7 @@ checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -982,7 +982,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.57", + "syn 2.0.58", "xz2", ] @@ -1025,7 +1025,7 @@ checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -1552,7 +1552,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -1569,7 +1569,7 @@ checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -1593,7 +1593,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -1604,7 +1604,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -1776,7 +1776,7 @@ checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -1858,7 +1858,7 @@ checksum = "eecf8589574ce9b895052fa12d69af7a233f99e6107f5cb8dd1044f2a17bfdcb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -1870,7 +1870,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -2008,7 +2008,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.57", + "syn 2.0.58", "toml 0.8.2", ] @@ -2183,7 +2183,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -3117,7 +3117,7 @@ checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -3509,7 +3509,7 @@ checksum = "cfb77679af88f8b125209d354a202862602672222e7f2313fdd6dc349bad4712" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -3591,7 +3591,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -3603,7 +3603,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -3665,7 +3665,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -3835,7 +3835,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -3995,7 +3995,7 @@ checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -4645,7 +4645,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -4729,7 +4729,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -4741,7 +4741,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -5342,7 +5342,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -5811,7 +5811,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -6130,7 +6130,7 @@ checksum = "fadbefec4f3c678215ca72bd71862697bb06b41fd77c0088902dd3203354387b" dependencies = [ "quote", "spl-discriminator-syn", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -6142,7 +6142,7 @@ dependencies = [ "proc-macro2", "quote", "sha2 0.10.8", - "syn 2.0.57", + "syn 2.0.58", "thiserror", ] @@ -6190,7 +6190,7 @@ dependencies = [ "proc-macro2", "quote", "sha2 0.10.8", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -6358,7 +6358,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -6386,9 +6386,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.57" +version = "2.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11a6ae1e52eb25aab8f3fb9fca13be982a373b8f1157ca14b897a825ba4a2d35" +checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" dependencies = [ "proc-macro2", "quote", @@ -6477,7 +6477,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -6594,7 +6594,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -6772,7 +6772,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -7069,7 +7069,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", "wasm-bindgen-shared", ] @@ -7103,7 +7103,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -7545,7 +7545,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] @@ -7565,7 +7565,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.57", + "syn 2.0.58", ] [[package]] From 2236f96675590ce613aebcab1c51437f6b179580 Mon Sep 17 00:00:00 2001 From: Kristina Nikolaeva <112946046+kristinaNikolaevaa@users.noreply.github.com> Date: Fri, 5 Apr 2024 12:24:30 +0200 Subject: [PATCH 164/318] publish image with branch tag before tests (#381) --- .github/workflows/deploy.py | 48 ++++++++++++++++++---------------- .github/workflows/pipeline.yml | 7 +++-- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index 25ec2b212..cfa727f2d 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -65,38 +65,40 @@ def build_docker_image(github_sha): @cli.command(name="publish_image") @click.option('--github_sha') -def publish_image(github_sha): - docker_client.login(username=DOCKER_USER, password=DOCKER_PASSWORD) - out = docker_client.push(f"{IMAGE_NAME}:{github_sha}", decode=True, stream=True) - process_output(out) +@click.option('--github_ref_name') +@click.option('--head_ref') +def publish_image(github_sha, github_ref_name, head_ref): + push_image_with_tag(github_sha, github_sha) + branch_name_tag = "" + if head_ref: + branch_name_tag = head_ref.split('/')[-1] + elif re.match(VERSION_BRANCH_TEMPLATE, github_ref_name): + branch_name_tag = github_ref_name + if branch_name_tag: + push_image_with_tag(github_sha, branch_name_tag) @cli.command(name="finalize_image") -@click.option('--head_ref_branch') @click.option('--github_ref') @click.option('--github_sha') -def finalize_image(head_ref_branch, github_ref, github_sha): - branch = github_ref.replace("refs/heads/", "") - if re.match(VERSION_BRANCH_TEMPLATE, branch) is None: - if 'refs/tags/' in branch: - tag = branch.replace("refs/tags/", "") - elif branch == 'master': - tag = 'stable' - elif branch == 'develop': - tag = 'latest' - else: - tag = head_ref_branch.split('/')[-1] - - docker_client.login(username=DOCKER_USER, password=DOCKER_PASSWORD) +def finalize_image(github_ref, github_sha): + tag = None + if 'refs/tags/' in github_ref: + tag = github_ref.replace("refs/tags/", "") + elif github_ref == 'refs/heads/develop': + tag = 'latest' + if tag: out = docker_client.pull(f"{IMAGE_NAME}:{github_sha}", decode=True, stream=True) process_output(out) - - docker_client.tag(f"{IMAGE_NAME}:{github_sha}", f"{IMAGE_NAME}:{tag}") - out = docker_client.push(f"{IMAGE_NAME}:{tag}", decode=True, stream=True) - process_output(out) + push_image_with_tag(github_sha, tag) else: - click.echo("The image is not published, please create tag for publishing") + click.echo("The image is not published") +def push_image_with_tag(sha, tag): + docker_client.login(username=DOCKER_USER, password=DOCKER_PASSWORD) + docker_client.tag(f"{IMAGE_NAME}:{sha}", f"{IMAGE_NAME}:{tag}") + out = docker_client.push(f"{IMAGE_NAME}:{tag}", decode=True, stream=True) + process_output(out) def run_subprocess(command): click.echo(f"run command: {command}") diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index ad3fe313c..51f4ef0fe 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -30,16 +30,16 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 - - name: build docker image run: | python3 ./.github/workflows/deploy.py build_docker_image \ --github_sha=${GITHUB_SHA} - - name: publish image run: | python3 ./.github/workflows/deploy.py publish_image \ - --github_sha=${GITHUB_SHA} + --github_sha=${GITHUB_SHA} \ + --head_ref=${{ github.head_ref }} \ + --github_ref_name=${{github.ref_name}} run-neon-evm-tests: runs-on: test-runner needs: @@ -114,7 +114,6 @@ jobs: - name: Finalize image run: | python3 ./.github/workflows/deploy.py finalize_image \ - --head_ref_branch=${{ github.head_ref }} \ --github_ref=${GITHUB_REF} \ --github_sha=${GITHUB_SHA} - name: Check if it version branch From 4ace853eba7f6ec3ae0a2e8d4f81605c7bb50c58 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Apr 2024 12:25:21 +0200 Subject: [PATCH 165/318] Bump h2 from 0.3.24 to 0.3.26 in /evm_loader (#382) Bumps [h2](https://github.com/hyperium/h2) from 0.3.24 to 0.3.26. - [Release notes](https://github.com/hyperium/h2/releases) - [Changelog](https://github.com/hyperium/h2/blob/v0.3.26/CHANGELOG.md) - [Commits](https://github.com/hyperium/h2/compare/v0.3.24...v0.3.26) --- updated-dependencies: - dependency-name: h2 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index e651cf723..b06137585 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -2336,9 +2336,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.24" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" dependencies = [ "bytes", "fnv", From 48a788d40ab814f76a01b746e78ae17bcfea55be Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Apr 2024 09:01:34 +0200 Subject: [PATCH 166/318] Bump anyhow from 1.0.81 to 1.0.82 in /evm_loader (#389) Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.81 to 1.0.82. - [Release notes](https://github.com/dtolnay/anyhow/releases) - [Commits](https://github.com/dtolnay/anyhow/compare/1.0.81...1.0.82) --- updated-dependencies: - dependency-name: anyhow dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index b06137585..238e3393d 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -381,9 +381,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.81" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" +checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" [[package]] name = "ark-bn254" From 81ee7f9c17b5fb929e04c2b9d994db55886e31c9 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Mon, 15 Apr 2024 09:55:39 +0200 Subject: [PATCH 167/318] NDEV-2875: Update Solana to v1.17.31 (#390) --- .github/workflows/deploy.py | 8 +- evm_loader/Cargo.lock | 193 ++++++++++++++++++------------------ evm_loader/Cargo.toml | 18 ++-- 3 files changed, 111 insertions(+), 108 deletions(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index cfa727f2d..7a2c26d79 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -32,8 +32,8 @@ IMAGE_NAME = os.environ.get("IMAGE_NAME") RUN_LINK_REPO = os.environ.get("RUN_LINK_REPO") DOCKERHUB_ORG_NAME = os.environ.get("DOCKERHUB_ORG_NAME") -SOLANA_NODE_VERSION = 'v1.17.28' -SOLANA_BPF_VERSION = 'v1.17.28' +SOLANA_NODE_VERSION = 'v1.17.31' +SOLANA_BPF_VERSION = 'v1.17.31' VERSION_BRANCH_TEMPLATE = r"[vt]{1}\d{1,2}\.\d{1,2}\.x.*" docker_client = docker.APIClient() @@ -72,7 +72,7 @@ def publish_image(github_sha, github_ref_name, head_ref): branch_name_tag = "" if head_ref: branch_name_tag = head_ref.split('/')[-1] - elif re.match(VERSION_BRANCH_TEMPLATE, github_ref_name): + elif re.match(VERSION_BRANCH_TEMPLATE, github_ref_name): branch_name_tag = github_ref_name if branch_name_tag: push_image_with_tag(github_sha, branch_name_tag) @@ -94,12 +94,14 @@ def finalize_image(github_ref, github_sha): else: click.echo("The image is not published") + def push_image_with_tag(sha, tag): docker_client.login(username=DOCKER_USER, password=DOCKER_PASSWORD) docker_client.tag(f"{IMAGE_NAME}:{sha}", f"{IMAGE_NAME}:{tag}") out = docker_client.push(f"{IMAGE_NAME}:{tag}", decode=True, stream=True) process_output(out) + def run_subprocess(command): click.echo(f"run command: {command}") subprocess.run(command, shell=True) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 238e3393d..7a12f7276 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -4884,9 +4884,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.10.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" @@ -4925,9 +4925,9 @@ dependencies = [ [[package]] name = "solana-account-decoder" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d76c43ef61f527d719b5c6bfa5a62ebba60839739125da9e8a00fb82349afd2" +checksum = "c4e29f060cabd0e1bd90a63f8e1517ddd3365d3dc2eaa05f9a9fa542f4adeaaa" dependencies = [ "Inflector", "base64 0.21.7", @@ -4950,9 +4950,9 @@ dependencies = [ [[package]] name = "solana-accounts-db" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36d5bd37de55b19efecc842f48f465edc588b107acf0c9f94d79b1182147e299" +checksum = "39e32ca00e7785d0fde702aa6c9fa749d33d1c275980baee85de0543357cae28" dependencies = [ "arrayref", "bincode", @@ -5009,9 +5009,9 @@ dependencies = [ [[package]] name = "solana-address-lookup-table-program" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d143225217baaf524eac490475802eb095a563833735a4dc0f1e84d5f57e03" +checksum = "71a93d1c1a0c13de20e13a0c9bd7275b00bb901b8b7c55424fea98f71cb37778" dependencies = [ "bincode", "bytemuck", @@ -5030,9 +5030,9 @@ dependencies = [ [[package]] name = "solana-bpf-loader-program" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ce801a3dc8a060446a0d4545e882f07635ef1ff57503917c7d3a8769dc5fed6" +checksum = "6a396f4190c9bc81ec2d697673a571d7f064634916105fdf9efecb6fa5bec818" dependencies = [ "bincode", "byteorder", @@ -5049,9 +5049,9 @@ dependencies = [ [[package]] name = "solana-bucket-map" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2977fbe89d8edd3f15ec06bd8d4d518017456ee2a8636972e5eb4b2b0a5e76e5" +checksum = "b4efb7bc86741650dc2a942d23e7e714d41bbc46eff5555784ec87ee7a591615" dependencies = [ "bv", "bytemuck", @@ -5067,9 +5067,9 @@ dependencies = [ [[package]] name = "solana-clap-utils" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb19b9bbd92eee2d8f637026559a9fb48bd98aba534caedf070498a50c91fce8" +checksum = "62e5cdc0ae0c8ae79c39a4a362066d0d61764bc7ea7e033961fd7510fd24da2a" dependencies = [ "chrono", "clap 2.34.0", @@ -5084,9 +5084,9 @@ dependencies = [ [[package]] name = "solana-cli" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72783963ea5eb41c67ba730e6dc9511a9747bb0286d476aa0e184f97a483b834" +checksum = "599b8cac742270ddc097458623d9688b3ad03e6adb19987e993f47ec51b330eb" dependencies = [ "bincode", "bs58 0.4.0", @@ -5135,9 +5135,9 @@ dependencies = [ [[package]] name = "solana-cli-config" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677c2b5da3a4788e2eb04c35f947c2f23754244177ae24db38344675c67ca825" +checksum = "e6de25e2f3e00901ffbe09e625303fdda62baaa584992027bdc92fc3fca04e1a" dependencies = [ "dirs-next", "lazy_static", @@ -5151,9 +5151,9 @@ dependencies = [ [[package]] name = "solana-cli-output" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddbf06ae70f42263d7ee251f0481e150300c08678a08ae8a2c6ad02f2a80d3ae" +checksum = "f30b3aca5a25e1ca04b5b1107bcdc26fcc69d167df0f617dbca5967df62e0d42" dependencies = [ "Inflector", "base64 0.21.7", @@ -5178,9 +5178,9 @@ dependencies = [ [[package]] name = "solana-client" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9538e3db584a8b1e70060f1f24222b8e0429f18b607f531fb45eb826f4917265" +checksum = "a1e2301c2af7e5a1dba0855f710329a2bb993829ed9fdf8f6207d02ee6fc54a4" dependencies = [ "async-trait", "bincode", @@ -5211,9 +5211,9 @@ dependencies = [ [[package]] name = "solana-compute-budget-program" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afbb8cfc7f4448db4c766e97b9175f96b73f947df8cf27dbbad8f1b9d40d9069" +checksum = "773ae3c4d99f9ed06d9dc5c6541df1db16bc42d77f91c46b9c9b117fc5e129b3" dependencies = [ "solana-program-runtime", "solana-sdk", @@ -5221,9 +5221,9 @@ dependencies = [ [[package]] name = "solana-config-program" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3afd4e309d304e296765cab716fb1fd66c66ec300465c8b26f8cce763275132" +checksum = "595118948b966b110aad3f9d8d8464958abe379ecfa7a813b4fc82659c8259bc" dependencies = [ "bincode", "chrono", @@ -5235,9 +5235,9 @@ dependencies = [ [[package]] name = "solana-connection-cache" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92716758e8c0e1c0bc2a5ac2eb3df443a0337fd3991cd38a3b02b12c3fbd18ce" +checksum = "d363d6bb43e618b6010b47c2eb0579777ce4ed388ca15b84a610a738edf0b97e" dependencies = [ "async-trait", "bincode", @@ -5257,9 +5257,9 @@ dependencies = [ [[package]] name = "solana-cost-model" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab342bd6a42e6c2fa21fe1d72801fbd98858eef44b1b8c1ecdf54f82c58dd496" +checksum = "8f1e8673cd74543895f310eb2dfd497c7ffc970a799923bd0f8fd6e0320e14ab" dependencies = [ "lazy_static", "log", @@ -5281,9 +5281,9 @@ dependencies = [ [[package]] name = "solana-faucet" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e001d384576317028fd682943ae9321eadd25a17c50e59d71f387e67c6a22266" +checksum = "2ad19317b6d6302967fe8946a27eb95ba9df67167a7ddf5f538ede312d899471" dependencies = [ "bincode", "byteorder", @@ -5305,9 +5305,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb1b8230474ae9f7c841060c299999124582e8d2a0448d7847720792e98cc64e" +checksum = "96734b05823c8b515f8e3cc02641a27aee2c9760b1a43c74cb20f2a1ab0ab76c" dependencies = [ "ahash 0.8.5", "blake3", @@ -5335,9 +5335,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi-macro" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793910ab733b113b80c357f8f492dda2fabd5671c4ea03db3aa4e46b938fdbe3" +checksum = "9a0f1291a464fd046135d019d57a81be165ee3d23aa7df880b47dac683a0582a" dependencies = [ "proc-macro2", "quote", @@ -5347,9 +5347,9 @@ dependencies = [ [[package]] name = "solana-loader-v4-program" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99507b87522b861b164673a127c5a291c2837ecf04b7466a3b5201053c1c267a" +checksum = "09a437265099d9782e1f95eee2feb3b9b4f0247a177d0c0646148da738ae3b1f" dependencies = [ "log", "solana-measure", @@ -5360,9 +5360,9 @@ dependencies = [ [[package]] name = "solana-logger" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d3f819af39632dc538a566c937253bf46256e4c0e60f621c6db448bc7c76294" +checksum = "c5977c8f24b83cf50e7139ffdb25d70bad6a177f18ccc79ca2293d6a987fa81c" dependencies = [ "env_logger", "lazy_static", @@ -5371,9 +5371,9 @@ dependencies = [ [[package]] name = "solana-measure" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb045f0235b16f7d926f6e0338db822747d61559a1368c3cb017ba6e02c516d0" +checksum = "7a39ef01b2c65552d05013b2642ffd73258f2c80e3a59e44c499762047df9456" dependencies = [ "log", "solana-sdk", @@ -5381,9 +5381,9 @@ dependencies = [ [[package]] name = "solana-metrics" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1af84362ad5804dc64ca88b1ca5c35bd41321e12d42c798ac06a6fbb60dd0e70" +checksum = "9ad30ff3775412f2929d440446aef8b070676920bc5df495ea6398a8f28ce91f" dependencies = [ "crossbeam-channel", "gethostname", @@ -5396,9 +5396,9 @@ dependencies = [ [[package]] name = "solana-net-utils" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8e640a95d317cad1322015c5a2b6a71697fd8dabebcb8dd33ed7f5a22869d12" +checksum = "6eafd5178a38a039e12c14780f1b6a74f1e672d62357343e0aee6d0fc7e5bd18" dependencies = [ "bincode", "clap 3.2.23", @@ -5418,9 +5418,9 @@ dependencies = [ [[package]] name = "solana-perf" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4266c4bd46620a925b8d508c26578d5559e97fcff6735fd22e39f369c3996ee1" +checksum = "10d6293cddcc98ae092d00f43f741405da30aa083acb96666606130810b064f3" dependencies = [ "ahash 0.8.5", "bincode", @@ -5447,9 +5447,9 @@ dependencies = [ [[package]] name = "solana-program" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581f38a870bffbe623d900c68579984671f8dfa35bbfb3309d7134de22ce8652" +checksum = "6412447793f8a3ef7526655906728325093b472e481791ac5c584e8d272166dc" dependencies = [ "ark-bn254", "ark-ec", @@ -5501,9 +5501,9 @@ dependencies = [ [[package]] name = "solana-program-runtime" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490b6f65aced077e0c5e57c20f151a134458fc350905c20d7dcf3f2162eaa6f6" +checksum = "1977e741a6793fca27413507457d797df0f41bc0ae634247d112bc77ab2b0325" dependencies = [ "base64 0.21.7", "bincode", @@ -5529,9 +5529,9 @@ dependencies = [ [[package]] name = "solana-pubsub-client" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0dc2b26a7a9860f180ce11f69b0ff2a8bea0d4b9e97daee741b1e76565b3c82" +checksum = "1ad21dd5d6fe09116dbc29aec279b7cf08d250b564899dc87437bd780ed26290" dependencies = [ "crossbeam-channel", "futures-util", @@ -5554,9 +5554,9 @@ dependencies = [ [[package]] name = "solana-quic-client" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727474945d51be37ffe03e7b1d6c9630da41228c7b298a8f45098c203a78ac89" +checksum = "6201869768fe133ce9b8088e4f718f53ff164b8e5df3d0d46a6563a22545924f" dependencies = [ "async-mutex", "async-trait", @@ -5581,9 +5581,9 @@ dependencies = [ [[package]] name = "solana-rayon-threadlimit" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "853794cccf3bd1984419a594040dfed19666e5a9ad33b0906d4174bc394b22af" +checksum = "1f100d0c3214d67bb847a1eefc7079f6bb755534266423f4c994ad3b40c685ed" dependencies = [ "lazy_static", "num_cpus", @@ -5591,9 +5591,9 @@ dependencies = [ [[package]] name = "solana-remote-wallet" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b368f270526a5f92ec47c45a6b74ac304b62b08c169b45cf91e0d2f1703889bd" +checksum = "3328c891079086b408a04e701470a346d517c9c51c0a96f2f166f616a3e1c3c8" dependencies = [ "console", "dialoguer", @@ -5611,9 +5611,9 @@ dependencies = [ [[package]] name = "solana-rpc-client" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71b766876b0c56950ab530d8495ef7eeaeb79e162f03dadaffc0d6852de9e844" +checksum = "bfacf1163a375d98c29779a03ba278b2ef43494f77e33826a33f9460563c0887" dependencies = [ "async-trait", "base64 0.21.7", @@ -5637,9 +5637,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-api" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876b2e410cc2403ea3216893f05034b02a180431100eb831d0b67b14fca4d29f" +checksum = "7fab293a88113511e66607d76bd027edfe0b1372b467fd76bbb5af03448539a2" dependencies = [ "base64 0.21.7", "bs58 0.4.0", @@ -5659,9 +5659,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-nonce-utils" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebdb3f02fb3cce3c967f718bc77b79433c24aa801b63dc70f374e8759b2424e4" +checksum = "1e43cb51374a6ec8fd401b3387334ef93e04f6d8ae87bbb29892aff42aeb1061" dependencies = [ "clap 2.34.0", "solana-clap-utils", @@ -5672,9 +5672,9 @@ dependencies = [ [[package]] name = "solana-runtime" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35b7851486b7b3deb2a6efee81cd1466b77beff914cb5cc93940d9f7f0430b7d" +checksum = "6c00486a8cc4fd4beddc5e22fdb1836c38a1280b6c708329bcfdfc61be39e377" dependencies = [ "arrayref", "base64 0.21.7", @@ -5749,9 +5749,9 @@ dependencies = [ [[package]] name = "solana-sdk" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d70ab837cc79ed67df6fdb145f1ffd544f1eaa60b0757b750f4864b90498bad" +checksum = "de1ce8848de4198f9bc7e4574252be02b1ed86ecbc2fff506780d5f8d6e4c4a8" dependencies = [ "assert_matches", "base64 0.21.7", @@ -5803,9 +5803,9 @@ dependencies = [ [[package]] name = "solana-sdk-macro" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f9d0433c4084a3260a32ec67f6b4272c4232d15e732be542cd5dfdf0ae1e784" +checksum = "bc5cc46bbda0a5472d8d0a4c846b22941436ac45c31456d3e885a387a5f264f7" dependencies = [ "bs58 0.4.0", "proc-macro2", @@ -5822,9 +5822,9 @@ checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" [[package]] name = "solana-stake-program" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c695b516f57e0291cdb18e994c22d9478e7f49be631782c352327ba5bee46a88" +checksum = "a9d94e05db9762c5fc6114e788570c4645dbe7e7ea5da2e39269128944b3a200" dependencies = [ "bincode", "log", @@ -5837,9 +5837,9 @@ dependencies = [ [[package]] name = "solana-streamer" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d70eda40efb5bc57ad50b1ac8452485065c1adae0e701a0348b397db054e2ab5" +checksum = "46f02b475fc20c55ebbcfa5638ff93f9b780414cc6185e3a6d0992bca0ae81ee" dependencies = [ "async-channel", "bytes", @@ -5859,6 +5859,7 @@ dependencies = [ "rand 0.8.5", "rcgen", "rustls", + "smallvec", "solana-metrics", "solana-perf", "solana-sdk", @@ -5869,9 +5870,9 @@ dependencies = [ [[package]] name = "solana-system-program" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f0b104dc8b94642988324a291c70f1c728be2276761e5523da1b4aa940b0f7a" +checksum = "7eec04b67da2f353fe18dcf7e8bcdd6d8ddcece8598de55a6a7671fd01e9188f" dependencies = [ "bincode", "log", @@ -5883,9 +5884,9 @@ dependencies = [ [[package]] name = "solana-thin-client" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3c510144695c3d1ee1f84dd9975af7f7d35c168447c484bbd35c21e903c515" +checksum = "9b6ce2304764b8bb699db734fde9cd19ace038d3895d828a557ea0ec2a9e0ecd" dependencies = [ "bincode", "log", @@ -5898,9 +5899,9 @@ dependencies = [ [[package]] name = "solana-tpu-client" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44f27c8fec609179a7dfc287060df2a926c8cd89329235c4b8d78bd019a72462" +checksum = "aa3e2351625e26f55e5e08f8e5aadaa2380fd0649f25641d6ba3f3848dbe5c9a" dependencies = [ "async-trait", "bincode", @@ -5922,9 +5923,9 @@ dependencies = [ [[package]] name = "solana-transaction-status" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29f58f2f864d900eddf2e21a99ebe445b6be525d597e44952f075d8237035b8e" +checksum = "0841bbd1845c87043e4184961e45cc7c08b36d96d0d146256b26ea5c74630a0f" dependencies = [ "Inflector", "base64 0.21.7", @@ -5947,9 +5948,9 @@ dependencies = [ [[package]] name = "solana-udp-client" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27ead118c5d549e4345dc59cbc5d9b282164f3e5334707f186e3aa10d40e3b30" +checksum = "bae54a100f0b0b5be065f5d05f2259f6d4a7b39f5866d579927f3ca35a01773b" dependencies = [ "async-trait", "solana-connection-cache", @@ -5962,9 +5963,9 @@ dependencies = [ [[package]] name = "solana-version" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532f5d631562587facc5fe88abd2e31c0d1f29012b6766c664db9f05a39fb05b" +checksum = "5f69945e38d7440221e2fac0aaa57a9d72adb329b0de705ca5bd9ba981aedc16" dependencies = [ "log", "rustc_version", @@ -5978,9 +5979,9 @@ dependencies = [ [[package]] name = "solana-vote" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94ee806a47c6b1a3790e7d49f57a2037e631fee6b83e608e3315fdfc485c5826" +checksum = "de0122b117497cac299cd52bbfcb9f3732d882833f5c87ee87d2d3541ba77057" dependencies = [ "crossbeam-channel", "itertools 0.10.5", @@ -5997,9 +5998,9 @@ dependencies = [ [[package]] name = "solana-vote-program" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c684430058b0a2e733936a8851c8843a3a6316ccd5c969d39411a479d6489642" +checksum = "e574aafc3c5adc7106ab4605d8ad378c9a12f2cf1dec2e8ba1aa6fd97a5d5490" dependencies = [ "bincode", "log", @@ -6019,9 +6020,9 @@ dependencies = [ [[package]] name = "solana-zk-token-proof-program" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b04ec720b6cf2d852f7aac4153e1f2b9eb4b88e7d6653a169989b2e4bcbd050" +checksum = "de791a3bb992976029ead33017d4d994614b10d3028c7598632019fdb432dcad" dependencies = [ "bytemuck", "num-derive 0.3.3", @@ -6033,9 +6034,9 @@ dependencies = [ [[package]] name = "solana-zk-token-sdk" -version = "1.17.28" +version = "1.17.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aef1b48d9fdb2619349d2d15942d83c99aabe995ff945d9b418176373aa823c" +checksum = "597dddc8ab46852dea7fc3d22e031fa4ffdb1b2291ac24d960605424a510a5f5" dependencies = [ "aes-gcm-siv", "base64 0.21.7", diff --git a/evm_loader/Cargo.toml b/evm_loader/Cargo.toml index ec864e037..26f1fa50b 100644 --- a/evm_loader/Cargo.toml +++ b/evm_loader/Cargo.toml @@ -12,12 +12,12 @@ members = [ ] [workspace.dependencies] -solana-clap-utils = "=1.17.28" -solana-cli = "=1.17.28" -solana-cli-config = "=1.17.28" -solana-client = "=1.17.28" -solana-program = { version = "=1.17.28", default-features = false } -solana-sdk = "=1.17.28" -solana-program-runtime = "=1.17.28" -solana-runtime = "=1.17.28" -solana-accounts-db = "=1.17.28" \ No newline at end of file +solana-clap-utils = "=1.17.31" +solana-cli = "=1.17.31" +solana-cli-config = "=1.17.31" +solana-client = "=1.17.31" +solana-program = { version = "=1.17.31", default-features = false } +solana-sdk = "=1.17.31" +solana-program-runtime = "=1.17.31" +solana-runtime = "=1.17.31" +solana-accounts-db = "=1.17.31" From ad7034f411c6c6e32d2f9a9658ec90d38af7766e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Apr 2024 12:00:48 +0200 Subject: [PATCH 168/318] Bump proc-macro2 from 1.0.79 to 1.0.80 in /evm_loader (#391) Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.79 to 1.0.80. - [Release notes](https://github.com/dtolnay/proc-macro2/releases) - [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.79...1.0.80) --- updated-dependencies: - dependency-name: proc-macro2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 7a12f7276..46a129378 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -3971,9 +3971,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "a56dea16b0a29e94408b9aa5e2940a4eedbd128a1ba20e8f7ae60fd3d465af0e" dependencies = [ "unicode-ident", ] From 7e8c352c9f45200f36a86ef9a8363644ab096623 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Apr 2024 11:37:41 +0300 Subject: [PATCH 169/318] Bump quote from 1.0.35 to 1.0.36 in /evm_loader (#392) Bumps [quote](https://github.com/dtolnay/quote) from 1.0.35 to 1.0.36. - [Release notes](https://github.com/dtolnay/quote/releases) - [Commits](https://github.com/dtolnay/quote/compare/1.0.35...1.0.36) --- updated-dependencies: - dependency-name: quote dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 46a129378..b7bf28dd6 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -4048,9 +4048,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] From 11f8493252108242d51eb3eb570c45900a445b9b Mon Sep 17 00:00:00 2001 From: s-medvedev <40623263+s-medvedev@users.noreply.github.com> Date: Thu, 18 Apr 2024 20:54:32 +0700 Subject: [PATCH 170/318] NDEV-1837 Composability for develop (#377) * NDEV-1837 Move composability to develop branch * NDEV-1837 Support SolanaSimulator for execute external calls * Fix external calls * Some fixes * Fix `execute_external_instruction` * Small code improvements * Fix the detection of SolanaCall mode * NDEV-2806 Overrides solana accounts for emulation (#387) Implement overrides Solana accounts for emulation * NDEV-1837 Fix calculating rent for upgrade legacy accounts * NDEV-1837 Added lamports estimation required to store an account with revision * NDEV-2837 Show error message from call before revert * NDEV-1837 Update call_solana.sol * NDEV-1837 Review fixes --------- Co-authored-by: Semen Medvedev --- evm_loader/Cargo.lock | 24 + evm_loader/lib/Cargo.toml | 4 + evm_loader/lib/src/account_data.rs | 187 + evm_loader/lib/src/account_storage.rs | 3070 ++++++++++++++--- evm_loader/lib/src/commands/emulate.rs | 137 +- evm_loader/lib/src/commands/get_storage_at.rs | 2 +- evm_loader/lib/src/lib.rs | 1 + evm_loader/lib/src/solana_emulator.rs | 439 +++ evm_loader/lib/src/solana_simulator/mod.rs | 8 + evm_loader/lib/src/types/mod.rs | 81 +- evm_loader/program/Cargo.toml | 2 + .../program/src/account/ether_balance.rs | 16 +- .../program/src/account/ether_contract.rs | 29 +- .../program/src/account/ether_storage.rs | 20 +- evm_loader/program/src/account/legacy/mod.rs | 2 +- .../program/src/account_storage/apply.rs | 10 +- .../program/src/account_storage/backend.rs | 4 + .../program/src/account_storage/base.rs | 3 + evm_loader/program/src/account_storage/mod.rs | 40 +- .../program/src/account_storage/synced.rs | 167 + evm_loader/program/src/entrypoint.rs | 14 + evm_loader/program/src/error.rs | 12 + evm_loader/program/src/evm/database.rs | 29 +- evm_loader/program/src/evm/mod.rs | 2 +- evm_loader/program/src/evm/opcode.rs | 16 +- evm_loader/program/src/executor/action.rs | 3 +- evm_loader/program/src/executor/mod.rs | 2 + .../precompile_extension/call_solana.rs | 478 +++ .../executor/precompile_extension/metaplex.rs | 481 +-- .../src/executor/precompile_extension/mod.rs | 69 +- .../precompile_extension/neon_token.rs | 211 +- .../precompile_extension/query_account.rs | 326 +- .../precompile_extension/spl_token.rs | 1319 +++---- evm_loader/program/src/executor/state.rs | 232 +- .../program/src/executor/synced_state.rs | 295 ++ evm_loader/program/src/instruction/mod.rs | 30 + .../src/instruction/transaction_execute.rs | 52 +- ...action_execute_from_account_solana_call.rs | 50 + ...on_execute_from_instruction_solana_call.rs | 45 + solidity/call_solana.sol | 181 + solidity/call_solana_test.sol | 236 ++ 41 files changed, 6559 insertions(+), 1770 deletions(-) create mode 100644 evm_loader/lib/src/account_data.rs create mode 100644 evm_loader/lib/src/solana_emulator.rs create mode 100644 evm_loader/program/src/account_storage/synced.rs create mode 100644 evm_loader/program/src/executor/precompile_extension/call_solana.rs create mode 100644 evm_loader/program/src/executor/synced_state.rs create mode 100644 evm_loader/program/src/instruction/transaction_execute_from_account_solana_call.rs create mode 100644 evm_loader/program/src/instruction/transaction_execute_from_instruction_solana_call.rs create mode 100644 solidity/call_solana.sol create mode 100644 solidity/call_solana_test.sol diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index b7bf28dd6..6871d2fe9 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -1826,6 +1826,15 @@ version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +[[package]] +name = "elsa" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98e71ae4df57d214182a2e5cb90230c0192c6ddfcaa05c36453d46a54713e10" +dependencies = [ + "stable_deref_trait", +] + [[package]] name = "encode_unicode" version = "0.3.6" @@ -1992,6 +2001,7 @@ dependencies = [ "serde_bytes", "serde_json", "solana-program", + "solana-sdk", "spl-associated-token-account", "spl-token", "static_assertions", @@ -2458,6 +2468,12 @@ dependencies = [ "serde", ] +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + [[package]] name = "hidapi" version = "2.4.1" @@ -3321,11 +3337,13 @@ dependencies = [ "build-info-build", "clap 2.34.0", "clickhouse", + "elsa", "enum_dispatch", "ethnum", "evm-loader", "goblin 0.6.1", "hex", + "hex-literal", "lazy_static", "log", "neon-lib-interface", @@ -6303,6 +6321,12 @@ dependencies = [ "spl-program-error", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "static_assertions" version = "1.1.0" diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index c012e7334..47fe11e71 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -44,8 +44,12 @@ strum = "0.26.2" strum_macros = "0.26.2" clap = "2.33.3" lazy_static = "1.4.0" +elsa = "1.10.0" arrayref = "0.3.6" +[dev-dependencies] +hex-literal = "0.4.1" + [build-dependencies] build-info-build = "0.0.31" diff --git a/evm_loader/lib/src/account_data.rs b/evm_loader/lib/src/account_data.rs new file mode 100644 index 000000000..515c1e70e --- /dev/null +++ b/evm_loader/lib/src/account_data.rs @@ -0,0 +1,187 @@ +pub use evm_loader::account_storage::{AccountStorage, SyncedAccountStorage}; +// use solana_sdk::account::{ReadableAccount, WritableAccount}; +use solana_sdk::system_program; +// use solana_sdk::clock::Epoch; +use solana_sdk::{ + account::{Account, ReadableAccount}, + account_info::AccountInfo, + pubkey::Pubkey, +}; + +#[derive(Clone, Debug)] +#[repr(C)] +pub struct AccountData { + original_length: u32, + pub pubkey: Pubkey, + pub lamports: u64, + data: Vec, + pub owner: Pubkey, + pub executable: bool, + pub rent_epoch: u64, +} + +use solana_sdk::account_info::IntoAccountInfo; +use solana_sdk::entrypoint::MAX_PERMITTED_DATA_INCREASE; + +impl AccountData { + pub fn new(pubkey: Pubkey) -> Self { + Self { + original_length: 0, + pubkey, + lamports: 0, + data: vec![0u8; 8 + MAX_PERMITTED_DATA_INCREASE], + owner: system_program::ID, + executable: false, + rent_epoch: 0, + } + } + + pub fn is_empty(&self) -> bool { + self.get_length() == 0 && self.owner == system_program::ID + } + + pub fn is_busy(&self) -> bool { + self.get_length() != 0 || self.owner != system_program::ID + } + + pub fn new_from_account(pubkey: Pubkey, account: &T) -> Self { + let account_data = account.data(); + let mut data = vec![0u8; account_data.len() + 8 + MAX_PERMITTED_DATA_INCREASE]; + let ptr_length = data.as_mut_ptr() as *mut _ as *mut u64; + unsafe { *ptr_length = account_data.len() as u64 }; + data[8..8 + account_data.len()].copy_from_slice(account_data); + + Self { + original_length: account_data.len() as u32, + pubkey, + lamports: account.lamports(), + data, + owner: *account.owner(), + executable: account.executable(), + rent_epoch: account.rent_epoch(), + } + } + + pub fn expand(&mut self, length: usize) { + if self.original_length < length as u32 { + self.data + .resize(length + 8 + MAX_PERMITTED_DATA_INCREASE, 0); + self.original_length = length as u32; + } + let ptr_length = self.data.as_mut_ptr() as *mut _ as *mut u64; + unsafe { + if *ptr_length < length as u64 { + *ptr_length = length as u64; + } + } + } + + pub fn reserve(&mut self) { + self.expand(self.get_length()) + } + + pub fn assign(&mut self, owner: Pubkey) -> evm_loader::error::Result<()> { + if self.owner != system_program::ID { + return Err(evm_loader::error::Error::AccountAlreadyInitialized( + self.pubkey, + )); + } + self.owner = owner; + Ok(()) + } + + pub fn data(&self) -> &[u8] { + let length = self.get_length(); + &self.data[8..8 + length] + } + + pub fn data_mut(&mut self) -> &mut [u8] { + let length = self.get_length(); + &mut self.data[8..8 + length] + } + + pub fn get_length(&self) -> usize { + let ptr_length = self.data.as_ptr() as *const _ as *const u64; + (unsafe { *ptr_length }) as usize + } + + fn get(&mut self) -> (&Pubkey, &mut u64, &mut [u8], &Pubkey, bool, u64) { + let length = self.get_length(); + ( + &self.pubkey, + &mut self.lamports, + &mut self.data[8..8 + length], + &self.owner, + self.executable, + self.rent_epoch, + ) + } +} + +impl<'a> IntoAccountInfo<'a> for &'a mut AccountData { + fn into_account_info(self) -> AccountInfo<'a> { + let (pubkey, lamports, data, owner, executable, rent_epoch) = self.get(); + + AccountInfo::new( + pubkey, false, false, lamports, data, owner, executable, rent_epoch, + ) + } +} + +impl<'a> From<&'a AccountData> for Account { + fn from(val: &'a AccountData) -> Self { + Account { + lamports: val.lamports, + data: val.data().to_vec(), + owner: val.owner, + executable: val.executable, + rent_epoch: val.rent_epoch, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::str::FromStr; + + #[tokio::test] + async fn test_account_data() { + let mut account_data = AccountData::new(Pubkey::default()); + let new_owner = Pubkey::from_str("53DfF883gyixYNXnM7s5xhdeyV8mVk9T4i2hGV9vG9io").unwrap(); + let new_size: usize = 10 * 1024; + + { + let account_info = (&mut account_data).into_account_info(); + assert_eq!(account_info.try_data_len().unwrap(), 0); + account_info.realloc(new_size - 1, false).unwrap(); + account_info.assign(&new_owner); + } + + assert_eq!(account_data.get_length(), new_size - 1); + + { + let account_info = (&mut account_data).into_account_info(); + assert_eq!(account_info.try_data_len().unwrap(), new_size - 1); + assert_eq!(account_info.realloc(new_size, false), Ok(())); + assert_eq!( + account_info.realloc(new_size + 1, false), + Err(solana_sdk::program_error::ProgramError::InvalidRealloc) + ); + let mut lamports = account_info.try_borrow_mut_lamports().unwrap(); + **lamports = 10000; + } + + assert_eq!(account_data.get_length(), new_size); + assert_eq!(account_data.owner, new_owner); + assert_eq!(account_data.lamports, 10000); + + { + let account_info = (&mut account_data).into_account_info(); + account_info.realloc(0, false).unwrap(); + account_info.assign(&Pubkey::default()); + } + assert_eq!(account_data.get_length(), 0); + assert_eq!(account_data.owner, Pubkey::default()); + } +} diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index 9d99e902a..53460e74c 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -1,59 +1,182 @@ use async_trait::async_trait; -use evm_loader::account::legacy::{ - LegacyEtherData, LegacyStorageData, TAG_ACCOUNT_CONTRACT_DEPRECATED, - TAG_STORAGE_CELL_DEPRECATED, +use elsa::FrozenMap; +use solana_client::rpc_response::{Response, RpcResponseContext, RpcResult}; +use std::collections::{HashMap, HashSet}; +use std::{ + cell::{RefCell, RefMut}, + convert::TryInto, + rc::Rc, +}; + +use crate::{ + account_data::AccountData, rpc::Rpc, solana_simulator::SolanaSimulator, NeonError, NeonResult, }; -use evm_loader::account::{TAG_ACCOUNT_CONTRACT, TAG_STORAGE_CELL}; -use evm_loader::account_storage::find_slot_hash; -use evm_loader::types::Address; -use solana_sdk::rent::Rent; -use solana_sdk::system_program; -use solana_sdk::sysvar::slot_hashes; -use std::collections::HashSet; -use std::{cell::RefCell, collections::HashMap, convert::TryInto, rc::Rc}; - -use crate::NeonResult; -use crate::{rpc::Rpc, NeonError}; use ethnum::U256; +pub use evm_loader::account_storage::{AccountStorage, SyncedAccountStorage}; use evm_loader::{ - account::{BalanceAccount, ContractAccount, StorageCell, StorageCellAddress}, - account_storage::AccountStorage, + account::{ + legacy::{LegacyEtherData, LegacyStorageData}, + BalanceAccount, ContractAccount, StorageCell, StorageCellAddress, + }, + account_storage::find_slot_hash, config::STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT, - executor::{Action, OwnedAccountInfo}, + error::Error as EvmLoaderError, + executor::OwnedAccountInfo, + types::Address, }; use log::{debug, info, trace}; -use serde::{Deserialize, Serialize}; -use solana_client::client_error; -use solana_sdk::{account::Account, account_info::AccountInfo, pubkey, pubkey::Pubkey}; +use solana_client::client_error::{self, Result as ClientResult}; +use solana_sdk::{ + account::Account, + account_info::{AccountInfo, IntoAccountInfo}, + clock::{Clock, Slot, UnixTimestamp}, + commitment_config::CommitmentConfig, + instruction::Instruction, + program_error::ProgramError, + pubkey, + pubkey::{Pubkey, PubkeyError}, + rent::Rent, + system_program, + sysvar::slot_hashes, + transaction_context::TransactionReturnData, +}; use crate::commands::get_config::{BuildConfigSimulator, ChainInfo}; -use crate::tracing::{AccountOverride, AccountOverrides, BlockOverrides}; -use serde_with::{serde_as, DisplayFromStr}; +use crate::tracing::{AccountOverrides, BlockOverrides}; const FAKE_OPERATOR: Pubkey = pubkey!("neonoperator1111111111111111111111111111111"); -#[serde_as] -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Default, Clone, Copy)] +pub struct ExecuteStatus { + pub external_solana_call: bool, + pub reverts_before_solana_calls: bool, + pub reverts_after_solana_calls: bool, +} + +#[derive(Debug, Clone)] pub struct SolanaAccount { - #[serde_as(as = "DisplayFromStr")] - pubkey: Pubkey, - is_writable: bool, - is_legacy: bool, - #[serde(skip)] - data: Option, + pub pubkey: Pubkey, + pub is_writable: bool, + pub is_legacy: bool, + pub lamports_after_upgrade: Option, +} + +pub type SolanaOverrides = HashMap>; + +trait UpdateLamports<'a> { + fn update_lamports(&mut self, rent: &Rent) { + let required_lamports = rent.minimum_balance(self.required_lamports()); + if self.info().lamports() < required_lamports { + **self.info().lamports.borrow_mut() = required_lamports; + } + } + fn required_lamports(&self) -> usize; + fn info(&self) -> &AccountInfo<'a>; +} +impl<'a> UpdateLamports<'a> for BalanceAccount<'a> { + fn required_lamports(&self) -> usize { + BalanceAccount::required_account_size() + } + fn info(&self) -> &AccountInfo<'a> { + self.info() + } +} +impl<'a> UpdateLamports<'a> for ContractAccount<'a> { + fn required_lamports(&self) -> usize { + ContractAccount::required_account_size(self.code().as_ref()) + } + fn info(&self) -> &AccountInfo<'a> { + self.info() + } +} +impl<'a> UpdateLamports<'a> for StorageCell<'a> { + fn required_lamports(&self) -> usize { + StorageCell::required_account_size(self.cells().len()) + } + fn info(&self) -> &AccountInfo<'a> { + self.info() + } } #[allow(clippy::module_name_repetitions)] pub struct EmulatorAccountStorage<'rpc, T: Rpc> { - pub accounts: RefCell>, + accounts: FrozenMap>>, + call_stack: Vec>>>, + pub gas: u64, + pub realloc_iterations: u64, + pub execute_status: ExecuteStatus, rpc: &'rpc T, program_id: Pubkey, + operator: Pubkey, chains: Vec, block_number: u64, block_timestamp: i64, + timestamp_used: RefCell, rent: Rent, - state_overrides: Option, + _state_overrides: Option, + accounts_cache: FrozenMap>>, + used_accounts: FrozenMap>>, + return_data: RefCell>, +} + +#[async_trait(?Send)] +impl<'rpc, T: Rpc> Rpc for EmulatorAccountStorage<'rpc, T> { + async fn get_account(&self, key: &Pubkey) -> RpcResult> { + let account = if *key == self.operator { + Some(Account { + lamports: 100 * 1_000_000_000, + data: vec![], + owner: system_program::ID, + executable: false, + rent_epoch: 0, + }) + } else if let Some(account) = self.accounts.get(key) { + let acc = &*account.borrow(); + Some(acc.into()) + } else { + self._get_account_from_rpc(*key).await?.cloned() + }; + + Ok(Response { + context: RpcResponseContext { + slot: self.block_number, + api_version: None, + }, + value: account, + }) + } + + async fn get_account_with_commitment( + &self, + _key: &Pubkey, + _commitment: CommitmentConfig, + ) -> RpcResult> { + unimplemented!(); + } + + async fn get_multiple_accounts( + &self, + pubkeys: &[Pubkey], + ) -> ClientResult>> { + // TODO: Optimize this!!! + let mut result = vec![]; + for key in pubkeys { + let account = self.get_account(key).await?.value; + result.push(account); + } + Ok(result) + } + + async fn get_block_time(&self, _slot: Slot) -> ClientResult { + // Ok(self.block_timestamp) + unimplemented!(); + } + + async fn get_slot(&self) -> ClientResult { + //Ok(self.block_number) + unimplemented!(); + } } impl<'rpc, T: Rpc + BuildConfigSimulator> EmulatorAccountStorage<'rpc, T> { @@ -63,6 +186,7 @@ impl<'rpc, T: Rpc + BuildConfigSimulator> EmulatorAccountStorage<'rpc, T> { chains: Option>, block_overrides: Option, state_overrides: Option, + solana_overrides: Option, ) -> Result, NeonError> { trace!("backend::new"); @@ -89,19 +213,56 @@ impl<'rpc, T: Rpc + BuildConfigSimulator> EmulatorAccountStorage<'rpc, T> { let rent = bincode::deserialize::(&rent_account.data)?; info!("Rent: {rent:?}"); + let accounts_cache = FrozenMap::new(); + if let Some(overrides) = solana_overrides { + for (pubkey, account) in overrides { + accounts_cache.insert(pubkey, Box::new(account)); + } + } + Ok(Self { - accounts: RefCell::new(HashMap::new()), + accounts: FrozenMap::new(), + call_stack: vec![], program_id, + operator: FAKE_OPERATOR, chains, gas: 0, + realloc_iterations: 0, + execute_status: ExecuteStatus::default(), rpc, block_number, block_timestamp, - state_overrides, + timestamp_used: RefCell::new(false), + _state_overrides: state_overrides, rent, + accounts_cache, + used_accounts: FrozenMap::new(), + return_data: RefCell::new(None), }) } + pub fn new_from_other(other: &Self, block_shift: u64, timestamp_shift: i64) -> Self { + Self { + accounts: FrozenMap::new(), + call_stack: vec![], + program_id: other.program_id, + operator: other.operator, + chains: other.chains.clone(), + gas: 0, + realloc_iterations: 0, + execute_status: ExecuteStatus::default(), + rpc: other.rpc, + block_number: other.block_number.saturating_add(block_shift), + block_timestamp: other.block_timestamp.saturating_add(timestamp_shift), + timestamp_used: RefCell::new(false), + rent: other.rent, + _state_overrides: other._state_overrides.clone(), + accounts_cache: other.accounts_cache.clone(), + used_accounts: other.used_accounts.clone(), + return_data: RefCell::new(None), + } + } + pub async fn with_accounts( rpc: &'rpc T, program_id: Pubkey, @@ -109,8 +270,17 @@ impl<'rpc, T: Rpc + BuildConfigSimulator> EmulatorAccountStorage<'rpc, T> { chains: Option>, block_overrides: Option, state_overrides: Option, + solana_overrides: Option, ) -> Result, NeonError> { - let storage = Self::new(rpc, program_id, chains, block_overrides, state_overrides).await?; + let storage = Self::new( + rpc, + program_id, + chains, + block_overrides, + state_overrides, + solana_overrides, + ) + .await?; storage.download_accounts(accounts).await?; @@ -118,428 +288,586 @@ impl<'rpc, T: Rpc + BuildConfigSimulator> EmulatorAccountStorage<'rpc, T> { } } -impl EmulatorAccountStorage<'_, T> { +impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { async fn download_accounts(&self, pubkeys: &[Pubkey]) -> Result<(), NeonError> { let accounts = self.rpc.get_multiple_accounts(pubkeys).await?; - let mut cache = self.accounts.borrow_mut(); - for (key, account) in pubkeys.iter().zip(accounts) { - let account = SolanaAccount { - pubkey: *key, - is_writable: false, - is_legacy: false, - data: account.clone(), - }; - - cache.insert(*key, account); + self.accounts_cache.insert(*key, Box::new(account)); } Ok(()) } - pub async fn use_account( + pub async fn _get_account_from_rpc( &self, pubkey: Pubkey, - is_writable: bool, - ) -> client_error::Result> { + ) -> client_error::Result> { if pubkey == FAKE_OPERATOR { return Ok(None); } - if let Some(account) = self.accounts.borrow_mut().get_mut(&pubkey) { - account.is_writable |= is_writable; - return Ok(account.data.clone()); + if let Some(account) = self.accounts_cache.get(&pubkey) { + return Ok(account.as_ref()); } let response = self.rpc.get_account(&pubkey).await?; - let account = response.value; - - self.accounts.borrow_mut().insert( - pubkey, - SolanaAccount { - pubkey, - is_writable, - is_legacy: false, - data: account.clone(), - }, - ); - - Ok(account) + let account = self.accounts_cache.insert(pubkey, Box::new(response.value)); + Ok(account.as_ref()) } - pub async fn use_balance_account( - &self, - address: Address, - chain_id: u64, - is_writable: bool, - ) -> NeonResult<(Pubkey, Option, Option)> { - let (pubkey, _) = address.find_balance_address(self.program_id(), chain_id); - let account = self.use_account(pubkey, is_writable).await?; - - let legacy_account = if account.is_none() && (chain_id == self.default_chain_id()) { - let (legacy_pubkey, _) = address.find_solana_address(self.program_id()); - self.use_account(legacy_pubkey, is_writable).await? - } else { - None - }; - - Ok((pubkey, account, legacy_account)) + fn mark_account(&self, pubkey: Pubkey, is_writable: bool) { + let mut data = self._get_account_mark(pubkey); + data.is_writable |= is_writable; } - pub async fn use_contract_account( + fn mark_legacy_account( &self, - address: Address, + pubkey: Pubkey, is_writable: bool, - ) -> NeonResult<(Pubkey, Option)> { - let (pubkey, _) = address.find_solana_address(self.program_id()); - let account = self.use_account(pubkey, is_writable).await?; + lamports_after_upgrade: Option, + ) { + let mut data = self._get_account_mark(pubkey); + data.is_writable |= is_writable; + data.is_legacy = true; + if lamports_after_upgrade.is_some() { + data.lamports_after_upgrade = lamports_after_upgrade; + } + } - Ok((pubkey, account)) + fn _get_account_mark(&self, pubkey: Pubkey) -> RefMut<'_, SolanaAccount> { + self.used_accounts + .insert( + pubkey, + Box::new(RefCell::new(SolanaAccount { + pubkey, + is_writable: false, + is_legacy: false, + lamports_after_upgrade: None, + })), + ) + .borrow_mut() } - pub async fn use_storage_cell( + async fn _add_legacy_account( &self, - address: Address, - index: U256, - is_writable: bool, - ) -> NeonResult<(Pubkey, Option)> { - let (base, _) = address.find_solana_address(self.program_id()); - let cell_address = StorageCellAddress::new(self.program_id(), &base, &index); + info: &AccountInfo<'_>, + ) -> NeonResult<(&RefCell, &RefCell)> { + let legacy = LegacyEtherData::from_account(&self.program_id, info)?; + + let (balance_pubkey, _) = legacy + .address + .find_balance_address(&self.program_id, self.default_chain_id()); + let balance_data = self.add_empty_account(balance_pubkey)?; + if (legacy.balance > 0) || (legacy.trx_count > 0) { + let mut balance_data = balance_data.borrow_mut(); + let mut balance = self.create_ethereum_balance( + &mut balance_data, + legacy.address, + self.default_chain_id(), + )?; + balance.mint(legacy.balance)?; + balance.increment_nonce_by(legacy.trx_count)?; + self.mark_legacy_account(balance_pubkey, true, Some(balance_data.lamports)); + } else { + self.mark_legacy_account(balance_pubkey, false, Some(0)); + } - let account = self - .use_account(*cell_address.pubkey(), is_writable) - .await?; + let (contract_pubkey, _) = legacy.address.find_solana_address(&self.program_id); + let contract_data = self.add_empty_account(contract_pubkey)?; + if (legacy.code_size > 0) || (legacy.generation > 0) { + let code = legacy.read_code(info); + let storage = legacy.read_storage(info); + + let mut contract_data = contract_data.borrow_mut(); + let mut contract = self.create_ethereum_contract( + &mut contract_data, + legacy.address, + self.default_chain_id(), + legacy.generation, + &code, + )?; + if !code.is_empty() { + contract.set_storage_multiple_values(0, &storage); + } + self.mark_legacy_account(contract_pubkey, true, Some(contract_data.lamports)); + } else { + // We have to mark account as writable, because we destroy the original legacy account + self.mark_legacy_account(contract_pubkey, true, Some(0)); + } - Ok((*cell_address.pubkey(), account)) + Ok((contract_data, balance_data)) } - pub async fn apply_actions(&mut self, actions: Vec) -> Result<(), NeonError> { - info!("apply_actions"); + async fn _get_contract_generation_limited(&self, address: Address) -> NeonResult> { + let extract_generation = |contract_data: &RefCell| -> NeonResult> { + let mut contract_data = contract_data.borrow_mut(); + if contract_data.is_empty() { + Ok(None) + } else { + let contract = ContractAccount::from_account( + &self.program_id, + contract_data.into_account_info(), + )?; + if contract.code().len() > 0 { + Ok(Some(contract.generation())) + } else { + Ok(None) + } + } + }; - let mut new_balance_accounts = HashSet::new(); + let (pubkey, _) = address.find_solana_address(&self.program_id); + let contract_data = if let Some(contract_data) = self.accounts.get(&pubkey) { + contract_data + } else { + let mut account = self._get_account_from_rpc(pubkey).await?.cloned(); + if let Some(account) = &mut account { + let info = account_info(&pubkey, account); + if *info.owner != self.program_id { + let account_data = AccountData::new_from_account(pubkey, account); + self.accounts + .insert(pubkey, Box::new(RefCell::new(account_data))) + } else { + match evm_loader::account::tag(&self.program_id, &info)? { + evm_loader::account::TAG_ACCOUNT_CONTRACT => { + let data = AccountData::new_from_account(pubkey, account); + self.accounts.insert(pubkey, Box::new(RefCell::new(data))) + } + evm_loader::account::legacy::TAG_ACCOUNT_CONTRACT_DEPRECATED => self + ._add_legacy_account(&info) + .await + .map(|(contract, _balance)| contract)?, + _ => { + unimplemented!(); + } + } + } + } else { + self.add_empty_account(pubkey)? + } + }; + self.mark_legacy_account(pubkey, false, None); + extract_generation(contract_data) + } - for action in actions { - #[allow(clippy::match_same_arms)] - match action { - Action::Transfer { - source, - target, - chain_id, - value, - } => { - info!("neon transfer {value} from {source} to {target}"); + async fn _add_legacy_storage( + &self, + legacy_storage: &LegacyStorageData, + info: &AccountInfo<'_>, + pubkey: Pubkey, + ) -> NeonResult<&RefCell> { + let generation = self + ._get_contract_generation_limited(legacy_storage.address) + .await?; + let storage_data = self.add_empty_account(pubkey)?; - self.use_balance_account(source, chain_id, true).await?; + if Some(legacy_storage.generation) == generation { + let cells = legacy_storage.read_cells(info); - let (key, target, legacy) = - self.use_balance_account(target, chain_id, true).await?; - if target.is_none() && legacy.is_none() { - new_balance_accounts.insert(key); - } - } - Action::Burn { - source, - value, - chain_id, - } => { - info!("neon withdraw {value} from {source}"); - - self.use_balance_account(source, chain_id, true).await?; - } - Action::EvmSetStorage { - address, - index, - value, - } => { - info!("set storage {address} -> {index} = {}", hex::encode(value)); - - if index < U256::from(STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT as u64) { - self.use_contract_account(address, true).await?; - } else { - let index = index & !U256::new(0xFF); - let (_, account) = self.use_storage_cell(address, index, true).await?; - - let cell_size = StorageCell::required_account_size(1); - let empty_size = StorageCell::required_account_size(0); - - let gas = if account.is_none() { - self.rent.minimum_balance(cell_size) - } else { - let existing_value = self.storage(address, index).await; - if existing_value == [0_u8; 32] { - self.rent - .minimum_balance(cell_size) - .saturating_sub(self.rent.minimum_balance(empty_size)) - } else { - 0 - } - }; + let mut storage_data = storage_data.borrow_mut(); + self.create_ethereum_storage(&mut storage_data)?; - self.gas = self.gas.saturating_add(gas); - } - } - Action::EvmSetTransientStorage { - address, - index, - value, - } => { - let value = hex::encode(value); - info!("set transient storage {address} -> {index} = {value}"); - } - Action::EvmIncrementNonce { address, chain_id } => { - info!("nonce increment {address}"); + storage_data.expand(StorageCell::required_account_size(cells.len())); + storage_data.lamports = self.rent.minimum_balance(storage_data.get_length()); + let mut storage = + StorageCell::from_account(&self.program_id, storage_data.into_account_info())?; + storage.cells_mut().copy_from_slice(&cells); + self.mark_legacy_account(pubkey, true, Some(storage_data.lamports)); + } else { + self.mark_legacy_account(pubkey, true, Some(0)); + } + Ok(storage_data) + } - let (key, account, legacy) = - self.use_balance_account(address, chain_id, true).await?; - if account.is_none() && legacy.is_none() { - new_balance_accounts.insert(key); - } + async fn add_account( + &self, + pubkey: Pubkey, + account: &Account, + ) -> NeonResult<&RefCell> { + let mut account = account.clone(); + let info = account_info(&pubkey, &mut account); + if *info.owner != self.program_id { + let account_data = AccountData::new_from_account(pubkey, &account); + self.mark_account(pubkey, false); + Ok(self + .accounts + .insert(pubkey, Box::new(RefCell::new(account_data)))) + } else { + let tag = evm_loader::account::tag(&self.program_id, &info)?; + match tag { + evm_loader::account::TAG_ACCOUNT_BALANCE + | evm_loader::account::TAG_ACCOUNT_CONTRACT + | evm_loader::account::TAG_STORAGE_CELL => { + // TODO: update header from previous revisions + let account_data = AccountData::new_from_account(pubkey, &account); + self.mark_account(pubkey, false); + Ok(self + .accounts + .insert(pubkey, Box::new(RefCell::new(account_data)))) } - Action::EvmSetCode { - address, - code, - chain_id: _, - } => { - info!("set code {address} -> {} bytes", code.len()); - self.use_contract_account(address, true).await?; - - let space = ContractAccount::required_account_size(&code); - self.gas = self.gas.saturating_add(self.rent.minimum_balance(space)); + evm_loader::account::legacy::TAG_ACCOUNT_CONTRACT_DEPRECATED => self + ._add_legacy_account(&info) + .await + .map(|(contract, _balance)| contract), + evm_loader::account::legacy::TAG_STORAGE_CELL_DEPRECATED => { + let legacy_storage = LegacyStorageData::from_account(&self.program_id, &info)?; + self._add_legacy_storage(&legacy_storage, &info, pubkey) + .await } - Action::ExternalInstruction { - program_id, - accounts, - fee, - .. - } => { - info!("external call {program_id}"); - - self.use_account(program_id, false).await?; - - for account in accounts { - self.use_account(account.pubkey, account.is_writable) - .await?; - } - - self.gas = self.gas.saturating_add(fee); + _ => { + unimplemented!(); } } } - - self.gas = self.gas.saturating_add( - self.rent - .minimum_balance(BalanceAccount::required_account_size()) - .saturating_mul(new_balance_accounts.len() as u64), - ); - - Ok(()) } - pub async fn mark_legacy_accounts(&mut self) -> Result<(), NeonError> { - let mut accounts = self.accounts.borrow_mut(); - let mut additional_balances = Vec::new(); + fn add_empty_account(&self, pubkey: Pubkey) -> NeonResult<&RefCell> { + let account_data = AccountData::new(pubkey); + self.mark_account(pubkey, false); + Ok(self + .accounts + .insert(pubkey, Box::new(RefCell::new(account_data)))) + } - for (key, account) in accounts.iter_mut() { - let Some(account_data) = account.data.as_mut() else { - continue; - }; + async fn use_account( + &self, + pubkey: Pubkey, + is_writable: bool, + ) -> NeonResult<&RefCell> { + if pubkey == self.operator() { + return Err(EvmLoaderError::InvalidAccountForCall(pubkey).into()); + } - let info = account_info(key, account_data); - if info.owner != self.program_id() { - continue; - } + self.mark_account(pubkey, is_writable); - let Ok(tag) = evm_loader::account::tag(self.program_id(), &info) else { - continue; - }; + if let Some(account) = self.accounts.get(&pubkey) { + return Ok(account); + } - if tag == TAG_STORAGE_CELL_DEPRECATED { - account.is_writable = true; - account.is_legacy = true; - } + let account = self._get_account_from_rpc(pubkey).await?; + if let Some(account) = account { + self.add_account(pubkey, account).await + } else { + self.add_empty_account(pubkey) + } + } - if tag == TAG_ACCOUNT_CONTRACT_DEPRECATED { - account.is_writable = true; - account.is_legacy = true; + async fn get_balance_account( + &self, + address: Address, + chain_id: u64, + ) -> NeonResult<&RefCell> { + let (pubkey, _) = address.find_balance_address(self.program_id(), chain_id); - let legacy_data = LegacyEtherData::from_account(self.program_id(), &info)?; - additional_balances.push(legacy_data.address); + if let Some(account) = self.accounts.get(&pubkey) { + return Ok(account); + } - if (legacy_data.code_size > 0) || (legacy_data.generation > 0) { - // This is a contract, we need additional gas for conversion - let lamports = self - .rent - .minimum_balance(BalanceAccount::required_account_size()); - self.gas = self.gas.saturating_add(lamports); + match self._get_account_from_rpc(pubkey).await? { + Some(account) => self.add_account(pubkey, account).await, + None => { + if chain_id == self.default_chain_id() { + let (legacy_pubkey, _) = address.find_solana_address(self.program_id()); + if self.accounts.get(&legacy_pubkey).is_some() { + // We already have information about contract account (empty or filled with data). + // So the balance should be updated, but it is missed. So return the empty account. + self.add_empty_account(pubkey) + } else { + // We didn't process contract account and we doesn't have any information about it. + // So we can try to process account which can be a legacy. + match self._get_account_from_rpc(legacy_pubkey).await? { + Some(legacy_account) => { + self.add_account(legacy_pubkey, legacy_account).await?; + match self.accounts.get(&pubkey) { + Some(account) => Ok(account), + None => self.add_empty_account(pubkey), + } + } + None => { + self.add_empty_account(legacy_pubkey)?; + self.add_empty_account(pubkey) + } + } + } + } else { + self.add_empty_account(pubkey) } } + } + } - if !account.is_writable { - continue; - } - - let required_header_realloc = match tag { - TAG_ACCOUNT_CONTRACT => { - let contract = ContractAccount::from_account(self.program_id(), info)?; - contract.required_header_realloc() - } - TAG_STORAGE_CELL => { - let cell = StorageCell::from_account(self.program_id(), info)?; - cell.required_header_realloc() - } - _ => 0, - }; + async fn get_contract_account(&self, address: Address) -> NeonResult<&RefCell> { + let (pubkey, _) = address.find_solana_address(self.program_id()); - let header_realloc_lamports = self - .rent - .minimum_balance(required_header_realloc) - .saturating_sub(self.rent.minimum_balance(0)); + if let Some(account) = self.accounts.get(&pubkey) { + return Ok(account); + } - self.gas = self.gas.saturating_add(header_realloc_lamports); + match self._get_account_from_rpc(pubkey).await? { + Some(account) => self.add_account(pubkey, account).await, + None => self.add_empty_account(pubkey), } + } - for a in additional_balances { - let (pubkey, _) = a.find_balance_address(self.program_id(), self.default_chain_id()); - let account = SolanaAccount { - pubkey, - is_writable: true, - is_legacy: false, - data: None, - }; + async fn get_storage_account( + &self, + address: Address, + index: U256, + ) -> NeonResult<&RefCell> { + let (base, _) = address.find_solana_address(self.program_id()); + let cell_address = StorageCellAddress::new(self.program_id(), &base, &index); + let cell_pubkey = *cell_address.pubkey(); - accounts.insert(pubkey, account); + if let Some(account) = self.accounts.get(&cell_pubkey) { + return Ok(account); } - Ok(()) + match self._get_account_from_rpc(cell_pubkey).await? { + Some(account) => self.add_account(cell_pubkey, account).await, + None => self.add_empty_account(cell_pubkey), + } } - pub async fn ethereum_balance_map_or( + pub async fn ethereum_balance_map_or( &self, address: Address, chain_id: u64, default: R, - legacy_action: L, action: F, - ) -> R + ) -> NeonResult where - L: FnOnce(LegacyEtherData) -> R, - F: FnOnce(BalanceAccount) -> R, + F: FnOnce(&BalanceAccount) -> R, { - let (pubkey, mut account, mut legacy) = self - .use_balance_account(address, chain_id, false) - .await - .unwrap(); - - if let Some(account_data) = &mut account { - let info = account_info(&pubkey, account_data); - if let Ok(a) = BalanceAccount::from_account(self.program_id(), info) { - return action(a); - } - } - - if chain_id != self.default_chain_id() { - return default; + let mut balance_data = self + .get_balance_account(address, chain_id) + .await? + .borrow_mut(); + if balance_data.is_empty() { + Ok(default) + } else { + let account_info = balance_data.into_account_info(); + let balance = BalanceAccount::from_account(self.program_id(), account_info)?; + Ok(action(&balance)) } + } - if let Some(legacy_data) = &mut legacy { - let info = account_info(&pubkey, legacy_data); - if let Ok(a) = LegacyEtherData::from_account(self.program_id(), &info) { - return legacy_action(a); - } + pub async fn ethereum_contract_map_or( + &self, + address: Address, + default: R, + action: F, + ) -> NeonResult + where + F: FnOnce(&ContractAccount) -> R, + { + let mut contract_data = self.get_contract_account(address).await?.borrow_mut(); + if contract_data.is_empty() { + Ok(default) + } else { + let account_info = contract_data.into_account_info(); + let contract = ContractAccount::from_account(self.program_id(), account_info)?; + Ok(action(&contract)) } - - default } - pub async fn ethereum_contract_map_or( + pub async fn ethereum_storage_map_or( &self, address: Address, + index: U256, default: R, - legacy_action: L, action: F, - ) -> R + ) -> NeonResult where - L: FnOnce(LegacyEtherData, &AccountInfo) -> R, - F: FnOnce(ContractAccount) -> R, + F: FnOnce(&StorageCell) -> R, { - let (pubkey, mut account) = self.use_contract_account(address, false).await.unwrap(); + let mut storage_data = self.get_storage_account(address, index).await?.borrow_mut(); + if storage_data.is_empty() { + Ok(default) + } else { + let account_info = storage_data.into_account_info(); + let storage = StorageCell::from_account(self.program_id(), account_info)?; + Ok(action(&storage)) + } + } - let Some(account_data) = &mut account else { - return default; - }; + fn create_ethereum_balance( + &'a self, + account_data: &'a mut RefMut, + address: Address, + chain_id: u64, + ) -> evm_loader::error::Result { + let required_len = BalanceAccount::required_account_size(); + account_data.assign(self.program_id)?; + account_data.expand(required_len); + account_data.lamports = self.rent.minimum_balance(account_data.get_length()); + + BalanceAccount::initialize( + account_data.into_account_info(), + &self.program_id, + address, + chain_id, + ) + } - if system_program::check_id(&account_data.owner) { - return default; + fn get_or_create_ethereum_balance( + &'a self, + account_data: &'a mut RefMut, + address: Address, + chain_id: u64, + ) -> evm_loader::error::Result { + if account_data.is_empty() { + self.create_ethereum_balance(account_data, address, chain_id) + } else { + BalanceAccount::from_account(&self.program_id, account_data.into_account_info()) } + } - let info = account_info(&pubkey, account_data); - let Ok(tag) = evm_loader::account::tag(self.program_id(), &info) else { - return default; - }; + fn create_ethereum_contract( + &'a self, + account_data: &'a mut RefMut, + address: Address, + chain_id: u64, + generation: u32, + code: &[u8], + ) -> evm_loader::error::Result { + self.mark_account(account_data.pubkey, true); + let required_len = ContractAccount::required_account_size(code); + account_data.assign(self.program_id)?; + account_data.expand(required_len); + account_data.lamports = self.rent.minimum_balance(account_data.get_length()); + + ContractAccount::initialize( + account_data.into_account_info(), + &self.program_id, + address, + chain_id, + generation, + code, + ) + } - match tag { - TAG_ACCOUNT_CONTRACT => { - let contract = ContractAccount::from_account(self.program_id(), info).unwrap(); - action(contract) - } - TAG_ACCOUNT_CONTRACT_DEPRECATED => { - let legacy_data = LegacyEtherData::from_account(self.program_id(), &info).unwrap(); - legacy_action(legacy_data, &info) - } - _ => default, + fn create_ethereum_storage( + &'a self, + account_data: &'a mut RefMut, + ) -> evm_loader::error::Result { + self.mark_account(account_data.pubkey, true); + account_data.assign(self.program_id)?; + account_data.expand(StorageCell::required_account_size(0)); + account_data.lamports = self.rent.minimum_balance(account_data.get_length()); + + StorageCell::initialize(account_data.into_account_info(), &self.program_id) + } + + fn get_or_create_ethereum_storage( + &'a self, + account_data: &'a mut RefMut, + ) -> evm_loader::error::Result { + if account_data.is_empty() { + self.create_ethereum_storage(account_data) + } else { + StorageCell::from_account(&self.program_id, account_data.into_account_info()) } } - pub async fn ethereum_storage_map_or( - &self, + async fn mint( + &mut self, address: Address, - index: U256, - default: R, - legacy_action: L, - action: F, - ) -> R - where - L: FnOnce(LegacyStorageData, &AccountInfo) -> R, - F: FnOnce(StorageCell) -> R, - { - let (pubkey, mut account) = self.use_storage_cell(address, index, false).await.unwrap(); + chain_id: u64, + value: U256, + ) -> evm_loader::error::Result<()> { + info!("mint {address}:{chain_id} {value}"); + let mut balance_data = self + .get_balance_account(address, chain_id) + .await + .map_err(map_neon_error)? + .borrow_mut(); - let Some(account_data) = &mut account else { - return default; - }; + let mut balance = + self.get_or_create_ethereum_balance(&mut balance_data, address, chain_id)?; + balance.mint(value)?; + balance.update_lamports(&self.rent); + self.mark_account(balance_data.pubkey, true); + + Ok(()) + } + + pub fn used_accounts(&self) -> Vec { + self.used_accounts + .clone() + .into_map() + .values() + .map(|v| v.borrow().clone()) + .collect::>() + } - if system_program::check_id(&account_data.owner) { - return default; + pub fn get_upgrade_rent(&self) -> evm_loader::error::Result { + let mut lamports_collected = 0u64; + let mut lamports_spend = 0u64; + for (_, used_account) in self.used_accounts.clone().into_tuple_vec() { + let used_account = used_account.borrow(); + if let Some(lamports_after_upgrade) = used_account.lamports_after_upgrade { + let orig_lamports = self + .accounts_cache + .get(&used_account.pubkey) + .unwrap_or(&None) + .as_ref() + .map(|v| v.lamports) + .unwrap_or(0); + if lamports_after_upgrade > orig_lamports { + lamports_spend += lamports_after_upgrade - orig_lamports; + } else { + lamports_collected += orig_lamports - lamports_after_upgrade; + } + } } + Ok(lamports_spend.saturating_sub(lamports_collected)) + } - let info = account_info(&pubkey, account_data); - let Ok(tag) = evm_loader::account::tag(self.program_id(), &info) else { - return default; - }; + pub fn get_regular_rent(&self) -> evm_loader::error::Result { + let accounts = self.accounts.clone(); + let mut changes_in_rent = 0u64; + for (pubkey, account) in accounts.into_map().iter() { + if *pubkey == system_program::ID { + continue; + } + + let (original_lamports, original_size) = + self.accounts_cache.get(pubkey).map_or((0, 0), |v| { + v.as_ref().map_or((0, 0), |v| (v.lamports, v.data.len())) + }); + + let lamports_after_upgrade = self + .used_accounts + .get(pubkey) + .and_then(|v| v.borrow().lamports_after_upgrade); + + let new_acc = account.borrow(); + let new_lamports = new_acc.lamports; + let new_size = new_acc.get_length(); - match tag { - TAG_STORAGE_CELL => { - let contract = StorageCell::from_account(self.program_id(), info).unwrap(); - action(contract) + if new_acc.is_busy() && new_lamports < self.rent.minimum_balance(new_acc.get_length()) { + info!("Account {pubkey} is not rent exempt"); + return Err(ProgramError::AccountNotRentExempt.into()); } - TAG_STORAGE_CELL_DEPRECATED => { - let legacy_data = - LegacyStorageData::from_account(self.program_id(), &info).unwrap(); - legacy_action(legacy_data, &info) + + if let Some(lamports_after_upgrade) = lamports_after_upgrade { + changes_in_rent += new_lamports.saturating_sub(lamports_after_upgrade); + info!("Changes in rent: {pubkey} {original_lamports} -> {lamports_after_upgrade} -> {new_lamports} | {original_size} -> {new_size}"); + } else { + changes_in_rent += new_lamports.saturating_sub(original_lamports); + info!("Changes in rent: {pubkey} {original_lamports} -> {new_lamports} | {original_size} -> {new_size}"); } - _ => default, } + Ok(changes_in_rent) } - fn account_override(&self, address: Address, f: F) -> Option - where - F: FnOnce(&AccountOverride) -> Option, - { - self.state_overrides - .as_ref() - .and_then(|a| a.get(&address)) - .and_then(f) + pub fn get_changes_in_rent(&self) -> evm_loader::error::Result { + Ok(self.get_upgrade_rent()? + self.get_regular_rent()?) + } + + pub fn is_timestamp_used(&self) -> bool { + *self.timestamp_used.borrow() } } @@ -552,7 +880,7 @@ impl AccountStorage for EmulatorAccountStorage<'_, T> { fn operator(&self) -> Pubkey { info!("operator"); - FAKE_OPERATOR + self.operator } fn block_number(&self) -> U256 { @@ -562,6 +890,7 @@ impl AccountStorage for EmulatorAccountStorage<'_, T> { fn block_timestamp(&self) -> U256 { info!("block_timestamp"); + *self.timestamp_used.borrow_mut() = true; self.block_timestamp.try_into().unwrap() } @@ -571,55 +900,61 @@ impl AccountStorage for EmulatorAccountStorage<'_, T> { fn return_data(&self) -> Option<(Pubkey, Vec)> { info!("return_data"); - // TODO: implement return_data() method with SyncedAccountStorage implementation - unimplemented!(); + self.return_data + .borrow() + .as_ref() + .map(|data| (data.program_id, data.data.clone())) + } + + fn set_return_data(&self, data: &[u8]) { + info!("set_return_data"); + *self.return_data.borrow_mut() = Some(TransactionReturnData { + program_id: self.program_id, + data: data.to_vec(), + }); } async fn block_hash(&self, slot: u64) -> [u8; 32] { info!("block_hash {slot}"); - if let Ok(Some(slot_hashes_account)) = self.use_account(slot_hashes::ID, false).await { - let slot_hashes_data = slot_hashes_account.data.as_slice(); - find_slot_hash(slot, slot_hashes_data) - } else { - panic!("Error querying account {} from Solana", slot_hashes::ID) + if let Ok(account) = self.use_account(slot_hashes::ID, false).await { + let account_data = account.borrow(); + let data = account_data.data(); + if !data.is_empty() { + return find_slot_hash(slot, data); + } } + panic!("Error querying account {} from Solana", slot_hashes::ID) } async fn nonce(&self, address: Address, chain_id: u64) -> u64 { info!("nonce {address} {chain_id}"); - let nonce_override = self.account_override(address, |a| a.nonce); - if let Some(nonce_override) = nonce_override { - return nonce_override; - } + // TODO: move to reading data from Solana node + // let nonce_override = self.account_override(address, |a| a.nonce); + // if let Some(nonce_override) = nonce_override { + // return nonce_override; + // } - self.ethereum_balance_map_or( - address, - chain_id, - u64::default(), - |legacy| legacy.trx_count, - |account| account.nonce(), - ) - .await + self.ethereum_balance_map_or(address, chain_id, u64::default(), |account| account.nonce()) + .await + .unwrap() } async fn balance(&self, address: Address, chain_id: u64) -> U256 { info!("balance {address} {chain_id}"); - let balance_override = self.account_override(address, |a| a.balance); - if let Some(balance_override) = balance_override { - return balance_override; - } + // TODO: move to reading data from Solana node + // let balance_override = self.account_override(address, |a| a.balance); + // if let Some(balance_override) = balance_override { + // return balance_override; + // } - self.ethereum_balance_map_or( - address, - chain_id, - U256::default(), - |legacy| legacy.balance, - |account| account.balance(), - ) + self.ethereum_balance_map_or(address, chain_id, U256::default(), |account| { + account.balance() + }) .await + .unwrap() } fn is_valid_chain_id(&self, chain_id: u64) -> bool { @@ -653,19 +988,13 @@ impl AccountStorage for EmulatorAccountStorage<'_, T> { } async fn contract_chain_id(&self, address: Address) -> evm_loader::error::Result { - use evm_loader::error::Error; - - let default_value = Err(Error::Custom(std::format!( + let default_value = Err(EvmLoaderError::Custom(std::format!( "Account {address} - invalid tag" ))); - self.ethereum_contract_map_or( - address, - default_value, - |_legacy, _| Ok(self.default_chain_id()), - |a| Ok(a.chain_id()), - ) - .await + self.ethereum_contract_map_or(address, default_value, |a| Ok(a.chain_id())) + .await + .unwrap() } fn contract_pubkey(&self, address: Address) -> (Pubkey, u8) { @@ -683,50 +1012,41 @@ impl AccountStorage for EmulatorAccountStorage<'_, T> { info!("code {address}"); - let code_override = self.account_override(address, |a| a.code.clone()); - if let Some(code_override) = code_override { - return Buffer::from_vec(code_override.0); - } + // TODO: move to reading data from Solana node + // let code_override = self.account_override(address, |a| a.code.clone()); + // if let Some(code_override) = code_override { + // return Buffer::from_vec(code_override.0); + // } let code = self - .ethereum_contract_map_or( - address, - Vec::default(), - |legacy, info| legacy.read_code(info), - |c| c.code().to_vec(), - ) - .await; + .ethereum_contract_map_or(address, Vec::default(), |c| c.code().to_vec()) + .await + .unwrap(); Buffer::from_vec(code) } async fn storage(&self, address: Address, index: U256) -> [u8; 32] { - let storage_override = self.account_override(address, |a| a.storage(index)); - if let Some(storage_override) = storage_override { - return storage_override; - } + // TODO: move to reading data from Solana node + // let storage_override = self.account_override(address, |a| a.storage(index)); + // if let Some(storage_override) = storage_override { + // return storage_override; + // } let value = if index < U256::from(STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT as u64) { let index: usize = index.as_usize(); - self.ethereum_contract_map_or( - address, - [0_u8; 32], - |legacy, info| legacy.read_storage(info)[index], - |c| c.storage_value(index), - ) - .await + self.ethereum_contract_map_or(address, [0_u8; 32], |c| c.storage_value(index)) + .await + .unwrap() } else { let subindex = (index & 0xFF).as_u8(); let index = index & !U256::new(0xFF); - self.ethereum_storage_map_or( - address, - index, - <[u8; 32]>::default(), - |legacy, info| legacy.read_value(subindex, info), - |cell| cell.get(subindex), - ) + self.ethereum_storage_map_or(address, index, <[u8; 32]>::default(), |cell| { + cell.get(subindex) + }) .await + .unwrap() }; info!("storage {address} -> {index} = {}", hex::encode(value)); @@ -737,9 +1057,9 @@ impl AccountStorage for EmulatorAccountStorage<'_, T> { async fn clone_solana_account(&self, address: &Pubkey) -> OwnedAccountInfo { info!("clone_solana_account {}", address); - if address == &FAKE_OPERATOR { + if *address == self.operator() { OwnedAccountInfo { - key: FAKE_OPERATOR, + key: self.operator(), is_signer: true, is_writable: false, lamports: 100 * 1_000_000_000, @@ -749,13 +1069,13 @@ impl AccountStorage for EmulatorAccountStorage<'_, T> { rent_epoch: 0, } } else { - let mut account = self + let account = self .use_account(*address, false) .await - .unwrap_or_default() - .unwrap_or_default(); + .expect("Error querying account from Solana"); - let info = account_info(address, &mut account); + let mut account_data = account.borrow_mut(); + let info = account_data.into_account_info(); OwnedAccountInfo::from_account_info(self.program_id(), &info) } } @@ -764,17 +1084,297 @@ impl AccountStorage for EmulatorAccountStorage<'_, T> { where F: FnOnce(&AccountInfo) -> R, { - let mut account = self + let account = self .use_account(*address, false) .await - .unwrap_or_default() - .unwrap_or_default(); + .expect("Error querying account from Solana"); - let info = account_info(address, &mut account); + let mut account_data = account.borrow_mut(); + let info = account_data.into_account_info(); action(&info) } } +fn map_neon_error(e: NeonError) -> EvmLoaderError { + EvmLoaderError::Custom(e.to_string()) +} + +#[async_trait(?Send)] +impl SyncedAccountStorage for EmulatorAccountStorage<'_, T> { + async fn set_code( + &mut self, + address: Address, + chain_id: u64, + code: Vec, + ) -> evm_loader::error::Result<()> { + info!("set_code {address} -> {} bytes", code.len()); + { + let mut account_data = self + .get_contract_account(address) + .await + .map_err(map_neon_error)? + .borrow_mut(); + let pubkey = account_data.pubkey; + + if account_data.is_empty() { + self.create_ethereum_contract(&mut account_data, address, chain_id, 0, &code)?; + } else { + let contract = ContractAccount::from_account( + self.program_id(), + account_data.into_account_info(), + )?; + if contract.code().len() > 0 { + return Err(EvmLoaderError::AccountAlreadyInitialized( + account_data.pubkey, + )); + } + let new_account_data = RefCell::new(AccountData::new(pubkey)); + { + let mut new_account = new_account_data.borrow_mut(); + let mut new_contract = self.create_ethereum_contract( + &mut new_account, + address, + chain_id, + contract.generation(), + &code, + )?; + let storage = *contract.storage(); + new_contract.set_storage_multiple_values(0, &storage); + } + *account_data = new_account_data.replace_with(|_| AccountData::new(pubkey)); + } + } + + let realloc = ContractAccount::required_account_size(&code) + / solana_sdk::entrypoint::MAX_PERMITTED_DATA_INCREASE; + self.realloc_iterations = self.realloc_iterations.max(realloc as u64); + + Ok(()) + } + + async fn set_storage( + &mut self, + address: Address, + index: U256, + value: [u8; 32], + ) -> evm_loader::error::Result<()> { + info!("set_storage {address} -> {index} = {}", hex::encode(value)); + const STATIC_STORAGE_LIMIT: U256 = U256::new(STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT as u128); + + if index < STATIC_STORAGE_LIMIT { + let mut contract_data = self + .get_contract_account(address) + .await + .map_err(map_neon_error)? + .borrow_mut(); + + let mut contract = if contract_data.is_empty() { + self.create_ethereum_contract(&mut contract_data, address, 0, 0, &[])? + } else { + ContractAccount::from_account(self.program_id(), contract_data.into_account_info())? + }; + contract.set_storage_value(index.as_usize(), &value); + contract.update_lamports(&self.rent); + self.mark_account(contract_data.pubkey, true); + } else { + let subindex = (index & 0xFF).as_u8(); + let index = index & !U256::new(0xFF); + + let mut storage_data = self + .get_storage_account(address, index) + .await + .map_err(map_neon_error)? + .borrow_mut(); + + let mut storage = self.get_or_create_ethereum_storage(&mut storage_data)?; + storage.update(subindex, &value)?; + storage.update_lamports(&self.rent); + self.mark_account(storage_data.pubkey, true); + } + + Ok(()) + } + + async fn increment_nonce( + &mut self, + address: Address, + chain_id: u64, + ) -> evm_loader::error::Result<()> { + info!("nonce increment {address} {chain_id}"); + let mut balance_data = self + .get_balance_account(address, chain_id) + .await + .map_err(map_neon_error)? + .borrow_mut(); + let mut balance = + self.get_or_create_ethereum_balance(&mut balance_data, address, chain_id)?; + balance.increment_nonce()?; + balance.update_lamports(&self.rent); + self.mark_account(balance_data.pubkey, true); + + Ok(()) + } + + async fn transfer( + &mut self, + from_address: Address, + to_address: Address, + chain_id: u64, + value: U256, + ) -> evm_loader::error::Result<()> { + self.burn(from_address, chain_id, value).await?; + self.mint(to_address, chain_id, value).await?; + + Ok(()) + } + + async fn burn( + &mut self, + address: Address, + chain_id: u64, + value: U256, + ) -> evm_loader::error::Result<()> { + info!("burn {address} {chain_id} {value}"); + let mut balance_data = self + .get_balance_account(address, chain_id) + .await + .map_err(map_neon_error)? + .borrow_mut(); + self.mark_account(balance_data.pubkey, true); + + let mut balance = + self.get_or_create_ethereum_balance(&mut balance_data, address, chain_id)?; + balance.burn(value)?; + balance.update_lamports(&self.rent); + + Ok(()) + } + + async fn execute_external_instruction( + &mut self, + instruction: Instruction, + seeds: Vec>>, + _fee: u64, + emulated_internally: bool, + ) -> evm_loader::error::Result<()> { + use solana_sdk::{message::Message, signature::Signer, transaction::Transaction}; + + info!("execute_external_instruction: {instruction:?}"); + info!("Operator: {}", self.operator); + self.execute_status.external_solana_call |= !emulated_internally; + + let mut solana_simulator = SolanaSimulator::new(self) + .await + .map_err(|e| EvmLoaderError::Custom(e.to_string()))?; + + solana_simulator.set_sysvar(&Clock { + slot: self.block_number, + epoch_start_timestamp: self.block_timestamp, + epoch: 0, + leader_schedule_epoch: 0, + unix_timestamp: self.block_timestamp, + }); + + let signers = seeds + .iter() + .map(|s| { + let seed = s.iter().map(|s| s.as_slice()).collect::>(); + let signer = Pubkey::create_program_address(&seed, &self.program_id)?; + Ok(signer) + }) + .collect::, PubkeyError>>()?; + info!("Signers: {signers:?}"); + + let mut accounts = Vec::new(); + accounts.push(instruction.program_id); + self.mark_account(instruction.program_id, false); + + for meta in instruction.accounts.iter() { + if meta.pubkey != self.operator { + self.use_account(meta.pubkey, meta.is_writable) + .await + .map_err(map_neon_error)?; + if meta.is_signer && !signers.contains(&meta.pubkey) { + return Err(ProgramError::MissingRequiredSignature.into()); + } + } + accounts.push(meta.pubkey); + } + + solana_simulator + .sync_accounts(self, &accounts) + .await + .map_err(|e| EvmLoaderError::Custom(e.to_string()))?; + + let trx = Transaction::new_unsigned(Message::new_with_blockhash( + &[instruction.clone()], + Some(&solana_simulator.payer().pubkey()), + &solana_simulator.blockhash(), + )); + + let result = solana_simulator + .simulate_legacy_transaction(trx) + .map_err(|e| EvmLoaderError::Custom(e.to_string()))?; + + if let Err(error) = result.result { + return Err(EvmLoaderError::ExternalCallFailed( + instruction.program_id, + error.to_string(), + )); + } + + if let Some(return_data) = result.return_data { + *self.return_data.borrow_mut() = Some(return_data); + } + + for meta in instruction.accounts.iter() { + if meta.pubkey == self.operator { + continue; + } + let account = result + .post_simulation_accounts + .iter() + .find(|(pubkey, _)| *pubkey == meta.pubkey) + .map(|(_, account)| account) + .ok_or_else(|| { + EvmLoaderError::Custom(format!("Account {} not found", meta.pubkey)) + })?; + + let mut account_data = self + .accounts + .get(&meta.pubkey) + .ok_or_else(|| { + EvmLoaderError::Custom(format!("Account data {} not found", meta.pubkey)) + })? + .borrow_mut(); + + *account_data = AccountData::new_from_account(meta.pubkey, account); + } + + Ok(()) + } + + fn snapshot(&mut self) { + info!("snapshot"); + self.call_stack.push(self.accounts.clone()); + } + + fn revert_snapshot(&mut self) { + info!("revert_snapshot"); + self.accounts = self.call_stack.pop().expect("No snapshots to revert"); + + if self.execute_status.external_solana_call { + self.execute_status.reverts_after_solana_calls = true; + } else { + self.execute_status.reverts_before_solana_calls = true; + } + } + + fn commit_snapshot(&mut self) { + self.call_stack.pop().expect("No snapshots to commit"); + } +} + /// Creates new instance of `AccountInfo` from `Account`. pub fn account_info<'a>(key: &'a Pubkey, account: &'a mut Account) -> AccountInfo<'a> { AccountInfo { @@ -788,3 +1388,1601 @@ pub fn account_info<'a>(key: &'a Pubkey, account: &'a mut Account) -> AccountInf rent_epoch: account.rent_epoch, } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::tracing::AccountOverride; + use hex_literal::hex; + use std::collections::HashMap; + use std::str::FromStr; + + mod mock_rpc_client { + use crate::commands::get_config::BuildConfigSimulator; + use crate::NeonResult; + use crate::{commands::get_config::ConfigSimulator, rpc::Rpc}; + use async_trait::async_trait; + use solana_client::client_error::Result as ClientResult; + use solana_client::rpc_response::{Response, RpcResponseContext, RpcResult}; + use solana_sdk::account::Account; + use solana_sdk::clock::{Slot, UnixTimestamp}; + use solana_sdk::commitment_config::CommitmentConfig; + use solana_sdk::pubkey::Pubkey; + use std::collections::HashMap; + + pub struct MockRpcClient { + accounts: HashMap, + } + + impl MockRpcClient { + pub fn new(accounts: &[(Pubkey, Account)]) -> Self { + Self { + accounts: accounts.iter().cloned().collect(), + } + } + } + + #[async_trait(?Send)] + impl Rpc for MockRpcClient { + async fn get_account(&self, key: &Pubkey) -> RpcResult> { + let result = self.accounts.get(key).cloned(); + Ok(Response { + context: RpcResponseContext { + slot: 0, + api_version: None, + }, + value: result, + }) + } + + async fn get_account_with_commitment( + &self, + key: &Pubkey, + _commitment: CommitmentConfig, + ) -> RpcResult> { + self.get_account(key).await + } + + async fn get_multiple_accounts( + &self, + pubkeys: &[Pubkey], + ) -> ClientResult>> { + let result = pubkeys + .iter() + .map(|key| self.accounts.get(key).cloned()) + .collect::>(); + Ok(result) + } + + async fn get_block_time(&self, _slot: Slot) -> ClientResult { + Ok(UnixTimestamp::default()) + } + + async fn get_slot(&self) -> ClientResult { + Ok(Slot::default()) + } + } + + #[async_trait(?Send)] + impl BuildConfigSimulator for MockRpcClient { + async fn build_config_simulator( + &self, + _program_id: Pubkey, + ) -> NeonResult { + unimplemented!(); + } + } + } + + fn create_legacy_ether_contract( + program_id: &Pubkey, + rent: &Rent, + address: Address, + balance: U256, + trx_count: u64, + generation: u32, + code: &[u8], + storage: &[[u8; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT], + ) -> Account { + let data_length = if (code.len() > 0) || (generation > 0) { + 1 + LegacyEtherData::SIZE + 32 * STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT + code.len() + } else { + 1 + LegacyEtherData::SIZE + }; + let mut data = vec![0u8; data_length]; + + let data_ref = arrayref::array_mut_ref![data, 0, 1 + LegacyEtherData::SIZE]; + let ( + tag_ptr, + address_ptr, + bump_seed_ptr, + trx_count_ptr, + balance_ptr, + generation_ptr, + code_size_ptr, + rw_blocked_ptr, + ) = arrayref::mut_array_refs![data_ref, 1, 20, 1, 8, 32, 4, 4, 1]; + + *tag_ptr = LegacyEtherData::TAG.to_le_bytes(); + *address_ptr = *address.as_bytes(); + *bump_seed_ptr = 0u8.to_le_bytes(); + *trx_count_ptr = trx_count.to_le_bytes(); + *balance_ptr = balance.to_le_bytes(); + *generation_ptr = generation.to_le_bytes(); + *code_size_ptr = (code.len() as u32).to_le_bytes(); + *rw_blocked_ptr = 0u8.to_le_bytes(); + + if (generation > 0) || (code.len() > 0) { + let storage_offset = 1 + LegacyEtherData::SIZE; + const STORAGE_LENGTH: usize = 32 * STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT; + let storage_ptr = &mut data[storage_offset..][..STORAGE_LENGTH]; + let storage_source = unsafe { + let ptr: *const u8 = storage.as_ptr().cast(); + std::slice::from_raw_parts(ptr, 32 * STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT) + }; + storage_ptr.copy_from_slice(storage_source); + + let code_offset = storage_offset + STORAGE_LENGTH; + let code_ptr = &mut data[code_offset..][..code.len()]; + code_ptr.copy_from_slice(code); + } + + Account { + lamports: rent.minimum_balance(data.len()), + data: data, + owner: *program_id, + executable: false, + rent_epoch: 0, + } + } + + fn create_legacy_ether_account( + program_id: &Pubkey, + rent: &Rent, + address: Address, + balance: U256, + trx_count: u64, + ) -> Account { + let storage = [[0u8; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT]; + create_legacy_ether_contract( + program_id, + rent, + address, + balance, + trx_count, + 0u32, + &[], + &storage, + ) + } + + struct ActualStorage { + index: U256, + values: &'static [(u8, [u8; 32])], + } + + struct LegacyStorage { + generation: u32, + index: U256, + values: &'static [(u8, [u8; 32])], + } + + impl ActualStorage { + pub fn account_with_pubkey( + &self, + program_id: &Pubkey, + rent: &Rent, + address: Address, + ) -> (Pubkey, Account) { + let (contract, _) = address.find_solana_address(program_id); + let cell_address = StorageCellAddress::new(program_id, &contract, &self.index); + let cell_pubkey = *cell_address.pubkey(); + let mut account_data = AccountData::new(cell_pubkey); + account_data.assign(*program_id).unwrap(); + account_data.expand(StorageCell::required_account_size(self.values.len())); + account_data.lamports = rent.minimum_balance(account_data.get_length()); + let mut storage = + StorageCell::initialize(account_data.into_account_info(), program_id).unwrap(); + for (cell, (index, value)) in storage.cells_mut().iter_mut().zip(self.values.iter()) { + cell.subindex = *index; + cell.value.copy_from_slice(value); + } + ( + cell_pubkey, + Account { + lamports: rent.minimum_balance(account_data.get_length()), + data: account_data.data().to_vec(), + owner: *program_id, + executable: false, + rent_epoch: 0, + }, + ) + } + } + + impl LegacyStorage { + pub fn required_account_size(count: usize) -> usize { + 1 + LegacyStorageData::SIZE + std::mem::size_of::<(u8, [u8; 32])>() * count + } + pub fn account_with_pubkey( + &self, + program_id: &Pubkey, + rent: &Rent, + address: Address, + ) -> (Pubkey, Account) { + let (contract, _) = address.find_solana_address(program_id); + let cell_address = StorageCellAddress::new(program_id, &contract, &self.index); + let cell_pubkey = *cell_address.pubkey(); + let mut data = vec![0u8; Self::required_account_size(self.values.len())]; + + let data_ref = arrayref::array_mut_ref![data, 0, 1 + LegacyStorageData::SIZE]; + let (tag_ptr, address_ptr, generation_ptr, index_ptr) = + arrayref::mut_array_refs![data_ref, 1, 20, 4, 32]; + + *tag_ptr = LegacyStorageData::TAG.to_le_bytes(); + *address_ptr = *address.as_bytes(); + *generation_ptr = self.generation.to_le_bytes(); + *index_ptr = self.index.to_le_bytes(); + + let storage = unsafe { + let data = &mut data[1 + LegacyStorageData::SIZE..]; + let ptr = data.as_mut_ptr().cast::<(u8, [u8; 32])>(); + std::slice::from_raw_parts_mut(ptr, self.values.len()) + }; + storage.copy_from_slice(self.values); + + let account = Account { + lamports: rent.minimum_balance(data.len()), + data: data, + owner: *program_id, + executable: false, + rent_epoch: 0, + }; + + (cell_pubkey, account) + } + } + + struct LegacyAccount { + pub address: Address, + pub balance: U256, + pub nonce: u64, + } + + impl LegacyAccount { + pub fn account_with_pubkey(&self, program_id: &Pubkey, rent: &Rent) -> (Pubkey, Account) { + ( + self.address.find_solana_address(&program_id).0, + create_legacy_ether_account( + &program_id, + &rent, + self.address, + self.balance, + self.nonce, + ), + ) + } + } + struct LegacyContract { + pub address: Address, + pub balance: U256, + pub nonce: u64, + pub generation: u32, + pub code: &'static [u8], + pub storage: [[u8; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT], + + pub legacy_storage: LegacyStorage, + pub outdate_storage: LegacyStorage, + } + + impl LegacyContract { + fn account_with_pubkey(&self, program_id: &Pubkey, rent: &Rent) -> (Pubkey, Account) { + ( + self.address.find_solana_address(&program_id).0, + create_legacy_ether_contract( + &program_id, + &rent, + self.address, + self.balance, + self.nonce, + self.generation, + &self.code, + &self.storage, + ), + ) + } + + pub fn legacy_storage_with_pubkey( + &self, + program_id: &Pubkey, + rent: &Rent, + ) -> (Pubkey, Account) { + self.legacy_storage + .account_with_pubkey(program_id, rent, self.address) + } + + pub fn outdate_storage_with_pubkey( + &self, + program_id: &Pubkey, + rent: &Rent, + ) -> (Pubkey, Account) { + self.outdate_storage + .account_with_pubkey(program_id, rent, self.address) + } + } + + struct ActualBalance { + pub address: Address, + pub chain_id: u64, + pub balance: U256, + pub nonce: u64, + } + + impl ActualBalance { + pub fn account_with_pubkey(&self, program_id: &Pubkey, rent: &Rent) -> (Pubkey, Account) { + let (pubkey, _) = self + .address + .find_balance_address(&program_id, self.chain_id); + let mut account_data = AccountData::new(pubkey); + account_data.assign(*program_id).unwrap(); + account_data.expand(BalanceAccount::required_account_size()); + account_data.lamports = rent.minimum_balance(account_data.get_length()); + + let mut balance = BalanceAccount::initialize( + account_data.into_account_info(), + program_id, + self.address, + self.chain_id, + ) + .unwrap(); + balance.mint(self.balance).unwrap(); + balance.increment_nonce_by(self.nonce).unwrap(); + + ( + pubkey, + Account { + lamports: rent.minimum_balance(account_data.get_length()), + data: account_data.data().to_vec(), + owner: *program_id, + executable: false, + rent_epoch: 0, + }, + ) + } + } + + struct ActualContract { + pub address: Address, + pub chain_id: u64, + pub generation: u32, + pub code: &'static [u8], + pub storage: [[u8; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT], + + pub actual_storage: ActualStorage, + pub legacy_storage: LegacyStorage, + pub outdate_storage: LegacyStorage, + } + + impl ActualContract { + pub fn account_with_pubkey(&self, program_id: &Pubkey, rent: &Rent) -> (Pubkey, Account) { + let (pubkey, _) = self.address.find_solana_address(&program_id); + let mut account_data = AccountData::new(pubkey); + account_data.assign(*program_id).unwrap(); + account_data.expand(ContractAccount::required_account_size(self.code)); + account_data.lamports = rent.minimum_balance(account_data.get_length()); + + let mut contract = ContractAccount::initialize( + account_data.into_account_info(), + program_id, + self.address, + self.chain_id, + self.generation, + self.code, + ) + .unwrap(); + contract.set_storage_multiple_values(0, &self.storage); + + ( + pubkey, + Account { + lamports: rent.minimum_balance(account_data.get_length()), + data: account_data.data().to_vec(), + owner: *program_id, + executable: false, + rent_epoch: 0, + }, + ) + } + + pub fn actual_storage_with_pubkey( + &self, + program_id: &Pubkey, + rent: &Rent, + ) -> (Pubkey, Account) { + self.actual_storage + .account_with_pubkey(program_id, rent, self.address) + } + + pub fn legacy_storage_with_pubkey( + &self, + program_id: &Pubkey, + rent: &Rent, + ) -> (Pubkey, Account) { + self.legacy_storage + .account_with_pubkey(program_id, rent, self.address) + } + + pub fn outdate_storage_with_pubkey( + &self, + program_id: &Pubkey, + rent: &Rent, + ) -> (Pubkey, Account) { + self.outdate_storage + .account_with_pubkey(program_id, rent, self.address) + } + } + + const LEGACY_CHAIN_ID: u64 = 1; + const EXTRA_CHAIN_ID: u64 = 2; + const MISSING_ADDRESS: Address = Address(hex!("7a250d5630b4cf539739df2c5dacb4c659f24800")); + + const MISSING_STORAGE_INDEX: U256 = U256::new(1 * 256u128); + const ACTUAL_STORAGE_INDEX: U256 = U256::new(2 * 256u128); + const LEGACY_STORAGE_INDEX: U256 = U256::new(3 * 256u128); + const OUTDATE_STORAGE_INDEX: U256 = U256::new(4 * 256u128); + + const ACTUAL_BALANCE: ActualBalance = ActualBalance { + address: Address(hex!("7a250d5630b4cf539739df2c5dacb4c659f24810")), + chain_id: LEGACY_CHAIN_ID, + balance: U256::new(1513), + nonce: 41, + }; + + const ACTUAL_BALANCE2: ActualBalance = ActualBalance { + address: Address(hex!("7a250d5630b4cf539739df2c5dacb4c659f24811")), + chain_id: EXTRA_CHAIN_ID, + balance: U256::new(5134), + nonce: 14, + }; + + const ACTUAL_CONTRACT: ActualContract = ActualContract { + address: Address(hex!("7a250d5630b4cf539739df2c5dacb4c659f24c11")), + chain_id: LEGACY_CHAIN_ID, + generation: 4, + code: &[0x03, 0x04, 0x05], + storage: [[14u8; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT], + actual_storage: ActualStorage { + index: ACTUAL_STORAGE_INDEX, + values: &[(0u8, [64u8; 32])], + }, + legacy_storage: LegacyStorage { + generation: 4, + index: LEGACY_STORAGE_INDEX, + values: &[(0u8, [54u8; 32])], + }, + outdate_storage: LegacyStorage { + generation: 3, + index: OUTDATE_STORAGE_INDEX, + values: &[(0u8, [34u8; 32])], + }, + }; + + const ACTUAL_SUICIDE: ActualContract = ActualContract { + address: Address(hex!("7a250d5630b4cf539739df2c5dacb4c659f24d10")), + chain_id: LEGACY_CHAIN_ID, + generation: 12, + code: &[], + storage: [[0u8; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT], // It's matter that suicide contract doesn't contains any values in storage! + actual_storage: ActualStorage { + index: U256::ZERO, + values: &[], + }, + legacy_storage: LegacyStorage { + generation: 0, + index: U256::ZERO, + values: &[], + }, + outdate_storage: LegacyStorage { + generation: 11, + index: LEGACY_STORAGE_INDEX, + values: &[(0u8, [13u8; 32])], + }, + }; + + const LEGACY_ACCOUNT: LegacyAccount = LegacyAccount { + address: Address(hex!("7a250d5630b4cf539739df2c5dacb4c659f24820")), + balance: U256::new(10234), + nonce: 123, + }; + + const LEGACY_CONTRACT: LegacyContract = LegacyContract { + address: Address(hex!("7a250d5630b4cf539739df2c5dacb4c659f24c21")), + balance: U256::new(6153), + nonce: 1, + generation: 3, + code: &[0x01, 0x02, 0x03], + storage: [[0u8; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT], + + legacy_storage: LegacyStorage { + generation: 3, + index: LEGACY_STORAGE_INDEX, + values: &[(0u8, [23u8; 32])], + }, + outdate_storage: LegacyStorage { + generation: 2, + index: OUTDATE_STORAGE_INDEX, + values: &[(0u8, [43u8; 32])], + }, + }; + + const LEGACY_CONTRACT_NO_BALANCE: LegacyContract = LegacyContract { + address: Address(hex!("7a250d5630b4cf539739df2c5dacb4c659f24c20")), + balance: U256::ZERO, + nonce: 0, + generation: 2, + code: &[0x01, 0x02, 0x03, 0x04], + storage: [[53u8; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT], + legacy_storage: LegacyStorage { + generation: 0, + index: U256::ZERO, + values: &[], + }, + outdate_storage: LegacyStorage { + generation: 1, + index: U256::ZERO, + values: &[], + }, + }; + + const LEGACY_SUICIDE: LegacyContract = LegacyContract { + address: Address(hex!("7a250d5630b4cf539739df2c5dacb4c659f24d21")), + balance: U256::new(41234), + nonce: 413, + generation: 5, + code: &[], + storage: [[42u8; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT], + + legacy_storage: LegacyStorage { + generation: 413, + index: LEGACY_STORAGE_INDEX, + values: &[(0u8, [65u8; 32])], + }, + outdate_storage: LegacyStorage { + generation: 412, + index: OUTDATE_STORAGE_INDEX, + values: &[(0u8, [76u8; 32])], + }, + }; + + struct Fixture { + program_id: Pubkey, + chains: Vec, + rent: Rent, + mock_rpc: mock_rpc_client::MockRpcClient, + block_overrides: Option, + state_overrides: Option>, + solana_overrides: Option, + } + + impl Fixture { + pub async fn new() -> Self { + let rent = Rent::default(); + let program_id = + Pubkey::from_str("53DfF883gyixYNXnM7s5xhdeyV8mVk9T4i2hGV9vG9io").unwrap(); + let accounts = vec![ + ( + Pubkey::from_str("SysvarRent111111111111111111111111111111111").unwrap(), + Account { + lamports: 1009200, + data: bincode::serialize(&rent).unwrap(), + owner: Pubkey::from_str("Sysvar1111111111111111111111111111111111111") + .unwrap(), + executable: false, + rent_epoch: 0, + }, + ), + ACTUAL_BALANCE.account_with_pubkey(&program_id, &rent), + ACTUAL_BALANCE2.account_with_pubkey(&program_id, &rent), + LEGACY_ACCOUNT.account_with_pubkey(&program_id, &rent), + ACTUAL_CONTRACT.account_with_pubkey(&program_id, &rent), + ACTUAL_CONTRACT.actual_storage_with_pubkey(&program_id, &rent), + ACTUAL_CONTRACT.legacy_storage_with_pubkey(&program_id, &rent), + ACTUAL_CONTRACT.outdate_storage_with_pubkey(&program_id, &rent), + ACTUAL_SUICIDE.account_with_pubkey(&program_id, &rent), + ACTUAL_SUICIDE.outdate_storage_with_pubkey(&program_id, &rent), + LEGACY_CONTRACT.account_with_pubkey(&program_id, &rent), + LEGACY_CONTRACT.legacy_storage_with_pubkey(&program_id, &rent), + LEGACY_CONTRACT.outdate_storage_with_pubkey(&program_id, &rent), + LEGACY_CONTRACT_NO_BALANCE.account_with_pubkey(&program_id, &rent), + LEGACY_SUICIDE.account_with_pubkey(&program_id, &rent), + LEGACY_SUICIDE.outdate_storage_with_pubkey(&program_id, &rent), + ]; + + let rpc_client = mock_rpc_client::MockRpcClient::new(&accounts); + + Self { + program_id, + chains: vec![ + ChainInfo { + id: LEGACY_CHAIN_ID, + name: "neon".to_string(), + token: Pubkey::new_unique(), + }, + ChainInfo { + id: EXTRA_CHAIN_ID, + name: "usdt".to_string(), + token: Pubkey::new_unique(), + }, + ], + rent, + mock_rpc: rpc_client, + block_overrides: None, + state_overrides: None, + solana_overrides: None, + } + } + + pub async fn build_account_storage( + &self, + ) -> EmulatorAccountStorage<'_, mock_rpc_client::MockRpcClient> { + EmulatorAccountStorage::new( + &self.mock_rpc, + self.program_id, + Some(self.chains.clone()), + self.block_overrides.clone(), + self.state_overrides.clone(), + self.solana_overrides.clone(), + ) + .await + .unwrap() + } + + pub fn balance_pubkey(&self, address: Address, chain_id: u64) -> Pubkey { + address.find_balance_address(&self.program_id, chain_id).0 + } + + pub fn legacy_pubkey(&self, address: Address) -> Pubkey { + address.find_solana_address(&self.program_id).0 + } + + pub fn contract_pubkey(&self, address: Address) -> Pubkey { + address.find_solana_address(&self.program_id).0 + } + + pub fn storage_pubkey(&self, address: Address, index: U256) -> Pubkey { + if index < U256::new(STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT as u128) { + self.contract_pubkey(address) + } else { + let index = index & !U256::new(0xFF); + let base = self.contract_pubkey(address); + let cell_address = StorageCellAddress::new(&self.program_id, &base, &index); + *cell_address.pubkey() + } + } + + pub fn storage_rent(&self, count: usize) -> u64 { + self.rent + .minimum_balance(StorageCell::required_account_size(count)) + } + + pub fn legacy_storage_rent(&self, count: usize) -> u64 { + self.rent + .minimum_balance(LegacyStorage::required_account_size(count)) + } + + pub fn balance_rent(&self) -> u64 { + self.rent + .minimum_balance(BalanceAccount::required_account_size()) + } + + pub fn legacy_rent(&self, code_len: Option) -> u64 { + let data_length = code_len + .map(|len| { + 1 + LegacyEtherData::SIZE + 32 * STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT + len + }) + .unwrap_or(1 + LegacyEtherData::SIZE); + self.rent.minimum_balance(data_length) + } + + pub fn contract_rent(&self, code: &[u8]) -> u64 { + self.rent + .minimum_balance(ContractAccount::required_account_size(code)) + } + } + + impl<'rpc, T: Rpc> EmulatorAccountStorage<'rpc, T> { + pub fn verify_used_accounts(&self, expected: &[(Pubkey, bool, bool)]) { + let mut expected = expected.to_vec(); + expected.sort_by_key(|(k, _, _)| *k); + let mut actual = self + .used_accounts() + .iter() + .map(|v| (v.pubkey, v.is_writable, v.is_legacy)) + .collect::>(); + actual.sort_by_key(|(k, _, _)| *k); + assert_eq!(actual, expected); + } + + pub fn verify_upgrade_rent(&self, added_rent: u64, removed_rent: u64) { + assert_eq!( + self.get_upgrade_rent().unwrap(), + added_rent.saturating_sub(removed_rent) + ); + } + + pub fn verify_regular_rent(&self, added_rent: u64, removed_rent: u64) { + assert_eq!( + self.get_regular_rent().unwrap(), + added_rent.saturating_sub(removed_rent) + ); + } + } + + #[tokio::test] + async fn test_read_balance_missing_account() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + assert_eq!( + storage.balance(MISSING_ADDRESS, LEGACY_CHAIN_ID).await, + U256::ZERO + ); + assert_eq!(storage.nonce(MISSING_ADDRESS, LEGACY_CHAIN_ID).await, 0); + + storage.verify_used_accounts(&[ + ( + fixture.balance_pubkey(MISSING_ADDRESS, LEGACY_CHAIN_ID), + false, + false, + ), + (fixture.legacy_pubkey(MISSING_ADDRESS), false, false), + ]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(0, 0); + } + + #[tokio::test] + async fn test_read_balance_missing_account_extra_chain() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + assert_eq!( + storage.balance(MISSING_ADDRESS, EXTRA_CHAIN_ID).await, + U256::ZERO + ); + assert_eq!(storage.nonce(MISSING_ADDRESS, EXTRA_CHAIN_ID).await, 0); + + storage.verify_used_accounts(&[( + fixture.balance_pubkey(MISSING_ADDRESS, EXTRA_CHAIN_ID), + false, + false, + )]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(0, 0); + } + + #[tokio::test] + async fn test_read_balance_actual_account() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + let acc = &ACTUAL_BALANCE; + assert_eq!( + storage.balance(acc.address, acc.chain_id).await, + acc.balance + ); + assert_eq!(storage.nonce(acc.address, acc.chain_id).await, acc.nonce); + + storage.verify_used_accounts(&[( + fixture.balance_pubkey(acc.address, acc.chain_id), + false, + false, + )]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(0, 0); + } + + #[tokio::test] + async fn test_read_balance_actual_account_extra_chain() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + let acc = &ACTUAL_BALANCE2; + assert_eq!(acc.chain_id, EXTRA_CHAIN_ID); + assert_eq!( + storage.balance(acc.address, acc.chain_id).await, + acc.balance + ); + assert_eq!(storage.nonce(acc.address, acc.chain_id).await, acc.nonce); + + storage.verify_used_accounts(&[( + fixture.balance_pubkey(acc.address, acc.chain_id), + false, + false, + )]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(0, 0); + } + + #[tokio::test] + async fn test_read_balance_legacy_account() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + let acc = &LEGACY_ACCOUNT; + assert_eq!( + storage.balance(acc.address, LEGACY_CHAIN_ID).await, + acc.balance + ); + assert_eq!(storage.nonce(acc.address, LEGACY_CHAIN_ID).await, acc.nonce); + + storage.verify_used_accounts(&[ + ( + fixture.balance_pubkey(acc.address, LEGACY_CHAIN_ID), + true, + true, + ), + (fixture.legacy_pubkey(acc.address), true, true), + ]); + storage.verify_upgrade_rent(fixture.balance_rent(), fixture.legacy_rent(None)); + storage.verify_regular_rent(0, 0); + } + + #[tokio::test] + async fn test_modify_actual_and_missing_account() { + let fixture = Fixture::new().await; + let mut storage = fixture.build_account_storage().await; + + let from = &ACTUAL_BALANCE; + let amount = U256::new(10); + assert_eq!(from.chain_id, LEGACY_CHAIN_ID); + assert_eq!( + storage + .transfer(from.address, MISSING_ADDRESS, from.chain_id, amount) + .await + .is_ok(), + true + ); + + storage.verify_used_accounts(&[ + ( + fixture.balance_pubkey(from.address, from.chain_id), + true, + false, + ), + ( + fixture.balance_pubkey(MISSING_ADDRESS, LEGACY_CHAIN_ID), + true, + false, + ), + (fixture.legacy_pubkey(MISSING_ADDRESS), false, false), + ]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(fixture.balance_rent(), 0); + + assert_eq!( + storage.balance(from.address, from.chain_id).await, + from.balance - amount + ); + assert_eq!( + storage.balance(MISSING_ADDRESS, LEGACY_CHAIN_ID).await, + amount + ); + } + + #[tokio::test] + async fn test_modify_actual_and_missing_account_extra_chain() { + let fixture = Fixture::new().await; + let mut storage = fixture.build_account_storage().await; + + let from = &ACTUAL_BALANCE2; + let amount = U256::new(11); + assert_eq!(from.chain_id, EXTRA_CHAIN_ID); + assert_eq!( + storage + .transfer(from.address, MISSING_ADDRESS, from.chain_id, amount) + .await + .is_ok(), + true + ); + + storage.verify_used_accounts(&[ + ( + fixture.balance_pubkey(from.address, from.chain_id), + true, + false, + ), + ( + fixture.balance_pubkey(MISSING_ADDRESS, from.chain_id), + true, + false, + ), + ]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(fixture.balance_rent(), 0); + + assert_eq!( + storage.balance(from.address, from.chain_id).await, + from.balance - amount + ); + assert_eq!( + storage.balance(MISSING_ADDRESS, from.chain_id).await, + amount + ); + } + + #[tokio::test] + async fn test_modify_actual_and_legacy_account() { + let fixture = Fixture::new().await; + let mut storage = fixture.build_account_storage().await; + + let from = &ACTUAL_BALANCE; + let to = &LEGACY_ACCOUNT; + let amount = U256::new(10); + assert_eq!(from.chain_id, LEGACY_CHAIN_ID); + assert_eq!( + storage + .transfer(from.address, to.address, from.chain_id, amount) + .await + .is_ok(), + true + ); + + storage.verify_used_accounts(&[ + ( + fixture.balance_pubkey(from.address, from.chain_id), + true, + false, + ), + ( + fixture.balance_pubkey(to.address, LEGACY_CHAIN_ID), + true, + true, + ), + (fixture.legacy_pubkey(to.address), true, true), + ]); + storage.verify_upgrade_rent(fixture.balance_rent(), fixture.legacy_rent(None)); + storage.verify_regular_rent(0, 0); + + assert_eq!( + storage.balance(from.address, from.chain_id).await, + from.balance - amount + ); + assert_eq!( + storage.balance(to.address, LEGACY_CHAIN_ID).await, + to.balance + amount + ); + } + + #[tokio::test] + async fn test_read_missing_contract() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + assert_eq!(*storage.code(MISSING_ADDRESS).await, [0u8; 0]); + assert_eq!( + storage.storage(MISSING_ADDRESS, U256::ZERO).await, + [0u8; 32] + ); + storage.verify_used_accounts(&[(fixture.contract_pubkey(MISSING_ADDRESS), false, false)]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(0, 0); + + assert_eq!( + storage + .storage( + MISSING_ADDRESS, + U256::new(STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT as u128) + ) + .await, + [0u8; 32] + ); + } + + #[tokio::test] + async fn test_read_legacy_contract() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + assert_eq!( + *storage.code(LEGACY_CONTRACT.address).await, + *LEGACY_CONTRACT.code + ); + assert_eq!( + storage.storage(LEGACY_CONTRACT.address, U256::ZERO).await, + [0u8; 32] + ); + storage.verify_used_accounts(&[ + ( + fixture.balance_pubkey(LEGACY_CONTRACT.address, LEGACY_CHAIN_ID), + true, + true, + ), + (fixture.contract_pubkey(LEGACY_CONTRACT.address), true, true), + ]); + storage.verify_upgrade_rent( + fixture.balance_rent() + fixture.contract_rent(LEGACY_CONTRACT.code), + fixture.legacy_rent(Some(LEGACY_CONTRACT.code.len())), + ); + storage.verify_regular_rent(0, 0); + } + + #[tokio::test] + async fn test_read_legacy_contract_no_balance() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + let contract = &LEGACY_CONTRACT_NO_BALANCE; + assert_eq!(*storage.code(contract.address).await, *contract.code); + assert_eq!( + storage.storage(contract.address, U256::ZERO).await, + [53u8; 32] + ); + storage.verify_used_accounts(&[ + ( + fixture.balance_pubkey(contract.address, LEGACY_CHAIN_ID), + false, + true, + ), + (fixture.contract_pubkey(contract.address), true, true), + ]); + storage.verify_upgrade_rent( + fixture.contract_rent(contract.code), + fixture.legacy_rent(Some(contract.code.len())), + ); + storage.verify_regular_rent(0, 0); + } + + #[tokio::test] + async fn test_read_actual_suicide_contract() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + let contract = &ACTUAL_SUICIDE; + assert_eq!(*storage.code(contract.address).await, [0u8; 0]); + assert_eq!( + storage.storage(contract.address, U256::ZERO).await, + [0u8; 32] + ); + storage.verify_used_accounts(&[(fixture.contract_pubkey(contract.address), false, false)]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(0, 0); + } + + #[tokio::test] + async fn test_read_legacy_suicide_contract() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + let contract = &LEGACY_SUICIDE; + assert_eq!(*storage.code(contract.address).await, [0u8; 0]); + assert_eq!( + storage.storage(contract.address, U256::ZERO).await, + [0u8; 32] + ); + storage.verify_used_accounts(&[ + ( + fixture.balance_pubkey(contract.address, LEGACY_CHAIN_ID), + true, + true, + ), + (fixture.contract_pubkey(contract.address), true, true), + ]); + storage.verify_upgrade_rent( + fixture.balance_rent() + fixture.contract_rent(contract.code), + fixture.legacy_rent(Some(contract.code.len())), + ); + storage.verify_regular_rent(0, 0); + } + + #[tokio::test] + async fn test_deploy_at_missing_contract() { + let fixture = Fixture::new().await; + let mut storage = fixture.build_account_storage().await; + + let code = hex!("14643165").to_vec(); + assert_eq!( + storage + .set_code(MISSING_ADDRESS, LEGACY_CHAIN_ID, code.clone()) + .await + .is_ok(), + true + ); + storage.verify_used_accounts(&[(fixture.contract_pubkey(MISSING_ADDRESS), true, false)]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(fixture.contract_rent(&code), 0); + } + + #[tokio::test] + async fn test_deploy_at_actual_balance() { + let fixture = Fixture::new().await; + let mut storage = fixture.build_account_storage().await; + + let code = hex!("14643165").to_vec(); + let acc = &ACTUAL_BALANCE; + assert_eq!( + storage + .set_code(acc.address, LEGACY_CHAIN_ID, code.clone()) + .await + .is_ok(), + true + ); + storage.verify_used_accounts(&[(fixture.contract_pubkey(acc.address), true, false)]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(fixture.contract_rent(&code), 0); + } + + #[tokio::test] + async fn test_deploy_at_actual_contract() { + let fixture = Fixture::new().await; + let mut storage = fixture.build_account_storage().await; + + let code = hex!("62345987").to_vec(); + let contract = &ACTUAL_CONTRACT; + assert_eq!( + storage + .set_code(contract.address, LEGACY_CHAIN_ID, code) + .await + .unwrap_err() + .to_string(), + EvmLoaderError::AccountAlreadyInitialized(fixture.contract_pubkey(contract.address)) + .to_string() + ); + storage.verify_used_accounts(&[(fixture.contract_pubkey(contract.address), false, false)]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(0, 0); + } + + #[tokio::test] + async fn test_deploy_at_legacy_account() { + let fixture = Fixture::new().await; + let mut storage = fixture.build_account_storage().await; + + let code = hex!("37455846").to_vec(); + let contract = &LEGACY_ACCOUNT; + assert_eq!( + storage + .set_code(contract.address, LEGACY_CHAIN_ID, code.clone()) + .await + .is_ok(), + true + ); + storage.verify_used_accounts(&[ + ( + fixture.balance_pubkey(contract.address, LEGACY_CHAIN_ID), + true, + true, + ), + (fixture.contract_pubkey(contract.address), true, true), + ]); + storage.verify_upgrade_rent(fixture.balance_rent(), fixture.legacy_rent(None)); + storage.verify_regular_rent(fixture.contract_rent(&code), 0); + } + + #[tokio::test] + async fn test_deploy_at_legacy_contract() { + let fixture = Fixture::new().await; + let mut storage = fixture.build_account_storage().await; + + let code = hex!("13412971").to_vec(); + let contract = &LEGACY_CONTRACT; + assert_eq!( + storage + .set_code(contract.address, LEGACY_CHAIN_ID, code) + .await + .unwrap_err() + .to_string(), + EvmLoaderError::AccountAlreadyInitialized(fixture.contract_pubkey(contract.address)) + .to_string() + ); + storage.verify_used_accounts(&[ + ( + fixture.balance_pubkey(contract.address, LEGACY_CHAIN_ID), + true, + true, + ), + (fixture.contract_pubkey(contract.address), true, true), + ]); + storage.verify_upgrade_rent( + fixture.balance_rent() + fixture.contract_rent(contract.code), + fixture.legacy_rent(Some(contract.code.len())), + ); + storage.verify_regular_rent(0, 0); + } + + #[tokio::test] + async fn test_deploy_at_actual_suicide() { + let fixture = Fixture::new().await; + let mut storage = fixture.build_account_storage().await; + + let code = hex!("13412971").to_vec(); + let contract = &ACTUAL_SUICIDE; + // TODO: Should we deploy new contract by the previous address? + assert_eq!( + storage + .set_code(contract.address, LEGACY_CHAIN_ID, code.clone()) + .await + .is_ok(), + true, + ); + storage.verify_used_accounts(&[(fixture.contract_pubkey(contract.address), true, false)]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent( + fixture.contract_rent(&code), + fixture.contract_rent(contract.code), + ); + } + + #[tokio::test] + async fn test_deploy_at_legacy_suicide() { + let fixture = Fixture::new().await; + let mut storage = fixture.build_account_storage().await; + + let code = hex!("13412971").to_vec(); + let contract = &LEGACY_SUICIDE; + // TODO: Should we deploy new contract by the previous address? + assert_eq!( + storage + .set_code(contract.address, LEGACY_CHAIN_ID, code.clone()) + .await + .is_ok(), + true, + ); + storage.verify_used_accounts(&[ + ( + fixture.balance_pubkey(contract.address, LEGACY_CHAIN_ID), + true, + true, + ), + (fixture.contract_pubkey(contract.address), true, true), + ]); + storage.verify_upgrade_rent( + fixture.balance_rent() + fixture.contract_rent(&contract.code), + fixture.legacy_rent(Some(contract.code.len())), + ); + storage.verify_regular_rent( + fixture.contract_rent(&code), + fixture.contract_rent(&contract.code), + ); + } + + #[tokio::test] + async fn test_read_missing_storage_for_missing_contract() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + assert_eq!( + storage + .storage(MISSING_ADDRESS, MISSING_STORAGE_INDEX) + .await, + [0u8; 32] + ); + storage.verify_used_accounts(&[( + fixture.storage_pubkey(MISSING_ADDRESS, MISSING_STORAGE_INDEX), + false, + false, + )]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(0, 0); + } + + #[tokio::test] + async fn test_read_missing_storage_for_actual_contract() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + let contract = &ACTUAL_CONTRACT; + assert_eq!( + storage + .storage(contract.address, MISSING_STORAGE_INDEX) + .await, + [0u8; 32] + ); + storage.verify_used_accounts(&[( + fixture.storage_pubkey(contract.address, MISSING_STORAGE_INDEX), + false, + false, + )]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(0, 0); + } + + #[tokio::test] + async fn test_read_actual_storage_for_actual_contract() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + let contract = &ACTUAL_CONTRACT; + assert_eq!( + storage + .storage(contract.address, ACTUAL_STORAGE_INDEX) + .await, + contract.actual_storage.values[0].1 + ); + storage.verify_used_accounts(&[( + fixture.storage_pubkey(contract.address, ACTUAL_STORAGE_INDEX), + false, + false, + )]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(0, 0); + } + + #[tokio::test] + async fn test_modify_new_storage_for_actual_contract() { + let fixture = Fixture::new().await; + let mut storage = fixture.build_account_storage().await; + + let contract = &ACTUAL_CONTRACT; + assert_eq!( + storage + .storage(contract.address, ACTUAL_STORAGE_INDEX + 1) + .await, + [0u8; 32] + ); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(0, 0); + + let new_value = [0x01u8; 32]; + assert_eq!( + storage + .set_storage( + contract.address, + ACTUAL_STORAGE_INDEX + 1, + new_value.clone() + ) + .await + .is_ok(), + true + ); + assert_eq!( + storage + .storage(contract.address, ACTUAL_STORAGE_INDEX + 1) + .await, + new_value + ); + storage.verify_used_accounts(&[( + fixture.storage_pubkey(contract.address, ACTUAL_STORAGE_INDEX), + true, + false, + )]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(fixture.storage_rent(2), fixture.storage_rent(1)); + } + + #[tokio::test] + async fn test_modify_missing_storage_for_actual_contract() { + let fixture = Fixture::new().await; + let mut storage = fixture.build_account_storage().await; + + let contract = &ACTUAL_CONTRACT; + let new_value = [0x02u8; 32]; + assert_eq!( + storage + .set_storage(contract.address, MISSING_STORAGE_INDEX, new_value.clone()) + .await + .is_ok(), + true + ); + assert_eq!( + storage + .storage(contract.address, MISSING_STORAGE_INDEX) + .await, + new_value + ); + storage.verify_used_accounts(&[( + fixture.storage_pubkey(contract.address, MISSING_STORAGE_INDEX), + true, + false, + )]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(fixture.storage_rent(1), 0); + } + + #[tokio::test] + async fn test_modify_internal_storage_for_actual_contract() { + let fixture = Fixture::new().await; + let mut storage = fixture.build_account_storage().await; + + let contract = &ACTUAL_CONTRACT; + let new_value = [0x03u8; 32]; + let index = U256::new(0); + assert_eq!( + storage + .set_storage(contract.address, index, new_value.clone()) + .await + .is_ok(), + true + ); + assert_eq!(storage.storage(contract.address, index).await, new_value); + storage.verify_used_accounts(&[(fixture.contract_pubkey(contract.address), true, false)]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(0, 0); + } + + #[tokio::test] + async fn test_read_legacy_storage_for_actual_contract() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + let contract = &ACTUAL_CONTRACT; + assert_eq!( + storage + .storage(contract.address, LEGACY_STORAGE_INDEX) + .await, + contract.legacy_storage.values[0].1 + ); + storage.verify_used_accounts(&[ + (fixture.contract_pubkey(contract.address), false, true), + ( + fixture.storage_pubkey(contract.address, LEGACY_STORAGE_INDEX), + true, + true, + ), + ]); + storage.verify_upgrade_rent(fixture.storage_rent(1), fixture.legacy_storage_rent(1)); + storage.verify_regular_rent(0, 0); + } + + #[tokio::test] + async fn test_read_outdate_storage_for_actual_contract() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + let contract = &ACTUAL_CONTRACT; + assert_eq!( + storage + .storage(contract.address, OUTDATE_STORAGE_INDEX) + .await, + [0u8; 32] + ); + storage.verify_used_accounts(&[ + (fixture.contract_pubkey(contract.address), false, true), + ( + fixture.storage_pubkey(contract.address, OUTDATE_STORAGE_INDEX), + true, + true, + ), + ]); + storage.verify_upgrade_rent(0, fixture.legacy_storage_rent(1)); + storage.verify_regular_rent(0, 0); + } + + #[tokio::test] + async fn test_read_missing_storage_for_legacy_contract() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + let contract = &LEGACY_CONTRACT; + assert_eq!( + storage + .storage(contract.address, MISSING_STORAGE_INDEX) + .await, + [0u8; 32] + ); + storage.verify_used_accounts(&[( + fixture.storage_pubkey(contract.address, MISSING_STORAGE_INDEX), + false, + false, + )]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(0, 0); + } + + #[tokio::test] + async fn test_read_legacy_storage_for_legacy_contract() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + let contract = &LEGACY_CONTRACT; + assert_eq!( + storage + .storage(contract.address, LEGACY_STORAGE_INDEX) + .await, + contract.legacy_storage.values[0].1 + ); + storage.verify_used_accounts(&[ + (fixture.contract_pubkey(contract.address), true, true), + ( + fixture.balance_pubkey(contract.address, LEGACY_CHAIN_ID), + true, + true, + ), + ( + fixture.storage_pubkey(contract.address, LEGACY_STORAGE_INDEX), + true, + true, + ), + ]); + storage.verify_upgrade_rent( + fixture.balance_rent() + fixture.contract_rent(contract.code) + fixture.storage_rent(1), + fixture.legacy_storage_rent(1) + fixture.legacy_rent(Some(contract.code.len())), + ); + storage.verify_regular_rent(0, 0); + } + + #[tokio::test] + async fn test_read_outdate_storage_for_legacy_contract() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + let contract = &LEGACY_CONTRACT; + assert_eq!( + storage + .storage(contract.address, OUTDATE_STORAGE_INDEX) + .await, + [0u8; 32] + ); + storage.verify_used_accounts(&[ + (fixture.contract_pubkey(contract.address), true, true), + ( + fixture.balance_pubkey(contract.address, LEGACY_CHAIN_ID), + true, + true, + ), + ( + fixture.storage_pubkey(contract.address, OUTDATE_STORAGE_INDEX), + true, + true, + ), + ]); + storage.verify_upgrade_rent( + fixture.balance_rent() + fixture.contract_rent(contract.code), + fixture.legacy_storage_rent(1) + fixture.legacy_rent(Some(contract.code.len())), + ); + storage.verify_regular_rent(0, 0); + } + + #[tokio::test] + async fn test_read_missing_storage_for_legacy_suicide() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + let contract = &LEGACY_SUICIDE; + assert_eq!( + storage + .storage(contract.address, MISSING_STORAGE_INDEX) + .await, + [0u8; 32] + ); + storage.verify_used_accounts(&[( + fixture.storage_pubkey(contract.address, MISSING_STORAGE_INDEX), + false, + false, + )]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(0, 0); + } + + #[tokio::test] + async fn test_read_outdate_storage_for_legacy_suicide() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + let contract = &LEGACY_SUICIDE; + assert_eq!( + storage + .storage(contract.address, OUTDATE_STORAGE_INDEX) + .await, + [0u8; 32] + ); + storage.verify_used_accounts(&[ + (fixture.contract_pubkey(contract.address), true, true), + ( + fixture.balance_pubkey(contract.address, LEGACY_CHAIN_ID), + true, + true, + ), + ( + fixture.storage_pubkey(contract.address, OUTDATE_STORAGE_INDEX), + true, + true, + ), + ]); + storage.verify_upgrade_rent( + fixture.balance_rent() + fixture.contract_rent(contract.code), + fixture.legacy_storage_rent(1) + fixture.legacy_rent(Some(contract.code.len())), + ); + storage.verify_regular_rent(0, 0); + } +} diff --git a/evm_loader/lib/src/commands/emulate.rs b/evm_loader/lib/src/commands/emulate.rs index 93fc56f16..719b11df3 100644 --- a/evm_loader/lib/src/commands/emulate.rs +++ b/evm_loader/lib/src/commands/emulate.rs @@ -1,33 +1,41 @@ -use evm_loader::account::ContractAccount; -use evm_loader::account_storage::AccountStorage; -use evm_loader::error::build_revert_message; -use log::{debug, info}; -use serde::{Deserialize, Serialize}; -use serde_json::Value; -use solana_sdk::entrypoint::MAX_PERMITTED_DATA_INCREASE; -use solana_sdk::pubkey::Pubkey; - use crate::commands::get_config::BuildConfigSimulator; use crate::rpc::Rpc; use crate::tracing::tracers::Tracer; use crate::types::{EmulateRequest, TxParams}; use crate::{ - account_storage::{EmulatorAccountStorage, SolanaAccount}, + account_storage::{EmulatorAccountStorage, SyncedAccountStorage}, errors::NeonError, NeonResult, }; +use evm_loader::account_storage::AccountStorage; +use evm_loader::error::build_revert_message; use evm_loader::{ config::{EVM_STEPS_MIN, PAYMENT_TO_TREASURE}, evm::{ExitStatus, Machine}, - executor::{Action, ExecutorState}, + executor::SyncedExecutorState, gasometer::LAMPORTS_PER_SIGNATURE, }; -use serde_with::{hex::Hex, serde_as}; +use log::{debug, info}; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use serde_with::{hex::Hex, serde_as, DisplayFromStr}; +use solana_sdk::{account::Account, pubkey::Pubkey}; +#[serde_as] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SolanaAccount { + #[serde_as(as = "DisplayFromStr")] + pub pubkey: Pubkey, + pub is_writable: bool, + pub is_legacy: bool, +} #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] pub struct EmulateResponse { pub exit_status: String, + pub external_solana_call: bool, + pub reverts_before_solana_calls: bool, + pub reverts_after_solana_calls: bool, #[serde_as(as = "Hex")] pub result: Vec, pub steps_executed: u64, @@ -42,6 +50,9 @@ impl EmulateResponse { let exit_status = ExitStatus::Revert(revert_message); Self { exit_status: exit_status.to_string(), + external_solana_call: false, + reverts_before_solana_calls: false, + reverts_after_solana_calls: false, result: exit_status.into_result().unwrap_or_default(), steps_executed: 0, used_gas: 0, @@ -66,6 +77,13 @@ pub async fn execute( .as_ref() .and_then(|t| t.state_overrides.clone()); + let solana_overrides = emulate_request.solana_overrides.map(|overrides| { + overrides + .iter() + .map(|(pubkey, account)| (*pubkey, account.as_ref().map(Account::from))) + .collect() + }); + let mut storage = EmulatorAccountStorage::with_accounts( rpc, program_id, @@ -73,12 +91,60 @@ pub async fn execute( emulate_request.chains, block_overrides, state_overrides, + solana_overrides, ) .await?; - let step_limit = emulate_request.step_limit.unwrap_or(100_000); + let step_limit = emulate_request.step_limit.unwrap_or(100000); + + let result = emulate_trx(emulate_request.tx.clone(), &mut storage, step_limit, tracer).await?; + + if storage.is_timestamp_used() { + let mut storage2 = EmulatorAccountStorage::new_from_other(&storage, 5, 3); + if let Ok(result2) = emulate_trx( + emulate_request.tx, + &mut storage2, + step_limit, + Option::::None, + ) + .await + { + let response = &result.0; + let response2 = &result2.0; + + let mut combined_solana_accounts = response.solana_accounts.clone(); + response2.solana_accounts.iter().for_each(|v| { + if let Some(w) = combined_solana_accounts + .iter_mut() + .find(|x| x.pubkey == v.pubkey) + { + w.is_writable |= v.is_writable; + w.is_legacy |= v.is_legacy; + } else { + combined_solana_accounts.push(v.clone()); + } + }); + + let emul_response = EmulateResponse { + // We get the result from the first response (as it is executed on the current time) + result: response.result.clone(), + exit_status: response.exit_status.to_string(), + external_solana_call: response.external_solana_call, + reverts_before_solana_calls: response.reverts_before_solana_calls, + reverts_after_solana_calls: response.reverts_after_solana_calls, + + // ...and consumed resources from the both responses (because the real execution can occur in the future) + steps_executed: response.steps_executed.max(response2.steps_executed), + used_gas: response.used_gas.max(response2.used_gas), + iterations: response.iterations.max(response2.iterations), + solana_accounts: combined_solana_accounts, + }; + + return Ok((emul_response, result.1)); + } + } - emulate_trx(emulate_request.tx, &mut storage, step_limit, tracer).await + Ok(result) } async fn emulate_trx( @@ -95,9 +161,9 @@ async fn emulate_trx( info!("tx: {:?}", tx); let chain_id = tx.chain_id().unwrap_or_else(|| storage.default_chain_id()); - storage.use_balance_account(origin, chain_id, true).await?; + storage.increment_nonce(origin, chain_id).await?; - let mut backend = ExecutorState::new(storage); + let mut backend = SyncedExecutorState::new(storage); let mut evm = match Machine::new(&tx, origin, &mut backend, tracer).await { Ok(evm) => evm, Err(e) => return Ok((EmulateResponse::revert(e), None)), @@ -108,29 +174,38 @@ async fn emulate_trx( return Err(NeonError::TooManySteps); } - let actions = backend.into_actions(); - - storage.apply_actions(actions.clone()).await?; - storage.mark_legacy_accounts().await?; - debug!("Execute done, result={exit_status:?}"); debug!("{steps_executed} steps executed"); + let execute_status = storage.execute_status; + let steps_iterations = (steps_executed + (EVM_STEPS_MIN - 1)) / EVM_STEPS_MIN; let treasury_gas = steps_iterations * PAYMENT_TO_TREASURE; let cancel_gas = LAMPORTS_PER_SIGNATURE; let begin_end_iterations = 2; - let iterations: u64 = steps_iterations + begin_end_iterations + realloc_iterations(&actions); + let iterations: u64 = steps_iterations + begin_end_iterations + storage.realloc_iterations; let iterations_gas = iterations * LAMPORTS_PER_SIGNATURE; + let storage_gas = storage.get_changes_in_rent()?; - let used_gas = storage.gas + iterations_gas + treasury_gas + cancel_gas; + let used_gas = storage_gas + iterations_gas + treasury_gas + cancel_gas; - let solana_accounts = storage.accounts.borrow().values().cloned().collect(); + let solana_accounts = storage + .used_accounts() + .iter() + .map(|v| SolanaAccount { + pubkey: v.pubkey, + is_writable: v.is_writable, + is_legacy: v.is_legacy, + }) + .collect::>(); Ok(( EmulateResponse { exit_status: exit_status.to_string(), + external_solana_call: execute_status.external_solana_call, + reverts_before_solana_calls: execute_status.reverts_before_solana_calls, + reverts_after_solana_calls: execute_status.reverts_after_solana_calls, steps_executed, used_gas, solana_accounts, @@ -140,17 +215,3 @@ async fn emulate_trx( tracer.map(|tracer| tracer.into_traces(used_gas)), )) } - -fn realloc_iterations(actions: &[Action]) -> u64 { - let mut result = 0; - - for action in actions { - if let Action::EvmSetCode { code, .. } = action { - let size = ContractAccount::required_account_size(code); - let c = size / MAX_PERMITTED_DATA_INCREASE; - result = std::cmp::max(result, c); - } - } - - result as u64 -} diff --git a/evm_loader/lib/src/commands/get_storage_at.rs b/evm_loader/lib/src/commands/get_storage_at.rs index 24cee229d..29d7ab310 100644 --- a/evm_loader/lib/src/commands/get_storage_at.rs +++ b/evm_loader/lib/src/commands/get_storage_at.rs @@ -17,7 +17,7 @@ pub async fn execute( address: Address, index: U256, ) -> NeonResult { - let value = EmulatorAccountStorage::new(rpc, *program_id, None, None, None) + let value = EmulatorAccountStorage::new(rpc, *program_id, None, None, None, None) .await? .storage(address, index) .await; diff --git a/evm_loader/lib/src/lib.rs b/evm_loader/lib/src/lib.rs index 4e5b8d771..279153337 100644 --- a/evm_loader/lib/src/lib.rs +++ b/evm_loader/lib/src/lib.rs @@ -1,4 +1,5 @@ pub mod abi; +pub mod account_data; pub mod account_storage; pub mod build_info; pub mod build_info_common; diff --git a/evm_loader/lib/src/solana_emulator.rs b/evm_loader/lib/src/solana_emulator.rs new file mode 100644 index 000000000..0b5eb55c2 --- /dev/null +++ b/evm_loader/lib/src/solana_emulator.rs @@ -0,0 +1,439 @@ +use solana_banks_interface::TransactionMetadata; +use solana_program_test::{ + processor, BanksClientError, BanksTransactionResultWithMetadata, ProgramTest, + ProgramTestContext, +}; +use solana_sdk::{ + account::AccountSharedData, + account::WritableAccount, + account::{Account, ReadableAccount}, + account_info::AccountInfo, + bpf_loader_upgradeable::{self, UpgradeableLoaderState}, + instruction::{AccountMeta, Instruction}, + message::Message, + program_error::ProgramError, + pubkey, + pubkey::Pubkey, + rent::Rent, + signature::Signer, + system_instruction::MAX_PERMITTED_DATA_LENGTH, + transaction::{Transaction, TransactionError}, +}; + +use log::info; +use maybe_async::maybe_async; +use tokio::sync::{Mutex, MutexGuard, OnceCell}; + +use crate::rpc::Rpc; +use crate::NeonError; + +#[maybe_async(?Send)] +pub trait ProgramCache { + type Error: std::error::Error; + + async fn get_account(&self, pubkey: Pubkey) -> Result, Self::Error>; + + async fn get_programdata( + &self, + programdata_pubkey: Pubkey, + ) -> evm_loader::error::Result> { + info!("ProgramData pubkey: {:?}", programdata_pubkey); + let programdata = self + .get_account(programdata_pubkey) + .await + .map_err(|e| evm_loader::error::Error::Custom(e.to_string()))? + .ok_or(ProgramError::UninitializedAccount)?; + if programdata.owner == bpf_loader_upgradeable::ID { + if let UpgradeableLoaderState::ProgramData { .. } = + bincode::deserialize(&programdata.data)? + { + return Ok(programdata.data + [UpgradeableLoaderState::size_of_programdata_metadata()..] + .to_vec()); + } + } + Err(solana_sdk::program_error::ProgramError::InvalidAccountData.into()) + } +} + +/// SolanaEmulator +/// Note: +/// 1. Use global program_stubs variable (new() function changes it inside ProgramTest::start_with_context) +/// 2. Get list of activated features from solana cluster (this list can't be changed after initialization) +pub struct SolanaEmulator { + pub program_id: Pubkey, + pub emulator_context: ProgramTestContext, + pub evm_loader_program: Account, +} + +static SOLANA_EMULATOR: OnceCell> = OnceCell::const_new(); +const SEEDS_PUBKEY: Pubkey = pubkey!("Seeds11111111111111111111111111111111111111"); + +pub async fn get_solana_emulator() -> MutexGuard<'static, SolanaEmulator> { + SOLANA_EMULATOR + .get() + .expect("SolanaEmulator is not initialized") + .lock() + .await +} + +pub async fn init_solana_emulator( + program_id: Pubkey, + rpc_client: &impl Rpc, +) -> &'static Mutex { + SOLANA_EMULATOR + .get_or_init(|| async { + let emulator = SolanaEmulator::new(program_id, rpc_client) + .await + .expect("Initialize SolanaEmulator"); + + Mutex::new(emulator) + }) + .await +} + +// evm_loader stub to call solana programs like from original program +// Pass signer seeds through the special account's data. +fn process_emulator_instruction( + program_id: &Pubkey, + accounts: &[AccountInfo], + instruction_data: &[u8], +) -> solana_sdk::entrypoint::ProgramResult { + let seeds: Vec>> = bincode::deserialize(&accounts[0].data.borrow()) + .map_err(|_| ProgramError::InvalidAccountData)?; + let seeds = seeds + .iter() + .map(|s| s.iter().map(|s| s.as_slice()).collect::>()) + .collect::>(); + let seeds = seeds.iter().map(|s| s.as_slice()).collect::>(); + + let signers = seeds + .iter() + .map(|s| { + Pubkey::create_program_address(s, program_id).map_err(|_| ProgramError::InvalidSeeds) + }) + .collect::, _>>()?; + + let instruction = Instruction::new_with_bytes( + *accounts[1].key, + instruction_data, + accounts[2..] + .iter() + .map(|a| AccountMeta { + pubkey: *a.key, + is_signer: if signers.contains(a.key) { + true + } else { + a.is_signer + }, + is_writable: a.is_writable, + }) + .collect::>(), + ); + + solana_sdk::program::invoke_signed_unchecked(&instruction, accounts, &seeds) +} + +impl SolanaEmulator { + pub async fn new( + program_id: Pubkey, + rpc_client: &impl Rpc, + ) -> Result { + let mut program_test = ProgramTest::default(); + program_test.prefer_bpf(false); + program_test.add_program( + "evm_loader", + program_id, + processor!(process_emulator_instruction), + ); + + // Disable features (get known feature list and disable by actual value) + let feature_list = solana_sdk::feature_set::FEATURE_NAMES + .iter() + .map(|feature| feature.0) + .cloned() + .collect::>(); + let features = rpc_client.get_multiple_accounts(&feature_list).await?; + + feature_list + .into_iter() + .zip(features) + .filter_map(|(pubkey, account)| { + let activated = account + .and_then(|ref acc| solana_sdk::feature::from_account(acc)) + .and_then(|v| v.activated_at); + match activated { + Some(_) => None, + None => Some(pubkey), + } + }) + .for_each(|feature_id| program_test.deactivate_feature(feature_id)); + + let mut emulator_context = program_test.start_with_context().await; + let evm_loader_program = emulator_context + .banks_client + .get_account(program_id) + .await + .expect("Can't get evm_loader program account") + .expect("evm_loader program account not found"); + + Ok(Self { + program_id, + emulator_context, + evm_loader_program, + }) + } + + pub fn payer(&self) -> Pubkey { + self.emulator_context.payer.pubkey() + } + + async fn set_programdata( + &mut self, + program_id: Pubkey, + programdata_address: Pubkey, + programdata: &mut Vec, + ) -> evm_loader::error::Result<()> { + if self + .emulator_context + .banks_client + .get_account(program_id) + .await + .map_err(|e| evm_loader::error::Error::Custom(e.to_string()))? + .is_none() + { + // Deploy new program + let mut program_account = AccountSharedData::new_data( + Rent::default().minimum_balance(programdata.len()), + &UpgradeableLoaderState::Program { + programdata_address, + }, + &bpf_loader_upgradeable::ID, + )?; + program_account.set_executable(true); + + let mut programdata_data = bincode::serialize(&UpgradeableLoaderState::ProgramData { + slot: 0, + upgrade_authority_address: Some(self.payer()), + })?; + programdata_data.append(programdata); + let mut programdata_account = AccountSharedData::new( + Rent::default().minimum_balance(programdata_data.len()), + programdata_data.len(), + &bpf_loader_upgradeable::ID, + ); + programdata_account.set_data(programdata_data); + + self.emulator_context + .set_account(&program_id, &program_account); + self.emulator_context + .set_account(&programdata_address, &programdata_account); + } else { + // Upgrade program + // let mut program_buffer = bincode::serialize( + // &UpgradeableLoaderState::Buffer { + // authority_address: Some(self.get_pubkey()) + // } + // )?; + // program_buffer.append(programdata); + // self.emulator_context.set_account(&BUFFER_PUBKEY, &Account { + // lamports: Rent::default().minimum_balance(program_buffer.len()), + // data: program_buffer, + // owner: solana_sdk::bpf_loader_upgradeable::ID, + // executable: false, + // rent_epoch: 0, + // }.into()); + + // self.process_transaction(&[ + // bpf_loader_upgradeable::upgrade( + // &program_id, + // &BUFFER_PUBKEY, + // &self.get_pubkey(), + // &self.get_pubkey(), + // ), + // ]).await?; + } + Ok(()) + } + + async fn set_account<'a, B: ProgramCache>( + &mut self, + program_cache: &B, + pubkey: &Pubkey, + account: &AccountSharedData, + ) -> evm_loader::error::Result<()> { + if *pubkey == self.payer() { + return Err(evm_loader::error::Error::InvalidAccountForCall(*pubkey)); + } + + if solana_sdk::bpf_loader_upgradeable::check_id(account.owner()) { + if let UpgradeableLoaderState::Program { + programdata_address, + } = account + .deserialize_data() + .map_err(|_| evm_loader::error::Error::AccountInvalidData(*pubkey))? + { + let mut programdata = program_cache.get_programdata(programdata_address).await?; + self.set_programdata(*pubkey, programdata_address, &mut programdata) + .await?; + info!("set_programdata: {:?}", pubkey); + return Ok(()); + } + } + + self.emulator_context.set_account(pubkey, account); + Ok(()) + } + + async fn prepare_transaction( + &mut self, + instructions: &[Instruction], + ) -> evm_loader::error::Result { + self.emulator_context + .get_new_latest_blockhash() + .await + .map_err(|e| evm_loader::error::Error::Custom(e.to_string()))?; + + let mut trx = Transaction::new_unsigned(Message::new(instructions, Some(&self.payer()))); + + trx.try_sign( + &[&self.emulator_context.payer], + self.emulator_context.last_blockhash, + ) + .map_err(|e| evm_loader::error::Error::Custom(e.to_string()))?; + + Ok(trx) + } + + pub async fn emulate_solana_call<'a, B: ProgramCache>( + &mut self, + program_cache: &B, + instruction: &Instruction, + accounts: &[AccountInfo<'a>], + seeds: &[Vec>], + ) -> evm_loader::error::Result> { + for account in accounts { + self.set_account(program_cache, account.key, &from_account_info(account)) + .await?; + } + + let signers = seeds + .iter() + .map(|s| { + let seed = s.iter().map(|s| s.as_slice()).collect::>(); + Pubkey::create_program_address(&seed, &self.program_id) + .expect("Create signer from seeds") + }) + .collect::>(); + + self.set_account( + program_cache, + &SEEDS_PUBKEY, + &AccountSharedData::new_data( + Rent::default().minimum_balance(MAX_PERMITTED_DATA_LENGTH as usize), + &seeds, + &self.program_id, + )?, + ) + .await?; + + let mut accounts_meta = vec![ + AccountMeta::new_readonly(SEEDS_PUBKEY, false), + AccountMeta::new_readonly(instruction.program_id, false), + ]; + accounts_meta.extend(instruction.accounts.iter().map(|m| AccountMeta { + pubkey: m.pubkey, + is_signer: !signers.contains(&m.pubkey) && m.is_signer, + is_writable: m.is_writable, + })); + + let emulate_trx = self + .prepare_transaction(&[Instruction::new_with_bytes( + self.program_id, + &instruction.data, + accounts_meta, + )]) + .await?; + + let trx_metadata = match self + .emulator_context + .banks_client + .process_transaction_with_metadata(emulate_trx) + .await + { + Ok(BanksTransactionResultWithMetadata { + result: Ok(()), + metadata, + }) => Ok(metadata), + Ok(BanksTransactionResultWithMetadata { + result: Err(err), .. + }) + | Err(BanksClientError::SimulationError { err, .. }) + | Err(BanksClientError::TransactionError(err)) => match err { + TransactionError::InstructionError(_, err) => { + Err(evm_loader::error::Error::ExternalCallFailed( + instruction.program_id, + err.to_string(), + )) + } + _ => Err(evm_loader::error::Error::Custom(err.to_string())), + }, + Err(err) => Err(evm_loader::error::Error::Custom(err.to_string())), + }?; + + let next_slot = self + .emulator_context + .banks_client + .get_root_slot() + .await + .unwrap() + + 1; + self.emulator_context + .warp_to_slot(next_slot) + .expect("Warp to next slot"); + + // Update writable accounts + let payer = self.payer(); + for pubkey in instruction.accounts.iter().filter_map(|m| { + if m.is_writable && m.pubkey != payer { + Some(m.pubkey) + } else { + None + } + }) { + let account = self + .emulator_context + .banks_client + .get_account(pubkey) + .await + .unwrap() + .unwrap_or_default(); + + let original = accounts + .iter() + .find(|a| a.key == &pubkey) + .expect("Missing pubkey in accounts map"); + + **original.try_borrow_mut_lamports()? = account.lamports; + if original.data_len() != account.data.len() { + original.realloc(account.data.len(), true)?; + } + original + .try_borrow_mut_data()? + .copy_from_slice(account.data.as_slice()); + if *original.owner != account.owner { + original.assign(&account.owner); + } + } + + Ok(trx_metadata) + } +} + +fn from_account_info(account: &AccountInfo) -> AccountSharedData { + let mut acc = AccountSharedData::new(account.lamports(), 0, account.owner); + acc.set_data(account.data.as_ref().borrow().to_vec()); + acc.set_executable(account.executable); + acc.set_rent_epoch(account.rent_epoch); + acc +} diff --git a/evm_loader/lib/src/solana_simulator/mod.rs b/evm_loader/lib/src/solana_simulator/mod.rs index 151a5bae1..47b052ccd 100644 --- a/evm_loader/lib/src/solana_simulator/mod.rs +++ b/evm_loader/lib/src/solana_simulator/mod.rs @@ -13,6 +13,7 @@ use solana_sdk::{ hash::Hash, pubkey::Pubkey, signature::Keypair, + sysvar::{Sysvar, SysvarId}, transaction::{ MessageHash, SanitizedTransaction, TransactionVerificationMode, VersionedTransaction, }, @@ -131,6 +132,13 @@ impl SolanaSimulator { self.bank().register_recent_blockhash(blockhash); } + pub fn set_sysvar(&self, sysvar: &T) + where + T: Sysvar + SysvarId, + { + self.bank().set_sysvar_for_tests(sysvar); + } + pub fn set_program_account(&mut self, pubkey: &Pubkey, data: Vec) { let rent = self.bank().rent_collector().rent; let lamports = rent.minimum_balance(data.len()); diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index 28df797fb..13d9e5555 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -8,7 +8,8 @@ use evm_loader::{ types::{AccessListTx, LegacyTx, TransactionPayload}, }; use serde_with::skip_serializing_none; -use solana_sdk::pubkey::Pubkey; +use solana_sdk::{account::Account, pubkey::Pubkey}; +use std::collections::HashMap; pub use tracer_ch_db::ClickHouseDb as TracerDb; use crate::tracing::TraceCallConfig; @@ -115,6 +116,30 @@ impl std::fmt::Debug for TxParams { } } +#[serde_as] +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +pub struct SerializedAccount { + pub lamports: u64, + #[serde_as(as = "DisplayFromStr")] + pub owner: Pubkey, + pub executable: bool, + pub rent_epoch: u64, + #[serde_as(as = "Hex")] + pub data: Vec, +} + +impl From<&SerializedAccount> for Account { + fn from(account: &SerializedAccount) -> Self { + Account { + lamports: account.lamports, + owner: account.owner, + executable: account.executable, + rent_epoch: account.rent_epoch, + data: account.data.clone(), + } + } +} + #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] pub struct EmulateRequest { @@ -124,6 +149,8 @@ pub struct EmulateRequest { pub trace_config: Option, #[serde_as(as = "Vec")] pub accounts: Vec, + #[serde_as(as = "Option>")] + pub solana_overrides: Option>>, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -281,4 +308,56 @@ mod tests { assert_eq!(map.get(123456800), None); // Beyond the top end of the last range } + + #[test] + fn test_deserialize() { + let txt = r#" + { + "step_limit": 500000, + "accounts": [], + "chains": [ + { + "id": 111, + "name": "neon", + "token": "HPsV9Deocecw3GeZv1FkAPNCBRfuVyfw9MMwjwRe1xaU" + }, + { + "id": 112, + "name": "sol", + "token": "So11111111111111111111111111111111111111112" + }, + { + "id": 113, + "name": "usdt", + "token": "2duuuuhNJHUYqcnZ7LKfeufeeTBgSJdftf2zM3cZV6ym" + }, + { + "id": 114, + "name": "eth", + "token": "EwJYd3UAFAgzodVeHprB2gMQ68r4ZEbbvpoVzCZ1dGq5" + } + ], + "tx": { + "from": "0x3fd219e7cf0e701fcf5a6903b40d47ca4e597d99", + "to": "0x0673ac30e9c5dd7955ae9fb7e46b3cddca435883", + "value": "0x0", + "data": "3ff21f8e", + "chain_id": 111 + }, + "solana_overrides": { + "EwJYd3UAFAgzodVeHprB2gMQ68r4ZEbbvpoVzCZ1dGq5": null, + "2duuuuhNJHUYqcnZ7LKfeufeeTBgSJdftf2zM3cZV6ym": { + "lamports": 1000000000000, + "owner": "So11111111111111111111111111111111111111112", + "executable": false, + "rent_epoch": 0, + "data": "0102030405" + } + } + } + "#; + + let request: super::EmulateRequest = serde_json::from_str(txt).unwrap(); + println!("{:?}", request); + } } diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 713758be2..59329254b 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -64,6 +64,8 @@ features = ["is_sync"] [dev-dependencies] tokio = { version = "1.0", features = ["full"] } serde_json = { version = "1.0.115", features = ["preserve_order"] } +solana-sdk.workspace = true + [lib] crate-type = ["cdylib", "lib"] diff --git a/evm_loader/program/src/account/ether_balance.rs b/evm_loader/program/src/account/ether_balance.rs index b2959bef4..e59f01700 100644 --- a/evm_loader/program/src/account/ether_balance.rs +++ b/evm_loader/program/src/account/ether_balance.rs @@ -41,6 +41,11 @@ impl<'a> BalanceAccount<'a> { Ok(Self { account }) } + #[must_use] + pub fn info(&self) -> &AccountInfo<'a> { + &self.account + } + pub fn create( address: Address, chain_id: u64, @@ -97,7 +102,16 @@ impl<'a> BalanceAccount<'a> { rent, )?; - super::set_tag(&crate::ID, &account, TAG_ACCOUNT_BALANCE, Header::VERSION)?; + Self::initialize(account, &crate::ID, address, chain_id) + } + + pub fn initialize( + account: AccountInfo<'a>, + program_id: &Pubkey, + address: Address, + chain_id: u64, + ) -> Result { + super::set_tag(program_id, &account, TAG_ACCOUNT_BALANCE, Header::VERSION)?; { let mut header = super::header_mut::
(&account); header.address = address; diff --git a/evm_loader/program/src/account/ether_contract.rs b/evm_loader/program/src/account/ether_contract.rs index 04241e018..40919abd2 100644 --- a/evm_loader/program/src/account/ether_contract.rs +++ b/evm_loader/program/src/account/ether_contract.rs @@ -75,6 +75,11 @@ impl<'a> ContractAccount<'a> { Ok(Self { account }) } + #[must_use] + pub fn info(&self) -> &AccountInfo<'a> { + &self.account + } + pub fn allocate( address: Address, code: &[u8], @@ -124,7 +129,7 @@ impl<'a> ContractAccount<'a> { } } - pub fn init( + pub fn create( address: Address, chain_id: u64, generation: u32, @@ -138,18 +143,29 @@ impl<'a> ContractAccount<'a> { ); let account = accounts.get(&pubkey).clone(); + Self::initialize(account, &crate::ID, address, chain_id, generation, code) + } - super::validate_tag(&crate::ID, &account, TAG_EMPTY)?; - super::set_tag(&crate::ID, &account, TAG_ACCOUNT_CONTRACT, Header::VERSION)?; + pub fn initialize( + account: AccountInfo<'a>, + program_id: &Pubkey, + address: Address, + chain_id: u64, + generation: u32, + code: &[u8], + ) -> Result { + super::validate_tag(program_id, &account, TAG_EMPTY)?; + super::set_tag(program_id, &account, TAG_ACCOUNT_CONTRACT, Header::VERSION)?; - let mut contract = Self { account }; { - let mut header = super::header_mut::
(&contract.account); + let mut header = super::header_mut::
(&account); header.v0.address = address; header.v0.chain_id = chain_id; header.v0.generation = generation; header.revision = 1; } + + let mut contract = Self::from_account(program_id, account)?; { let mut contract_code = contract.code_mut(); contract_code.copy_from_slice(code); @@ -192,7 +208,8 @@ impl<'a> ContractAccount<'a> { } #[inline] - fn storage(&self) -> Ref { + #[must_use] + pub fn storage(&self) -> Ref { let offset = self.storage_offset(); super::section(&self.account, offset) } diff --git a/evm_loader/program/src/account/ether_storage.rs b/evm_loader/program/src/account/ether_storage.rs index e05617922..cdd216d6a 100644 --- a/evm_loader/program/src/account/ether_storage.rs +++ b/evm_loader/program/src/account/ether_storage.rs @@ -1,7 +1,7 @@ use std::cell::{Ref, RefMut}; use std::mem::size_of; -use super::{AccountHeader, AccountsDB, NoHeader, ACCOUNT_PREFIX_LEN, TAG_STORAGE_CELL}; +use super::{AccountHeader, AccountsDB, NoHeader, ACCOUNT_PREFIX_LEN, TAG_EMPTY, TAG_STORAGE_CELL}; use crate::error::Result; use ethnum::U256; use solana_program::{account_info::AccountInfo, pubkey::Pubkey, rent::Rent}; @@ -108,6 +108,11 @@ impl<'a> StorageCell<'a> { Ok(Self { account }) } + #[must_use] + pub fn info(&self) -> &AccountInfo<'a> { + &self.account + } + pub fn create( address: StorageCellAddress, allocate_cells: usize, @@ -134,15 +139,18 @@ impl<'a> StorageCell<'a> { rent, )?; - super::set_tag(&crate::ID, cell_account, TAG_STORAGE_CELL, Header::VERSION)?; + Self::initialize(cell_account.clone(), &crate::ID) + } + + pub fn initialize(account: AccountInfo<'a>, program_id: &Pubkey) -> Result { + super::validate_tag(program_id, &account, TAG_EMPTY)?; + super::set_tag(program_id, &account, TAG_STORAGE_CELL, Header::VERSION)?; { - let mut header = super::header_mut::
(cell_account); + let mut header = super::header_mut::
(&account); header.revision = 1; } - Ok(Self { - account: cell_account.clone(), - }) + Ok(Self { account }) } #[must_use] diff --git a/evm_loader/program/src/account/legacy/mod.rs b/evm_loader/program/src/account/legacy/mod.rs index ec75d2d6a..58e5586a9 100644 --- a/evm_loader/program/src/account/legacy/mod.rs +++ b/evm_loader/program/src/account/legacy/mod.rs @@ -87,7 +87,7 @@ fn update_ether_account_from_v1( // Fill it with new data account.try_borrow_mut_data()?.fill(0); - let mut contract = ContractAccount::init( + let mut contract = ContractAccount::create( legacy_data.address, crate::config::DEFAULT_CHAIN_ID, legacy_data.generation, diff --git a/evm_loader/program/src/account_storage/apply.rs b/evm_loader/program/src/account_storage/apply.rs index ea11f6403..7265c1784 100644 --- a/evm_loader/program/src/account_storage/apply.rs +++ b/evm_loader/program/src/account_storage/apply.rs @@ -111,7 +111,7 @@ impl<'a> ProgramAccountStorage<'a> { chain_id, code, } => { - ContractAccount::init( + ContractAccount::create( address, chain_id, 0, @@ -127,7 +127,11 @@ impl<'a> ProgramAccountStorage<'a> { seeds, .. } => { - let seeds: Vec<&[u8]> = seeds.iter().map(|seed| &seed[..]).collect(); + let seeds = seeds + .iter() + .map(|s| s.iter().map(|s| s.as_slice()).collect::>()) + .collect::>(); + let seeds = seeds.iter().map(|s| s.as_slice()).collect::>(); let mut accounts_info = Vec::with_capacity(accounts.len() + 1); @@ -151,7 +155,7 @@ impl<'a> ProgramAccountStorage<'a> { }; if !seeds.is_empty() { - invoke_signed_unchecked(&instruction, &accounts_info, &[&seeds])?; + invoke_signed_unchecked(&instruction, &accounts_info, &seeds)?; } else { invoke_unchecked(&instruction, &accounts_info)?; } diff --git a/evm_loader/program/src/account_storage/backend.rs b/evm_loader/program/src/account_storage/backend.rs index d6f7b0a05..e5cea5d91 100644 --- a/evm_loader/program/src/account_storage/backend.rs +++ b/evm_loader/program/src/account_storage/backend.rs @@ -36,6 +36,10 @@ impl<'a> AccountStorage for ProgramAccountStorage<'a> { solana_program::program::get_return_data() } + fn set_return_data(&self, data: &[u8]) { + solana_program::program::set_return_data(data); + } + fn block_hash(&self, slot: u64) -> [u8; 32] { let slot_hashes_account = self.accounts.get(&slot_hashes::ID); let slot_hashes_data = slot_hashes_account.data.borrow(); diff --git a/evm_loader/program/src/account_storage/base.rs b/evm_loader/program/src/account_storage/base.rs index df43c2ae4..b5f79dee7 100644 --- a/evm_loader/program/src/account_storage/base.rs +++ b/evm_loader/program/src/account_storage/base.rs @@ -1,3 +1,5 @@ +use std::collections::HashSet; + use crate::account::{ AccountsDB, BalanceAccount, ContractAccount, Operator, StorageCell, Treasury, }; @@ -18,6 +20,7 @@ impl<'a> ProgramAccountStorage<'a> { rent: Rent::get()?, accounts, keys: KeysCache::new(), + synced_modified_contracts: HashSet::new(), }) } diff --git a/evm_loader/program/src/account_storage/mod.rs b/evm_loader/program/src/account_storage/mod.rs index 90972705f..9a3aba7c1 100644 --- a/evm_loader/program/src/account_storage/mod.rs +++ b/evm_loader/program/src/account_storage/mod.rs @@ -3,19 +3,21 @@ use crate::executor::OwnedAccountInfo; use crate::types::Address; use ethnum::U256; use maybe_async::maybe_async; -use solana_program::account_info::AccountInfo; +use solana_program::{ + account_info::AccountInfo, instruction::Instruction, pubkey::Pubkey, rent::Rent, +}; #[cfg(target_os = "solana")] use {crate::account::AccountsDB, solana_program::clock::Clock}; -use solana_program::pubkey::Pubkey; -use solana_program::rent::Rent; - #[cfg(target_os = "solana")] mod apply; #[cfg(target_os = "solana")] mod backend; #[cfg(target_os = "solana")] mod base; +#[cfg(target_os = "solana")] +mod synced; + mod block_hash; pub use block_hash::find_slot_hash; @@ -28,6 +30,7 @@ pub struct ProgramAccountStorage<'a> { rent: Rent, accounts: AccountsDB<'a>, keys: keys_cache::KeysCache, + synced_modified_contracts: std::collections::HashSet, } /// Account storage @@ -52,6 +55,9 @@ pub trait AccountStorage { /// Get return data from Solana fn return_data(&self) -> Option<(Pubkey, Vec)>; + /// Set return data to Solana + fn set_return_data(&self, data: &[u8]); + /// Get account nonce async fn nonce(&self, address: Address, chain_id: u64) -> u64; /// Get account balance @@ -82,3 +88,29 @@ pub trait AccountStorage { where F: FnOnce(&AccountInfo) -> R; } + +#[maybe_async(?Send)] +pub trait SyncedAccountStorage { + async fn set_code(&mut self, address: Address, chain_id: u64, code: Vec) -> Result<()>; + async fn set_storage(&mut self, address: Address, index: U256, value: [u8; 32]) -> Result<()>; + async fn increment_nonce(&mut self, address: Address, chain_id: u64) -> Result<()>; + async fn transfer( + &mut self, + from_address: Address, + to_address: Address, + chain_id: u64, + value: U256, + ) -> Result<()>; + async fn burn(&mut self, address: Address, chain_id: u64, value: U256) -> Result<()>; + async fn execute_external_instruction( + &mut self, + instruction: Instruction, + seeds: Vec>>, + fee: u64, + emulated_internally: bool, + ) -> Result<()>; + + fn snapshot(&mut self); + fn revert_snapshot(&mut self); + fn commit_snapshot(&mut self); +} diff --git a/evm_loader/program/src/account_storage/synced.rs b/evm_loader/program/src/account_storage/synced.rs new file mode 100644 index 000000000..3c95e4cd6 --- /dev/null +++ b/evm_loader/program/src/account_storage/synced.rs @@ -0,0 +1,167 @@ +use ethnum::U256; +use solana_program::account_info::AccountInfo; +use solana_program::instruction::Instruction; +use solana_program::program::{invoke_signed_unchecked, invoke_unchecked}; +use solana_program::system_program; + +use crate::account::{AllocateResult, ContractAccount, StorageCell}; +use crate::account_storage::SyncedAccountStorage; +use crate::config::{ACCOUNT_SEED_VERSION, STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT}; +use crate::error::Result; +use crate::types::Address; + +use super::{AccountStorage, ProgramAccountStorage}; + +impl<'a> SyncedAccountStorage for crate::account_storage::ProgramAccountStorage<'a> { + fn set_code(&mut self, address: Address, chain_id: u64, code: Vec) -> Result<()> { + let result = ContractAccount::allocate( + address, + &code, + &self.rent, + &self.accounts, + Some(&self.keys), + )?; + + if result != AllocateResult::Ready { + return Err(crate::error::Error::AccountSpaceAllocationFailure); + } + + ContractAccount::create( + address, + chain_id, + 0, + &code, + &self.accounts, + Some(&self.keys), + )?; + + Ok(()) + } + + fn set_storage(&mut self, address: Address, index: U256, value: [u8; 32]) -> Result<()> { + const STATIC_STORAGE_LIMIT: U256 = U256::new(STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT as u128); + + if index < STATIC_STORAGE_LIMIT { + // Static Storage - Write into contract account + let mut contract = self.contract_account(address)?; + let index: usize = index.as_usize(); + contract.set_storage_value(index, &value); + + // Mark contract as modified + // We can't increase the revision here because it might break the pointer to the contract code inside the evm. + // TODO: After Account HEAP experiment, may be we could remove the Buffer magic + self.synced_modified_contracts.insert(*contract.pubkey()); + } else { + // Infinite Storage - Write into separate account + let cell_address = self.keys.storage_cell_address(&crate::ID, address, index); + let account = self.accounts.get(cell_address.pubkey()); + if system_program::check_id(account.owner) { + let (_, bump) = self.keys.contract_with_bump_seed(&crate::ID, address); + let sign: &[&[u8]] = &[&[ACCOUNT_SEED_VERSION], address.as_bytes(), &[bump]]; + + let mut storage = + StorageCell::create(cell_address, 1, &self.accounts, sign, &self.rent)?; + let mut cells = storage.cells_mut(); + + assert_eq!(cells.len(), 1); + cells[0].subindex = (index & 0xFF).as_u8(); + cells[0].value = value; + } else { + let mut storage = StorageCell::from_account(&crate::ID, account.clone())?; + storage.update((index & 0xFF).as_u8(), &value)?; + + storage.sync_lamports(&self.rent, &self.accounts)?; + storage.increment_revision(&self.rent, &self.accounts)?; + }; + } + + Ok(()) + } + + fn increment_nonce(&mut self, address: Address, chain_id: u64) -> Result<()> { + let mut account = self.create_balance_account(address, chain_id)?; + account.increment_nonce() + } + + fn transfer( + &mut self, + source: Address, + target: Address, + chain_id: u64, + value: U256, + ) -> Result<()> { + let mut source = self.balance_account(source, chain_id)?; + let mut target = self.create_balance_account(target, chain_id)?; + source.transfer(&mut target, value) + } + + fn burn(&mut self, address: Address, chain_id: u64, value: U256) -> Result<()> { + let mut account = self.balance_account(address, chain_id)?; + account.burn(value) + } + + fn execute_external_instruction( + &mut self, + instruction: Instruction, + seeds: Vec>>, + _fee: u64, + _emulated_internally: bool, + ) -> Result<()> { + let seeds = seeds + .iter() + .map(|s| s.iter().map(|s| s.as_slice()).collect::>()) + .collect::>(); + let seeds = seeds.iter().map(|s| s.as_slice()).collect::>(); + + let mut accounts_info = Vec::with_capacity(instruction.accounts.len() + 1); + + let program = self.accounts.get(&instruction.program_id).clone(); + accounts_info.push(program); + + for meta in &instruction.accounts { + let account: AccountInfo<'a> = if meta.pubkey == self.accounts.operator_key() { + self.accounts.operator_info().clone() + } else { + self.accounts.get(&meta.pubkey).clone() + }; + accounts_info.push(account); + } + + let instruction = Instruction { + program_id: instruction.program_id, + accounts: instruction.accounts, + data: instruction.data, + }; + + if !seeds.is_empty() { + invoke_signed_unchecked(&instruction, &accounts_info, &seeds)?; + } else { + invoke_unchecked(&instruction, &accounts_info)?; + } + + Ok(()) + } + + fn snapshot(&mut self) {} + + fn revert_snapshot(&mut self) { + panic!("revert snapshot not implemented for ProgramAccountStorage"); + } + + fn commit_snapshot(&mut self) {} +} + +impl<'a> ProgramAccountStorage<'a> { + pub fn increment_revision_for_modified_contracts(&mut self) -> Result<()> { + for pubkey in self.synced_modified_contracts.iter() { + let account = self.accounts.get(pubkey); + + let mut contract = ContractAccount::from_account(&self.program_id(), account.clone())?; + contract.increment_revision(&self.rent, &self.accounts)?; + } + + self.synced_modified_contracts.clear(); + + Ok(()) + } +} diff --git a/evm_loader/program/src/entrypoint.rs b/evm_loader/program/src/entrypoint.rs index eaf4edc69..5d84c72fa 100644 --- a/evm_loader/program/src/entrypoint.rs +++ b/evm_loader/program/src/entrypoint.rs @@ -128,6 +128,20 @@ fn process_instruction<'a>( EvmInstruction::AccountCreateBalance => { instruction::account_create_balance::process(program_id, accounts, instruction) } + EvmInstruction::TransactionExecuteFromInstructionWithSolanaCall => { + instruction::transaction_execute_from_instruction_solana_call::process( + program_id, + accounts, + instruction, + ) + } + EvmInstruction::TransactionExecuteFromAccountWithSolanaCall => { + instruction::transaction_execute_from_account_solana_call::process( + program_id, + accounts, + instruction, + ) + } EvmInstruction::ConfigGetChainCount => { instruction::config_get_chain_count::process(program_id, accounts, instruction) } diff --git a/evm_loader/program/src/error.rs b/evm_loader/program/src/error.rs index 22e79f95b..825db02dd 100644 --- a/evm_loader/program/src/error.rs +++ b/evm_loader/program/src/error.rs @@ -178,6 +178,18 @@ pub enum Error { That's why you have to use iterative transaction for the deployment." )] AccountSpaceAllocationFailure, + + #[error("Invalid account for call {0}")] + InvalidAccountForCall(Pubkey), + + #[error("Call for external Solana programs not available in this mode")] + UnavalableExternalSolanaCall, + + #[error("Program not allowed to call itself")] + RecursiveCall, + + #[error("External call fails {0}: {1}")] + ExternalCallFailed(Pubkey, String), } pub type Result = std::result::Result; diff --git a/evm_loader/program/src/evm/database.rs b/evm_loader/program/src/evm/database.rs index 0aadd4fdd..1fbf5625d 100644 --- a/evm_loader/program/src/evm/database.rs +++ b/evm_loader/program/src/evm/database.rs @@ -1,17 +1,24 @@ use super::{Buffer, Context}; -use crate::{error::Result, types::Address}; +use crate::{error::Result, executor::OwnedAccountInfo, types::Address}; use ethnum::U256; use maybe_async::maybe_async; -use solana_program::{account_info::AccountInfo, pubkey::Pubkey, rent::Rent}; +use solana_program::{ + account_info::AccountInfo, instruction::Instruction, pubkey::Pubkey, rent::Rent, +}; #[maybe_async(?Send)] pub trait Database { + fn program_id(&self) -> &Pubkey; + fn operator(&self) -> Pubkey; + fn chain_id_to_token(&self, chain_id: u64) -> Pubkey; + fn contract_pubkey(&self, address: Address) -> (Pubkey, u8); + fn default_chain_id(&self) -> u64; fn is_valid_chain_id(&self, chain_id: u64) -> bool; async fn contract_chain_id(&self, address: Address) -> Result; async fn nonce(&self, address: Address, chain_id: u64) -> Result; - fn increment_nonce(&mut self, address: Address, chain_id: u64) -> Result<()>; + async fn increment_nonce(&mut self, address: Address, chain_id: u64) -> Result<()>; async fn balance(&self, address: Address, chain_id: u64) -> Result; async fn transfer( @@ -21,12 +28,14 @@ pub trait Database { chain_id: u64, value: U256, ) -> Result<()>; + async fn burn(&mut self, address: Address, chain_id: u64, value: U256) -> Result<()>; + async fn code_size(&self, address: Address) -> Result; async fn code(&self, address: Address) -> Result; - fn set_code(&mut self, address: Address, chain_id: u64, code: Vec) -> Result<()>; + async fn set_code(&mut self, address: Address, chain_id: u64, code: Vec) -> Result<()>; async fn storage(&self, address: Address, index: U256) -> Result<[u8; 32]>; - fn set_storage(&mut self, address: Address, index: U256, value: [u8; 32]) -> Result<()>; + async fn set_storage(&mut self, address: Address, index: U256, value: [u8; 32]) -> Result<()>; async fn transient_storage(&self, address: Address, index: U256) -> Result<[u8; 32]>; fn set_transient_storage( @@ -41,7 +50,9 @@ pub trait Database { fn block_timestamp(&self) -> Result; fn rent(&self) -> &Rent; fn return_data(&self) -> Option<(Pubkey, Vec)>; + fn set_return_data(&mut self, data: &[u8]); + async fn external_account(&self, address: Pubkey) -> Result; async fn map_solana_account(&self, address: &Pubkey, action: F) -> R where F: FnOnce(&AccountInfo) -> R; @@ -50,6 +61,14 @@ pub trait Database { fn revert_snapshot(&mut self); fn commit_snapshot(&mut self); + async fn queue_external_instruction( + &mut self, + instruction: Instruction, + seeds: Vec>>, + fee: u64, + emulated_internally: bool, + ) -> Result<()>; + async fn precompile_extension( &mut self, context: &Context, diff --git a/evm_loader/program/src/evm/mod.rs b/evm_loader/program/src/evm/mod.rs index 295ca5d16..6399e305a 100644 --- a/evm_loader/program/src/evm/mod.rs +++ b/evm_loader/program/src/evm/mod.rs @@ -330,7 +330,7 @@ impl Machine { backend.snapshot(); - backend.increment_nonce(target, chain_id)?; + backend.increment_nonce(target, chain_id).await?; backend .transfer(origin, target, chain_id, trx.value()) .await?; diff --git a/evm_loader/program/src/evm/opcode.rs b/evm_loader/program/src/evm/opcode.rs index e06e0b5b3..e3789ea1f 100644 --- a/evm_loader/program/src/evm/opcode.rs +++ b/evm_loader/program/src/evm/opcode.rs @@ -830,7 +830,9 @@ impl Machine { let index = self.stack.pop_u256()?; let value = *self.stack.pop_array()?; - backend.set_storage(self.context.contract, index, value)?; + backend + .set_storage(self.context.contract, index, value) + .await?; Ok(Action::Continue) } @@ -1096,7 +1098,9 @@ impl Machine { return Err(Error::NonceOverflow(self.context.contract)); } - backend.increment_nonce(self.context.contract, chain_id)?; + backend + .increment_nonce(self.context.contract, chain_id) + .await?; self.return_data = Buffer::empty(); self.return_range = 0..0; @@ -1131,7 +1135,7 @@ impl Machine { return Err(Error::DeployToExistingAccount(address, self.context.caller)); } - backend.increment_nonce(address, chain_id)?; + backend.increment_nonce(address, chain_id).await?; backend .transfer(self.context.caller, address, chain_id, value) .await?; @@ -1368,7 +1372,9 @@ impl Machine { ) -> Result { if self.reason == Reason::Create { let code = std::mem::take(&mut return_data); - backend.set_code(self.context.contract, self.chain_id, code)?; + backend + .set_code(self.context.contract, self.chain_id, code) + .await?; } backend.commit_snapshot(); @@ -1418,8 +1424,8 @@ impl Machine { return_data: Vec, backend: &mut B, ) -> Result { - backend.revert_snapshot(); log_data(&[b"EXIT", b"REVERT", &return_data]); + backend.revert_snapshot(); end_vm!( self, diff --git a/evm_loader/program/src/executor/action.rs b/evm_loader/program/src/executor/action.rs index 17d8567e1..0705b77f2 100644 --- a/evm_loader/program/src/executor/action.rs +++ b/evm_loader/program/src/executor/action.rs @@ -11,8 +11,9 @@ pub enum Action { accounts: Vec, #[serde(with = "serde_bytes")] data: Vec, - seeds: Vec>, + seeds: Vec>>, fee: u64, + emulated_internally: bool, }, Transfer { source: Address, diff --git a/evm_loader/program/src/executor/mod.rs b/evm_loader/program/src/executor/mod.rs index 722238c17..5de732354 100644 --- a/evm_loader/program/src/executor/mod.rs +++ b/evm_loader/program/src/executor/mod.rs @@ -2,7 +2,9 @@ mod action; mod cache; mod precompile_extension; mod state; +mod synced_state; pub use action::Action; pub use cache::OwnedAccountInfo; pub use state::ExecutorState; +pub use synced_state::SyncedExecutorState; diff --git a/evm_loader/program/src/executor/precompile_extension/call_solana.rs b/evm_loader/program/src/executor/precompile_extension/call_solana.rs new file mode 100644 index 000000000..ad1fbb1e5 --- /dev/null +++ b/evm_loader/program/src/executor/precompile_extension/call_solana.rs @@ -0,0 +1,478 @@ +use crate::{ + config::ACCOUNT_SEED_VERSION, + error::{Error, Result}, + evm::database::Database, + types::Address, +}; +use arrayref::array_ref; +use ethnum::U256; +use maybe_async::maybe_async; +use solana_program::{ + instruction::{AccountMeta, Instruction}, + pubkey::Pubkey, +}; + +// "cfd51d32": "createResource(bytes32,uint64,uint64,bytes32)" +// "154d4aa5": "getNeonAddress(address)" +// "59e4ad63": "getResourceAddress(bytes32)" +// "4a890f31": "getSolanaPDA(bytes32,bytes)" +// "cd2d1a3a": "getExtAuthority(bytes32)" +// "30aa81c6": "getPayer()", + +// "c549a7af": "execute(uint64,bytes)", +// "32607450": "executeWithSeed(uint64,bytes32,bytes)", +// "aeed7f1e": "execute(uint64,(bytes32,(bytes32,bool,bool)[],bytes))", +// "add378af": "executeWithSeed(uint64,bytes32,(bytes32,(bytes32,bool,bool)[],bytes))", +// "cff5c1a5": "getReturnData()", + +#[maybe_async] +#[allow(clippy::too_many_lines)] +pub async fn call_solana( + state: &mut State, + address: &Address, + input: &[u8], + context: &crate::evm::Context, + is_static: bool, +) -> Result> { + if context.value != 0 { + return Err(Error::Custom("CallSolana: value != 0".to_string())); + } + + if &context.contract != address { + return Err(Error::Custom( + "CallSolana: callcode or delegatecall is not allowed".to_string(), + )); + } + + let (selector, input) = input.split_at(4); + let selector: [u8; 4] = selector.try_into()?; + + #[cfg(not(target_os = "solana"))] + log::info!("Call arguments: {}", hex::encode(input)); + + match selector { + // "c549a7af": "execute(uint64,bytes)", + [0xc5, 0x49, 0xa7, 0xaf] => { + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let required_lamports = read_u64(&input[0..])?; + let offset = read_usize(&input[32..])?; + let instruction: Instruction = + bincode::deserialize(&input[offset + 32..]).map_err(|_| Error::OutOfBounds)?; + + let signer = context.caller; + let (_signer_pubkey, bump_seed) = state.contract_pubkey(signer); + + let signer_seeds = vec![ + vec![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vec(), + vec![bump_seed], + ]; + + execute_external_instruction( + state, + context, + instruction, + signer_seeds, + required_lamports, + ) + .await + } + + // "32607450": "executeWithSeed(uint64,bytes32,bytes)", + [0x32, 0x60, 0x74, 0x50] => { + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let required_lamports = read_u64(&input[0..])?; + let salt = read_salt(&input[32..])?; + let offset = read_usize(&input[64..])?; + let instruction: Instruction = + bincode::deserialize(&input[offset + 32..]).map_err(|_| Error::OutOfBounds)?; + + let seeds: &[&[u8]] = &[ + &[ACCOUNT_SEED_VERSION], + b"AUTH", + context.caller.as_bytes(), + salt, + ]; + let (_, signer_seed) = Pubkey::find_program_address(seeds, state.program_id()); + let seeds = vec![ + vec![ACCOUNT_SEED_VERSION], + b"AUTH".to_vec(), + context.caller.as_bytes().to_vec(), + salt.to_vec(), + vec![signer_seed], + ]; + + execute_external_instruction(state, context, instruction, seeds, required_lamports) + .await + } + + // "aeed7f1e": "execute(uint64,(bytes32,(bytes32,bool,bool)[],bytes))", + [0xae, 0xed, 0x7f, 0x1e] => { + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let required_lamports = read_u64(&input[0..])?; + let instruction_offset = read_usize(&input[32..])?; + let instruction = read_instruction(&input[instruction_offset..])?; + + let signer = context.caller; + let (_signer_pubkey, bump_seed) = state.contract_pubkey(signer); + + let signer_seeds = vec![ + vec![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vec(), + vec![bump_seed], + ]; + + execute_external_instruction( + state, + context, + instruction, + signer_seeds, + required_lamports, + ) + .await + } + + // "add378af": "executeWithSeed(uint64,bytes32,(bytes32,(bytes32,bool,bool)[],bytes))", + [0xad, 0xd3, 0x78, 0xaf] => { + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let required_lamports = read_u64(&input[0..])?; + let salt = read_salt(&input[32..])?; + let instruction_offset = read_usize(&input[64..])?; + let instruction = read_instruction(&input[instruction_offset..])?; + + let seeds: &[&[u8]] = &[ + &[ACCOUNT_SEED_VERSION], + b"AUTH", + context.caller.as_bytes(), + salt, + ]; + let (_, signer_seed) = Pubkey::find_program_address(seeds, state.program_id()); + let seeds = vec![ + vec![ACCOUNT_SEED_VERSION], + b"AUTH".to_vec(), + context.caller.as_bytes().to_vec(), + salt.to_vec(), + vec![signer_seed], + ]; + + execute_external_instruction(state, context, instruction, seeds, required_lamports) + .await + } + + // "154d4aa5": "getNeonAddress(address)" + [0x15, 0x4d, 0x4a, 0xa5] => { + let neon_addess = Address::from(*array_ref![input, 12, 20]); + let sol_address = state.contract_pubkey(neon_addess).0; + Ok(sol_address.to_bytes().to_vec()) + } + + // "59e4ad63": "getResourceAddress(bytes32)" + [0x59, 0xe4, 0xad, 0x63] => { + let salt = read_salt(input)?; + let seeds: &[&[u8]] = &[ + &[ACCOUNT_SEED_VERSION], + b"ContractData", + context.caller.as_bytes(), + salt, + ]; + let (sol_address, _) = Pubkey::find_program_address(seeds, state.program_id()); + Ok(sol_address.to_bytes().to_vec()) + } + + // "cd2d1a3a": "getExtAuthority(bytes32)" + [0xcd, 0x2d, 0x1a, 0x3a] => { + let salt = read_salt(input)?; + let seeds: &[&[u8]] = &[ + &[ACCOUNT_SEED_VERSION], + b"AUTH", + context.caller.as_bytes(), + salt, + ]; + let (sol_address, _) = Pubkey::find_program_address(seeds, state.program_id()); + Ok(sol_address.to_bytes().to_vec()) + } + + // "4a890f31": "getSolanaPDA(bytes32,bytes)" + [0x4a, 0x89, 0x0f, 0x31] => { + let program_id = read_pubkey(&input[0..])?; + let offset = read_usize(&input[32..])?; + let length = read_usize(&input[offset..])?; + let mut seeds = Vec::with_capacity((length + 31) / 32); + for i in 0..length / 32 { + seeds.push(&input[offset + 32 + i * 32..offset + 32 + (i + 1) * 32]); + } + if length % 32 != 0 { + seeds.push(&input[offset + 32 + length - length % 32..offset + 32 + length]); + } + let (sol_address, _) = Pubkey::find_program_address(&seeds, &program_id); + Ok(sol_address.to_bytes().to_vec()) + } + + // "30aa81c6": "getPayer()" + [0x30, 0xaa, 0x81, 0xc6] => { + let seeds: &[&[u8]] = &[&[ACCOUNT_SEED_VERSION], b"PAYER", context.caller.as_bytes()]; + let (sol_address, _bump_seed) = Pubkey::find_program_address(seeds, state.program_id()); + + Ok(sol_address.to_bytes().to_vec()) + } + + // "cfd51d32": "createResource(bytes32,uint64,uint64,bytes32)" + [0xcf, 0xd5, 0x1d, 0x32] => { + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let salt = read_salt(&input[0..])?; + let space = read_usize(&input[32..])?; + let _lamports = read_u64(&input[64..])?; + let owner = read_pubkey(&input[96..])?; + + let (sol_address, bump_seed) = Pubkey::find_program_address( + &[ + &[ACCOUNT_SEED_VERSION], + b"ContractData", + context.caller.as_bytes(), + salt, + ], + state.program_id(), + ); + let account = state.external_account(sol_address).await?; + let seeds: Vec> = vec![ + vec![ACCOUNT_SEED_VERSION], + b"ContractData".to_vec(), + context.caller.as_bytes().to_vec(), + salt.to_vec(), + vec![bump_seed], + ]; + + super::create_account(state, &account, space, &owner, seeds).await?; + Ok(sol_address.to_bytes().to_vec()) + } + + // "cff5c1a5": "getReturnData()", + [0xcf, 0xf5, 0xc1, 0xa5] => { + let return_value = match state.return_data() { + Some((program, data)) => { + let data_len = (data.len() + 31) & (!31); + let mut result = vec![0_u8; 32 + 32 + 32 + data_len]; + + result[0..32].copy_from_slice(&program.to_bytes()); + result[63] = 0x40; // offset - 64 bytes + + let length = U256::new(data.len() as u128); + result[64..96].copy_from_slice(&length.to_be_bytes()); + result[96..96 + data.len()].copy_from_slice(&data); + + result + } + None => { + vec![ + // program_id + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // offset of data + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + // length of data + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + } + }; + + Ok(return_value) + } + + _ => Err(Error::UnknownPrecompileMethodSelector(*address, selector)), + } +} + +#[maybe_async] +async fn execute_external_instruction( + state: &mut State, + context: &crate::evm::Context, + instruction: Instruction, + signer_seeds: Vec>, + required_lamports: u64, +) -> Result> { + #[cfg(not(target_os = "solana"))] + log::info!("instruction: {:?}", instruction); + + let called_program = instruction.program_id; + state.set_return_data(&[]); + + if called_program == *state.program_id() { + return Err(Error::RecursiveCall); + } + + for meta in &instruction.accounts { + if meta.pubkey == state.operator() || meta.pubkey == *state.program_id() { + return Err(Error::InvalidAccountForCall(meta.pubkey)); + } + } + + let payer_seeds: &[&[u8]] = &[&[ACCOUNT_SEED_VERSION], b"PAYER", context.caller.as_bytes()]; + let (payer_pubkey, payer_bump_seed) = + Pubkey::find_program_address(payer_seeds, state.program_id()); + let required_payer = instruction + .accounts + .iter() + .any(|meta| meta.pubkey == payer_pubkey); + + if required_payer { + let payer_seeds = vec![ + vec![ACCOUNT_SEED_VERSION], + b"PAYER".to_vec(), + context.caller.as_bytes().to_vec(), + vec![payer_bump_seed], + ]; + + let payer = state.external_account(payer_pubkey).await?; + if payer.lamports < required_lamports { + let transfer_instruction = solana_program::system_instruction::transfer( + &state.operator(), + &payer_pubkey, + required_lamports - payer.lamports, + ); + state + .queue_external_instruction(transfer_instruction, vec![], 0, false) + .await?; + } + + state + .queue_external_instruction( + instruction, + vec![signer_seeds, payer_seeds.clone()], + required_lamports, + false, + ) + .await?; + + let payer = state.external_account(payer_pubkey).await?; + if payer.lamports > 0 { + let transfer_instruction = solana_program::system_instruction::transfer( + &payer_pubkey, + &state.operator(), + payer.lamports, + ); + state + .queue_external_instruction(transfer_instruction, vec![payer_seeds], 0, false) + .await?; + } + } else { + state + .queue_external_instruction(instruction, vec![signer_seeds], required_lamports, false) + .await?; + } + + let return_data = state + .return_data() + .and_then(|(program, data)| { + if program == called_program { + Some(data) + } else { + None + } + }) + .unwrap_or_default(); + Ok(to_solidity_bytes(&return_data)) +} + +#[inline] +fn read_instruction(input: &[u8]) -> Result { + let program_id = read_pubkey(&input[0..])?; + let accounts_offset = read_usize(&input[32..])?; + + let data_offset = read_usize(&input[64..])?; + let data_length = read_usize(&input[data_offset..])?; + + let accounts_length = read_usize(&input[accounts_offset..])?; + let mut accounts = Vec::with_capacity(accounts_length); + for i in 0..accounts_length { + let acc_offset = accounts_offset + 32 + i * 96; + let pubkey = read_pubkey(&input[acc_offset..])?; + let is_signer = read_u8(&input[acc_offset + 32..])? != 0; + let is_writable = read_u8(&input[acc_offset + 64..])? != 0; + accounts.push(AccountMeta { + pubkey, + is_signer, + is_writable, + }); + } + + Ok(Instruction { + program_id, + accounts, + data: input[data_offset + 32..data_offset + 32 + data_length].to_vec(), + }) +} + +#[inline] +fn read_u8(input: &[u8]) -> Result { + U256::from_be_bytes(*arrayref::array_ref![input, 0, 32]) + .try_into() + .map_err(Into::into) +} + +#[inline] +fn read_u64(input: &[u8]) -> Result { + U256::from_be_bytes(*arrayref::array_ref![input, 0, 32]) + .try_into() + .map_err(Into::into) +} + +#[inline] +fn read_usize(input: &[u8]) -> Result { + U256::from_be_bytes(*arrayref::array_ref![input, 0, 32]) + .try_into() + .map_err(Into::into) +} + +#[inline] +fn read_pubkey(input: &[u8]) -> Result { + if input.len() < 32 { + return Err(Error::OutOfBounds); + } + Ok(Pubkey::new_from_array(*arrayref::array_ref![input, 0, 32])) +} + +#[inline] +fn read_salt(input: &[u8]) -> Result<&[u8; 32]> { + if input.len() < 32 { + return Err(Error::OutOfBounds); + } + Ok(arrayref::array_ref![input, 0, 32]) +} + +fn to_solidity_bytes(b: &[u8]) -> Vec { + // Bytes encoding + // 32 bytes - offset + // 32 bytes - length + // length + padding bytes - data + + let data_len = (b.len() + 31) & (!31); + let mut result = vec![0_u8; 32 + 32 + data_len]; + + result[31] = 0x20; // offset - 32 bytes + + let length = U256::new(b.len() as u128); + result[32..64].copy_from_slice(&length.to_be_bytes()); + result[64..64 + b.len()].copy_from_slice(b); + + result +} diff --git a/evm_loader/program/src/executor/precompile_extension/metaplex.rs b/evm_loader/program/src/executor/precompile_extension/metaplex.rs index 48fe2fd51..1da971bb7 100644 --- a/evm_loader/program/src/executor/precompile_extension/metaplex.rs +++ b/evm_loader/program/src/executor/precompile_extension/metaplex.rs @@ -14,9 +14,8 @@ use solana_program::pubkey::Pubkey; use crate::{ account::ACCOUNT_SEED_VERSION, - account_storage::AccountStorage, error::{Error, Result}, - executor::ExecutorState, + evm::database::Database, types::Address, }; @@ -59,6 +58,81 @@ pub const MAX_MASTER_EDITION_LEN: usize = 1 + 9 + 8 + 264; // "[0x69, 0x1f, 0x34, 0x31]": "name(bytes32)" // "[0x6b, 0xaa, 0x03, 0x30]": "symbol(bytes32)" +#[maybe_async] +pub async fn metaplex( + state: &mut State, + address: &Address, + input: &[u8], + context: &crate::evm::Context, + is_static: bool, +) -> Result> { + if context.value != 0 { + return Err(Error::Custom("Metaplex: value != 0".to_string())); + } + + if &context.contract != address { + return Err(Error::Custom( + "Metaplex: callcode or delegatecall is not allowed".to_string(), + )); + } + + let (selector, input) = input.split_at(4); + let selector: [u8; 4] = selector.try_into()?; + + match selector { + [0xc5, 0x73, 0x50, 0xc6] => { + // "createMetadata(bytes32,string,string,string)" + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let mint = read_pubkey(input)?; + let name = read_string(input, 32, 256)?; + let symbol = read_string(input, 64, 256)?; + let uri = read_string(input, 96, 1024)?; + + create_metadata(context, state, mint, name, symbol, uri).await + } + [0x4a, 0xe8, 0xb6, 0x6b] => { + // "createMasterEdition(bytes32,uint64)" + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let mint = read_pubkey(input)?; + let max_supply = read_u64(&input[32..])?; + + create_master_edition(context, state, mint, Some(max_supply)).await + } + [0xf7, 0xb6, 0x37, 0xbb] => { + // "isInitialized(bytes32)" + let mint = read_pubkey(input)?; + is_initialized(context, state, mint).await + } + [0x23, 0x5b, 0x2b, 0x94] => { + // "isNFT(bytes32)" + let mint = read_pubkey(input)?; + is_nft(context, state, mint).await + } + [0x9e, 0xd1, 0x9d, 0xdb] => { + // "uri(bytes32)" + let mint = read_pubkey(input)?; + uri(context, state, mint).await + } + [0x69, 0x1f, 0x34, 0x31] => { + // "name(bytes32)" + let mint = read_pubkey(input)?; + token_name(context, state, mint).await + } + [0x6b, 0xaa, 0x03, 0x30] => { + // "symbol(bytes32)" + let mint = read_pubkey(input)?; + symbol(context, state, mint).await + } + _ => Err(Error::UnknownPrecompileMethodSelector(*address, selector)), + } +} + #[inline] fn read_u64(input: &[u8]) -> Result { if input.len() < 32 { @@ -102,248 +176,189 @@ fn read_string(input: &[u8], offset_position: usize, max_length: usize) -> Resul String::from_utf8(data).map_err(|_| Error::Custom("Invalid utf8 string".to_string())) } -impl ExecutorState<'_, B> { - #[maybe_async] - pub async fn metaplex( - &mut self, - address: &Address, - input: &[u8], - context: &crate::evm::Context, - is_static: bool, - ) -> Result> { - if context.value != 0 { - return Err(Error::Custom("Metaplex: value != 0".to_string())); - } - - if &context.contract != address { - return Err(Error::Custom( - "Metaplex: callcode or delegatecall is not allowed".to_string(), - )); - } - - let (selector, input) = input.split_at(4); - let selector: [u8; 4] = selector.try_into()?; - - match selector { - [0xc5, 0x73, 0x50, 0xc6] => { - // "createMetadata(bytes32,string,string,string)" - if is_static { - return Err(Error::StaticModeViolation(*address)); - } - - let mint = read_pubkey(input)?; - let name = read_string(input, 32, 256)?; - let symbol = read_string(input, 64, 256)?; - let uri = read_string(input, 96, 1024)?; - - self.create_metadata(context, mint, name, symbol, uri) - } - [0x4a, 0xe8, 0xb6, 0x6b] => { - // "createMasterEdition(bytes32,uint64)" - if is_static { - return Err(Error::StaticModeViolation(*address)); - } - - let mint = read_pubkey(input)?; - let max_supply = read_u64(&input[32..])?; - - self.create_master_edition(context, mint, Some(max_supply)) - } - [0xf7, 0xb6, 0x37, 0xbb] => { - // "isInitialized(bytes32)" - let mint = read_pubkey(input)?; - self.is_initialized(context, mint).await - } - [0x23, 0x5b, 0x2b, 0x94] => { - // "isNFT(bytes32)" - let mint = read_pubkey(input)?; - self.is_nft(context, mint).await - } - [0x9e, 0xd1, 0x9d, 0xdb] => { - // "uri(bytes32)" - let mint = read_pubkey(input)?; - self.uri(context, mint).await - } - [0x69, 0x1f, 0x34, 0x31] => { - // "name(bytes32)" - let mint = read_pubkey(input)?; - self.token_name(context, mint).await - } - [0x6b, 0xaa, 0x03, 0x30] => { - // "symbol(bytes32)" - let mint = read_pubkey(input)?; - self.symbol(context, mint).await - } - _ => Err(Error::UnknownPrecompileMethodSelector(*address, selector)), - } - } - - fn create_metadata( - &mut self, - context: &crate::evm::Context, - mint: Pubkey, - name: String, - symbol: String, - uri: String, - ) -> Result> { - let signer = context.caller; - let (signer_pubkey, bump_seed) = self.backend.contract_pubkey(signer); - - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], - ]; - - let (metadata_pubkey, _) = Metadata::find_pda(&mint); - - let instruction = CreateMetadataAccountV3Builder::new() - .metadata(metadata_pubkey) - .mint(mint) - .mint_authority(signer_pubkey) - .update_authority(signer_pubkey, true) - .payer(self.backend.operator()) - .is_mutable(true) - .data(DataV2 { - name, - symbol, - uri, - seller_fee_basis_points: 0, - creators: Some(vec![ - Creator { - address: *self.backend.program_id(), - verified: false, - share: 0, - }, - Creator { - address: signer_pubkey, - verified: true, - share: 100, - }, - ]), - collection: None, - uses: None, - }) - .instruction(); - - let fee = self.backend.rent().minimum_balance(MAX_METADATA_LEN) + CREATE_FEE; - self.queue_external_instruction(instruction, seeds, fee); - - Ok(metadata_pubkey.to_bytes().to_vec()) - } - - fn create_master_edition( - &mut self, - context: &crate::evm::Context, - mint: Pubkey, - max_supply: Option, - ) -> Result> { - let signer = context.caller; - let (signer_pubkey, bump_seed) = self.backend.contract_pubkey(signer); - - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], - ]; - - let (metadata_pubkey, _) = Metadata::find_pda(&mint); - let (edition_pubkey, _) = MasterEdition::find_pda(&mint); - - let mut instruction_builder = CreateMasterEditionV3Builder::new(); - instruction_builder - .metadata(metadata_pubkey) - .edition(edition_pubkey) - .mint(mint) - .mint_authority(signer_pubkey) - .update_authority(signer_pubkey) - .payer(self.backend.operator()); - - if let Some(max_supply) = max_supply { - instruction_builder.max_supply(max_supply); - } - - let instruction = instruction_builder.instruction(); - - let fee = self.backend.rent().minimum_balance(MAX_MASTER_EDITION_LEN) + CREATE_FEE; - self.queue_external_instruction(instruction, seeds, fee); - - Ok(edition_pubkey.to_bytes().to_vec()) - } +#[maybe_async] +async fn create_metadata( + context: &crate::evm::Context, + state: &mut State, + mint: Pubkey, + name: String, + symbol: String, + uri: String, +) -> Result> { + let signer = context.caller; + let (signer_pubkey, bump_seed) = state.contract_pubkey(signer); + + let seeds = vec![ + vec![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vec(), + vec![bump_seed], + ]; + + let (metadata_pubkey, _) = Metadata::find_pda(&mint); + + let instruction = CreateMetadataAccountV3Builder::new() + .metadata(metadata_pubkey) + .mint(mint) + .mint_authority(signer_pubkey) + .update_authority(signer_pubkey, true) + .payer(state.operator()) + .is_mutable(true) + .data(DataV2 { + name, + symbol, + uri, + seller_fee_basis_points: 0, + creators: Some(vec![ + Creator { + address: *state.program_id(), + verified: false, + share: 0, + }, + Creator { + address: signer_pubkey, + verified: true, + share: 100, + }, + ]), + collection: None, + uses: None, + }) + .instruction(); + + let fee = state.rent().minimum_balance(MAX_METADATA_LEN) + CREATE_FEE; + state + .queue_external_instruction(instruction, vec![seeds], fee, true) + .await?; + + Ok(metadata_pubkey.to_bytes().to_vec()) +} - #[maybe_async] - async fn is_initialized( - &mut self, - context: &crate::evm::Context, - mint: Pubkey, - ) -> Result> { - let is_initialized = self - .metadata(context, mint) - .await? - .map_or_else(|| false, |_| true); - - Ok(to_solidity_bool(is_initialized)) +#[maybe_async] +async fn create_master_edition( + context: &crate::evm::Context, + state: &mut State, + mint: Pubkey, + max_supply: Option, +) -> Result> { + let signer = context.caller; + let (signer_pubkey, bump_seed) = state.contract_pubkey(signer); + + let seeds = vec![ + vec![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vec(), + vec![bump_seed], + ]; + + let (metadata_pubkey, _) = Metadata::find_pda(&mint); + let (edition_pubkey, _) = MasterEdition::find_pda(&mint); + + let mut instruction_builder = CreateMasterEditionV3Builder::new(); + instruction_builder + .metadata(metadata_pubkey) + .edition(edition_pubkey) + .mint(mint) + .mint_authority(signer_pubkey) + .update_authority(signer_pubkey) + .payer(state.operator()); + + if let Some(max_supply) = max_supply { + instruction_builder.max_supply(max_supply); } - #[maybe_async] - async fn is_nft(&mut self, context: &crate::evm::Context, mint: Pubkey) -> Result> { - let is_nft = self.metadata(context, mint).await?.map_or_else( - || false, - |m| m.token_standard == Some(TokenStandard::NonFungible), - ); + let instruction = instruction_builder.instruction(); - Ok(to_solidity_bool(is_nft)) - } + let fee = state.rent().minimum_balance(MAX_MASTER_EDITION_LEN) + CREATE_FEE; + state + .queue_external_instruction(instruction, vec![seeds], fee, true) + .await?; - #[maybe_async] - async fn uri(&mut self, context: &crate::evm::Context, mint: Pubkey) -> Result> { - let uri = self - .metadata(context, mint) - .await? - .map_or_else(String::new, |m| m.uri); + Ok(edition_pubkey.to_bytes().to_vec()) +} - Ok(to_solidity_string(uri.trim_end_matches('\0'))) - } +#[maybe_async] +async fn is_initialized( + context: &crate::evm::Context, + state: &State, + mint: Pubkey, +) -> Result> { + let is_initialized = metadata(context, state, mint) + .await? + .map_or_else(|| false, |_| true); + + Ok(to_solidity_bool(is_initialized)) +} - #[maybe_async] - async fn token_name(&mut self, context: &crate::evm::Context, mint: Pubkey) -> Result> { - let token_name = self - .metadata(context, mint) - .await? - .map_or_else(String::new, |m| m.name); +#[maybe_async] +async fn is_nft( + context: &crate::evm::Context, + state: &State, + mint: Pubkey, +) -> Result> { + let is_nft = metadata(context, state, mint).await?.map_or_else( + || false, + |m| m.token_standard == Some(TokenStandard::NonFungible), + ); + + Ok(to_solidity_bool(is_nft)) +} - Ok(to_solidity_string(token_name.trim_end_matches('\0'))) - } +#[maybe_async] +async fn uri( + context: &crate::evm::Context, + state: &State, + mint: Pubkey, +) -> Result> { + let uri = metadata(context, state, mint) + .await? + .map_or_else(String::new, |m| m.uri); + + Ok(to_solidity_string(uri.trim_end_matches('\0'))) +} - #[maybe_async] - async fn symbol(&mut self, context: &crate::evm::Context, mint: Pubkey) -> Result> { - let symbol = self - .metadata(context, mint) - .await? - .map_or_else(String::new, |m| m.symbol); +#[maybe_async] +async fn token_name( + context: &crate::evm::Context, + state: &State, + mint: Pubkey, +) -> Result> { + let token_name = metadata(context, state, mint) + .await? + .map_or_else(String::new, |m| m.name); + + Ok(to_solidity_string(token_name.trim_end_matches('\0'))) +} - Ok(to_solidity_string(symbol.trim_end_matches('\0'))) - } +#[maybe_async] +async fn symbol( + context: &crate::evm::Context, + state: &State, + mint: Pubkey, +) -> Result> { + let symbol = metadata(context, state, mint) + .await? + .map_or_else(String::new, |m| m.symbol); + + Ok(to_solidity_string(symbol.trim_end_matches('\0'))) +} - #[maybe_async] - async fn metadata( - &mut self, - _context: &crate::evm::Context, - mint: Pubkey, - ) -> Result> { - let (metadata_pubkey, _) = Metadata::find_pda(&mint); - let metadata_account = self.external_account(metadata_pubkey).await?; - - let result = { - if MPL_TOKEN_METADATA_ID == metadata_account.owner { - let metadata = Metadata::safe_deserialize(&metadata_account.data); - metadata.ok() - } else { - None - } - }; - Ok(result) - } +#[maybe_async] +async fn metadata( + _context: &crate::evm::Context, + state: &State, + mint: Pubkey, +) -> Result> { + let (metadata_pubkey, _) = Metadata::find_pda(&mint); + let metadata_account = state.external_account(metadata_pubkey).await?; + + let result = { + if MPL_TOKEN_METADATA_ID == metadata_account.owner { + let metadata = Metadata::safe_deserialize(&metadata_account.data); + metadata.ok() + } else { + None + } + }; + Ok(result) } fn to_solidity_bool(v: bool) -> Vec { diff --git a/evm_loader/program/src/executor/precompile_extension/mod.rs b/evm_loader/program/src/executor/precompile_extension/mod.rs index 0d9eb91bd..c527bf3a7 100644 --- a/evm_loader/program/src/executor/precompile_extension/mod.rs +++ b/evm_loader/program/src/executor/precompile_extension/mod.rs @@ -1,14 +1,22 @@ -use crate::{account_storage::AccountStorage, error::Result, evm::Context, types::Address}; +use crate::{ + error::Result, + evm::{database::Database, Context}, + types::Address, +}; use maybe_async::maybe_async; +use solana_program::{pubkey::Pubkey, system_instruction}; -use super::ExecutorState; +use super::OwnedAccountInfo; +mod call_solana; mod metaplex; mod neon_token; mod query_account; mod spl_token; -impl ExecutorState<'_, B> { +pub struct PrecompiledContracts {} + +impl PrecompiledContracts { #[deprecated] const _SYSTEM_ACCOUNT_ERC20_WRAPPER: Address = Address([ 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01, @@ -25,19 +33,22 @@ impl ExecutorState<'_, B> { const SYSTEM_ACCOUNT_METAPLEX: Address = Address([ 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x05, ]); + const SYSTEM_ACCOUNT_CALL_SOLANA: Address = Address([ + 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x06, + ]); #[must_use] - #[allow(clippy::unused_self)] - pub fn is_precompile_extension(&self, address: &Address) -> bool { + pub fn is_precompile_extension(address: &Address) -> bool { *address == Self::SYSTEM_ACCOUNT_QUERY || *address == Self::SYSTEM_ACCOUNT_NEON_TOKEN || *address == Self::SYSTEM_ACCOUNT_SPL_TOKEN || *address == Self::SYSTEM_ACCOUNT_METAPLEX + || *address == Self::SYSTEM_ACCOUNT_CALL_SOLANA } #[maybe_async] - pub async fn call_precompile_extension( - &mut self, + pub async fn call_precompile_extension( + state: &mut State, context: &Context, address: &Address, input: &[u8], @@ -45,18 +56,54 @@ impl ExecutorState<'_, B> { ) -> Option>> { match *address { Self::SYSTEM_ACCOUNT_QUERY => { - Some(self.query_account(address, input, context, is_static).await) + Some(query_account::query_account(state, address, input, context, is_static).await) } Self::SYSTEM_ACCOUNT_NEON_TOKEN => { - Some(self.neon_token(address, input, context, is_static).await) + Some(neon_token::neon_token(state, address, input, context, is_static).await) } Self::SYSTEM_ACCOUNT_SPL_TOKEN => { - Some(self.spl_token(address, input, context, is_static).await) + Some(spl_token::spl_token(state, address, input, context, is_static).await) } Self::SYSTEM_ACCOUNT_METAPLEX => { - Some(self.metaplex(address, input, context, is_static).await) + Some(metaplex::metaplex(state, address, input, context, is_static).await) + } + Self::SYSTEM_ACCOUNT_CALL_SOLANA => { + Some(call_solana::call_solana(state, address, input, context, is_static).await) } _ => None, } } } + +#[maybe_async] +pub async fn create_account( + state: &mut State, + account: &OwnedAccountInfo, + space: usize, + owner: &Pubkey, + seeds: Vec>, +) -> Result<()> { + let minimum_balance = state.rent().minimum_balance(space); + + let required_lamports = minimum_balance.saturating_sub(account.lamports); + + if required_lamports > 0 { + let transfer = + system_instruction::transfer(&state.operator(), &account.key, required_lamports); + state + .queue_external_instruction(transfer, vec![], required_lamports, true) + .await?; + } + + let allocate = system_instruction::allocate(&account.key, space.try_into().unwrap()); + state + .queue_external_instruction(allocate, vec![seeds.clone()], 0, true) + .await?; + + let assign = system_instruction::assign(&account.key, owner); + state + .queue_external_instruction(assign, vec![seeds], 0, true) + .await?; + + Ok(()) +} diff --git a/evm_loader/program/src/executor/precompile_extension/neon_token.rs b/evm_loader/program/src/executor/precompile_extension/neon_token.rs index 8fef61051..bbbb73242 100644 --- a/evm_loader/program/src/executor/precompile_extension/neon_token.rs +++ b/evm_loader/program/src/executor/precompile_extension/neon_token.rs @@ -8,9 +8,8 @@ use spl_associated_token_account::get_associated_token_address; use crate::{ account::token, - account_storage::AccountStorage, error::{Error, Result}, - executor::ExecutorState, + evm::database::Database, types::Address, }; @@ -20,128 +19,126 @@ use crate::{ //-------------------------------------------------- const NEON_TOKEN_METHOD_WITHDRAW_ID: &[u8; 4] = &[0x8e, 0x19, 0x89, 0x9e]; -impl ExecutorState<'_, B> { - #[maybe_async] - pub async fn neon_token( - &mut self, - address: &Address, - input: &[u8], - context: &crate::evm::Context, - is_static: bool, - ) -> Result> { - debug_print!("neon_token({})", hex::encode(input)); - - if &context.contract != address { - return Err(Error::Custom( - "Withdraw: callcode or delegatecall is not allowed".to_string(), - )); - } - - let (method_id, rest) = input.split_at(4); - let method_id: &[u8; 4] = method_id.try_into().unwrap_or(&[0_u8; 4]); +#[maybe_async] +pub async fn neon_token( + state: &mut State, + address: &Address, + input: &[u8], + context: &crate::evm::Context, + is_static: bool, +) -> Result> { + debug_print!("neon_token({})", hex::encode(input)); + + if &context.contract != address { + return Err(Error::Custom( + "Withdraw: callcode or delegatecall is not allowed".to_string(), + )); + } - if method_id == NEON_TOKEN_METHOD_WITHDRAW_ID { - if is_static { - return Err(Error::StaticModeViolation(*address)); - } + let (method_id, rest) = input.split_at(4); + let method_id: &[u8; 4] = method_id.try_into().unwrap_or(&[0_u8; 4]); - let source = context.contract; - let chain_id = context.contract_chain_id; - let value = context.value; - // owner of the associated token account - let destination = array_ref![rest, 0, 32]; - let destination = Pubkey::new_from_array(*destination); + if method_id == NEON_TOKEN_METHOD_WITHDRAW_ID { + if is_static { + return Err(Error::StaticModeViolation(*address)); + } - self.withdraw(source, chain_id, destination, value).await?; + let source = context.contract; + let chain_id = context.contract_chain_id; + let value = context.value; + // owner of the associated token account + let destination = array_ref![rest, 0, 32]; + let destination = Pubkey::new_from_array(*destination); - let mut output = vec![0_u8; 32]; - output[31] = 1; // return true + withdraw(state, source, chain_id, destination, value).await?; - return Ok(output); - }; + let mut output = vec![0_u8; 32]; + output[31] = 1; // return true - debug_print!("neon_token UNKNOWN"); - Err(Error::UnknownPrecompileMethodSelector(*address, *method_id)) - } + return Ok(output); + }; - #[maybe_async] - async fn withdraw( - &mut self, - source: Address, - chain_id: u64, - target: Pubkey, - value: U256, - ) -> Result<()> { - if value == 0 { - return Err(Error::Custom("Neon Withdraw: value == 0".to_string())); - } + debug_print!("neon_token UNKNOWN"); + Err(Error::UnknownPrecompileMethodSelector(*address, *method_id)) +} - let mint_address = self.backend.chain_id_to_token(chain_id); +#[maybe_async] +async fn withdraw( + state: &mut State, + source: Address, + chain_id: u64, + target: Pubkey, + value: U256, +) -> Result<()> { + if value == 0 { + return Err(Error::Custom("Neon Withdraw: value == 0".to_string())); + } - let mut mint_account = self.external_account(mint_address).await?; - let mint_data = { - let info = mint_account.into_account_info(); - token::Mint::from_account(&info)?.into_data() - }; + let mint_address = state.chain_id_to_token(chain_id); - assert!(mint_data.decimals < 18); + let mut mint_account = state.external_account(mint_address).await?; + let mint_data = { + let info = mint_account.into_account_info(); + token::Mint::from_account(&info)?.into_data() + }; - let additional_decimals: u32 = (18 - mint_data.decimals).into(); - let min_amount: u128 = u128::pow(10, additional_decimals); + assert!(mint_data.decimals < 18); - let spl_amount = value / min_amount; - let remainder = value % min_amount; + let additional_decimals: u32 = (18 - mint_data.decimals).into(); + let min_amount: u128 = u128::pow(10, additional_decimals); - if spl_amount > U256::from(u64::MAX) { - return Err(Error::Custom( - "Neon Withdraw: value exceeds u64::max".to_string(), - )); - } + let spl_amount = value / min_amount; + let remainder = value % min_amount; - if remainder != 0 { - return Err(Error::Custom(std::format!( - "Neon Withdraw: value must be divisible by 10^{additional_decimals}" - ))); - } + if spl_amount > U256::from(u64::MAX) { + return Err(Error::Custom( + "Neon Withdraw: value exceeds u64::max".to_string(), + )); + } - let target_token = get_associated_token_address(&target, &mint_address); - let account = self.external_account(target_token).await?; - if !spl_token::check_id(&account.owner) { - use spl_associated_token_account::instruction::create_associated_token_account; - - let create_associated = create_associated_token_account( - &self.backend.operator(), - &target, - &mint_address, - &spl_token::ID, - ); - - let fee = self - .backend - .rent() - .minimum_balance(spl_token::state::Account::LEN); - self.queue_external_instruction(create_associated, vec![], fee); - } + if remainder != 0 { + return Err(Error::Custom(std::format!( + "Neon Withdraw: value must be divisible by 10^{additional_decimals}" + ))); + } - let (authority, bump_seed) = - Pubkey::find_program_address(&[b"Deposit"], self.backend.program_id()); - let pool = get_associated_token_address(&authority, &mint_address); + let target_token = get_associated_token_address(&target, &mint_address); + let account = state.external_account(target_token).await?; + if !spl_token::check_id(&account.owner) { + use spl_associated_token_account::instruction::create_associated_token_account; - let transfer = spl_token::instruction::transfer_checked( - &spl_token::ID, - &pool, + let create_associated = create_associated_token_account( + &state.operator(), + &target, &mint_address, - &target_token, - &authority, - &[], - spl_amount.as_u64(), - mint_data.decimals, - )?; - let transfer_seeds = vec![b"Deposit".to_vec(), vec![bump_seed]]; - self.queue_external_instruction(transfer, transfer_seeds, 0); - - self.burn(source, chain_id, value); - - Ok(()) + &spl_token::ID, + ); + + let fee = state.rent().minimum_balance(spl_token::state::Account::LEN); + state + .queue_external_instruction(create_associated, vec![], fee, true) + .await?; } + + let (authority, bump_seed) = Pubkey::find_program_address(&[b"Deposit"], state.program_id()); + let pool = get_associated_token_address(&authority, &mint_address); + + let transfer = spl_token::instruction::transfer_checked( + &spl_token::ID, + &pool, + &mint_address, + &target_token, + &authority, + &[], + spl_amount.as_u64(), + mint_data.decimals, + )?; + let transfer_seeds = vec![b"Deposit".to_vec(), vec![bump_seed]]; + state + .queue_external_instruction(transfer, vec![transfer_seeds], 0, true) + .await?; + + state.burn(source, chain_id, value).await?; + + Ok(()) } diff --git a/evm_loader/program/src/executor/precompile_extension/query_account.rs b/evm_loader/program/src/executor/precompile_extension/query_account.rs index d08e97649..7c84ef27f 100644 --- a/evm_loader/program/src/executor/precompile_extension/query_account.rs +++ b/evm_loader/program/src/executor/precompile_extension/query_account.rs @@ -6,9 +6,8 @@ use maybe_async::maybe_async; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; use crate::{ - account_storage::AccountStorage, error::{Error, Result}, - executor::ExecutorState, + evm::database::Database, types::Address, }; @@ -31,191 +30,186 @@ use crate::{ // "a9dbaf25": "length(bytes32)", // "7dd6c1a0": "data(bytes32,uint64,uint64)", -impl ExecutorState<'_, B> { - #[maybe_async] - pub async fn query_account( - &mut self, - address: &Address, - input: &[u8], - context: &crate::evm::Context, - _is_static: bool, - ) -> Result> { - debug_print!("query_account({})", hex::encode(input)); - - if context.value != 0 { - return Err(Error::Custom("Query Account: value != 0".to_string())); - } +#[maybe_async] +pub async fn query_account( + state: &State, + address: &Address, + input: &[u8], + context: &crate::evm::Context, + _is_static: bool, +) -> Result> { + debug_print!("query_account({})", hex::encode(input)); + + if context.value != 0 { + return Err(Error::Custom("Query Account: value != 0".to_string())); + } + + let (method_id, rest) = input.split_at(4); + let method_id: [u8; 4] = method_id.try_into()?; + + let (account_address, rest) = rest.split_at(32); + let account_address = Pubkey::try_from(account_address)?; - let (method_id, rest) = input.split_at(4); - let method_id: [u8; 4] = method_id.try_into()?; - - let (account_address, rest) = rest.split_at(32); - let account_address = Pubkey::try_from(account_address)?; - - match method_id { - [0x2b, 0x3c, 0x83, 0x22] => { - // cache(uint256,uint64,uint64) - // deprecated - Ok(Vec::new()) - } - [0xa1, 0x23, 0xc3, 0x3e] | [0x02, 0x57, 0x1b, 0xe3] => { - debug_print!("query_account.owner({})", &account_address); - self.account_owner(&account_address).await - } - [0xaa, 0x8b, 0x99, 0xd2] | [0xa9, 0xdb, 0xaf, 0x25] => { - debug_print!("query_account.length({})", &account_address); - self.account_data_length(&account_address).await - } - [0x74, 0x8f, 0x2d, 0x8a] | [0x62, 0x73, 0x44, 0x8f] => { - debug_print!("query_account.lamports({})", &account_address); - self.account_lamports(&account_address).await - } - [0xc2, 0x19, 0xa7, 0x85] | [0xe6, 0xbe, 0xf4, 0x88] => { - debug_print!("query_account.executable({})", &account_address); - self.account_is_executable(&account_address).await - } - [0xc4, 0xd3, 0x69, 0xb5] | [0x8b, 0xb9, 0xe6, 0xf4] => { - debug_print!("query_account.rent_epoch({})", &account_address); - self.account_rent_epoch(&account_address).await - } - [0x43, 0xca, 0x51, 0x61] | [0x7d, 0xd6, 0xc1, 0xa0] => { - let arguments = array_ref![rest, 0, 64]; - let (offset, length) = array_refs!(arguments, 32, 32); - let offset = U256::from_be_bytes(*offset).try_into()?; - let length = U256::from_be_bytes(*length).try_into()?; - debug_print!( - "query_account.data({}, {}, {})", - account_address, - offset, - length - ); - self.account_data(&account_address, offset, length).await - } - [0xb6, 0x4a, 0x09, 0x7e] => { - debug_print!("query_account.info({})", &account_address); - self.account_info(&account_address).await - } - _ => { - debug_print!("query_account UNKNOWN {:?}", method_id); - Err(Error::UnknownPrecompileMethodSelector(*address, method_id)) - } + match method_id { + [0x2b, 0x3c, 0x83, 0x22] => { + // cache(uint256,uint64,uint64) + // deprecated + Ok(Vec::new()) + } + [0xa1, 0x23, 0xc3, 0x3e] | [0x02, 0x57, 0x1b, 0xe3] => { + debug_print!("query_account.owner({})", &account_address); + account_owner(state, &account_address).await + } + [0xaa, 0x8b, 0x99, 0xd2] | [0xa9, 0xdb, 0xaf, 0x25] => { + debug_print!("query_account.length({})", &account_address); + account_data_length(state, &account_address).await + } + [0x74, 0x8f, 0x2d, 0x8a] | [0x62, 0x73, 0x44, 0x8f] => { + debug_print!("query_account.lamports({})", &account_address); + account_lamports(state, &account_address).await + } + [0xc2, 0x19, 0xa7, 0x85] | [0xe6, 0xbe, 0xf4, 0x88] => { + debug_print!("query_account.executable({})", &account_address); + account_is_executable(state, &account_address).await + } + [0xc4, 0xd3, 0x69, 0xb5] | [0x8b, 0xb9, 0xe6, 0xf4] => { + debug_print!("query_account.rent_epoch({})", &account_address); + account_rent_epoch(state, &account_address).await + } + [0x43, 0xca, 0x51, 0x61] | [0x7d, 0xd6, 0xc1, 0xa0] => { + let arguments = array_ref![rest, 0, 64]; + let (offset, length) = array_refs!(arguments, 32, 32); + let offset = U256::from_be_bytes(*offset).try_into()?; + let length = U256::from_be_bytes(*length).try_into()?; + debug_print!( + "query_account.data({}, {}, {})", + account_address, + offset, + length + ); + account_data(state, &account_address, offset, length).await + } + [0xb6, 0x4a, 0x09, 0x7e] => { + debug_print!("query_account.info({})", &account_address); + account_info(state, &account_address).await + } + _ => { + debug_print!("query_account UNKNOWN {:?}", method_id); + Err(Error::UnknownPrecompileMethodSelector(*address, method_id)) } } +} - #[allow(clippy::unnecessary_wraps)] - #[maybe_async] - async fn account_owner(&mut self, address: &Pubkey) -> Result> { - let owner = self - .backend - .map_solana_account(address, |info| info.owner.to_bytes()) - .await; +#[allow(clippy::unnecessary_wraps)] +#[maybe_async] +async fn account_owner(state: &State, address: &Pubkey) -> Result> { + let owner = state + .map_solana_account(address, |info| info.owner.to_bytes()) + .await; - Ok(owner.to_vec()) - } + Ok(owner.to_vec()) +} - #[allow(clippy::unnecessary_wraps)] - #[maybe_async] - async fn account_lamports(&mut self, address: &Pubkey) -> Result> { - let lamports: U256 = self - .backend - .map_solana_account(address, |info| **info.lamports.borrow()) - .await - .into(); +#[allow(clippy::unnecessary_wraps)] +#[maybe_async] +async fn account_lamports(state: &State, address: &Pubkey) -> Result> { + let lamports: U256 = state + .map_solana_account(address, |info| **info.lamports.borrow()) + .await + .into(); - let bytes = lamports.to_be_bytes().to_vec(); + let bytes = lamports.to_be_bytes().to_vec(); - Ok(bytes) - } + Ok(bytes) +} - #[allow(clippy::unnecessary_wraps)] - #[maybe_async] - async fn account_rent_epoch(&mut self, address: &Pubkey) -> Result> { - let epoch: U256 = self - .backend - .map_solana_account(address, |info| info.rent_epoch) - .await - .into(); +#[allow(clippy::unnecessary_wraps)] +#[maybe_async] +async fn account_rent_epoch(state: &State, address: &Pubkey) -> Result> { + let epoch: U256 = state + .map_solana_account(address, |info| info.rent_epoch) + .await + .into(); - let bytes = epoch.to_be_bytes().to_vec(); + let bytes = epoch.to_be_bytes().to_vec(); - Ok(bytes) - } + Ok(bytes) +} - #[allow(clippy::unnecessary_wraps)] - #[maybe_async] - async fn account_is_executable(&mut self, address: &Pubkey) -> Result> { - let executable: U256 = self - .backend - .map_solana_account(address, |info| info.executable) - .await - .into(); +#[allow(clippy::unnecessary_wraps)] +#[maybe_async] +async fn account_is_executable( + state: &State, + address: &Pubkey, +) -> Result> { + let executable: U256 = state + .map_solana_account(address, |info| info.executable) + .await + .into(); - let bytes = executable.to_be_bytes().to_vec(); + let bytes = executable.to_be_bytes().to_vec(); - Ok(bytes) - } + Ok(bytes) +} - #[allow(clippy::unnecessary_wraps)] - #[maybe_async] - async fn account_data_length(&mut self, address: &Pubkey) -> Result> { - let length: U256 = self - .backend - .map_solana_account(address, |info| info.data.borrow().len()) - .await - .try_into()?; +#[allow(clippy::unnecessary_wraps)] +#[maybe_async] +async fn account_data_length(state: &State, address: &Pubkey) -> Result> { + let length: U256 = state + .map_solana_account(address, |info| info.data.borrow().len()) + .await + .try_into()?; - let bytes = length.to_be_bytes().to_vec(); + let bytes = length.to_be_bytes().to_vec(); - Ok(bytes) + Ok(bytes) +} + +#[allow(clippy::unnecessary_wraps)] +#[maybe_async] +async fn account_data( + state: &State, + address: &Pubkey, + offset: usize, + length: usize, +) -> Result> { + if length == 0 { + return Err(Error::Custom( + "Query Account: data() - length == 0".to_string(), + )); } - #[allow(clippy::unnecessary_wraps)] - #[maybe_async] - async fn account_data( - &mut self, - address: &Pubkey, - offset: usize, - length: usize, - ) -> Result> { - if length == 0 { - return Err(Error::Custom( - "Query Account: data() - length == 0".to_string(), - )); - } + state + .map_solana_account(address, |info| { + info.data + .borrow() + .get(offset..offset + length) + .map(<[u8]>::to_vec) + }) + .await + .ok_or_else(|| Error::Custom("Query Account: data() - out of bounds".to_string())) +} - self.backend - .map_solana_account(address, |info| { - info.data - .borrow() - .get(offset..offset + length) - .map(<[u8]>::to_vec) - }) - .await - .ok_or_else(|| Error::Custom("Query Account: data() - out of bounds".to_string())) +#[allow(clippy::unnecessary_wraps)] +#[maybe_async] +async fn account_info(state: &State, address: &Pubkey) -> Result> { + fn to_solidity_account_value(info: &AccountInfo) -> Vec { + let mut buffer = [0_u8; 5 * 32]; + let (key, _, lamports, owner, _, executable, _, rent_epoch) = + arrayref::mut_array_refs![&mut buffer, 32, 24, 8, 32, 31, 1, 24, 8]; + + *key = info.key.to_bytes(); + *lamports = info.lamports().to_be_bytes(); + *owner = info.owner.to_bytes(); + executable[0] = info.executable.into(); + *rent_epoch = info.rent_epoch.to_be_bytes(); + + buffer.to_vec() } - #[allow(clippy::unnecessary_wraps)] - #[maybe_async] - async fn account_info(&mut self, address: &Pubkey) -> Result> { - fn to_solidity_account_value(info: &AccountInfo) -> Vec { - let mut buffer = [0_u8; 5 * 32]; - let (key, _, lamports, owner, _, executable, _, rent_epoch) = - arrayref::mut_array_refs![&mut buffer, 32, 24, 8, 32, 31, 1, 24, 8]; - - *key = info.key.to_bytes(); - *lamports = info.lamports().to_be_bytes(); - *owner = info.owner.to_bytes(); - executable[0] = info.executable.into(); - *rent_epoch = info.rent_epoch.to_be_bytes(); - - buffer.to_vec() - } - - let info = self - .backend - .map_solana_account(address, to_solidity_account_value) - .await; + let info = state + .map_solana_account(address, to_solidity_account_value) + .await; - Ok(info) - } + Ok(info) } diff --git a/evm_loader/program/src/executor/precompile_extension/spl_token.rs b/evm_loader/program/src/executor/precompile_extension/spl_token.rs index 20119d6ce..54744e0c5 100644 --- a/evm_loader/program/src/executor/precompile_extension/spl_token.rs +++ b/evm_loader/program/src/executor/precompile_extension/spl_token.rs @@ -3,15 +3,14 @@ use std::convert::{Into, TryInto}; use ethnum::U256; use maybe_async::maybe_async; use solana_program::{ - program_error::ProgramError, program_pack::Pack, pubkey::Pubkey, system_instruction, - system_program, + program_error::ProgramError, program_pack::Pack, pubkey::Pubkey, system_program, }; +use super::create_account; use crate::{ account::ACCOUNT_SEED_VERSION, - account_storage::AccountStorage, error::{Error, Result}, - executor::{ExecutorState, OwnedAccountInfo}, + evm::database::Database, types::Address, }; @@ -33,6 +32,201 @@ use crate::{ // [0x78, 0x42, 0x3b, 0xcf] : "transfer(bytes32,bytes32,uint64)" // [0x7c, 0x0e, 0xb8, 0x10] : "transferWithSeed(bytes32,bytes32,bytes32,uint64)" +#[allow(clippy::too_many_lines)] +#[maybe_async] +pub async fn spl_token( + state: &mut State, + address: &Address, + input: &[u8], + context: &crate::evm::Context, + is_static: bool, +) -> Result> { + if context.value != 0 { + return Err(Error::Custom("SplToken: value != 0".to_string())); + } + + if &context.contract != address { + return Err(Error::Custom( + "SplToken: callcode or delegatecall is not allowed".to_string(), + )); + } + + let (selector, input) = input.split_at(4); + let selector: [u8; 4] = selector.try_into()?; + + match selector { + [0xb1, 0x1e, 0xcc, 0x50] => { + // initializeMint(bytes32 seed, uint8 decimals) + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let seed = read_salt(input)?; + let decimals = read_u8(&input[32..])?; + + initialize_mint(context, state, seed, decimals, None, None).await + } + [0xc3, 0xf3, 0xf2, 0xf2] => { + // initializeMint(bytes32 seed, uint8 decimals, bytes32 mint_authority, bytes32 freeze_authority) + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let seed = read_salt(input)?; + let decimals = read_u8(&input[32..])?; + let mint_authority = read_pubkey(&input[64..])?; + let freeze_authority = read_pubkey(&input[96..])?; + initialize_mint( + context, + state, + seed, + decimals, + Some(mint_authority), + Some(freeze_authority), + ) + .await + } + [0xda, 0xa1, 0x2c, 0x5c] => { + // initializeAccount(bytes32 seed, bytes32 mint) + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let seed = read_salt(input)?; + let mint = read_pubkey(&input[32..])?; + + initialize_account(context, state, seed, mint, None).await + } + [0xfc, 0x86, 0xb7, 0x17] => { + // initializeAccount(bytes32 seed, bytes32 mint, bytes32 owner) + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let seed = read_salt(input)?; + let mint = read_pubkey(&input[32..])?; + let owner = read_pubkey(&input[64..])?; + initialize_account(context, state, seed, mint, Some(owner)).await + } + [0x57, 0x82, 0xa0, 0x43] => { + // closeAccount(bytes32 account) + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let account = read_pubkey(input)?; + close_account(context, state, account).await + } + [0xa9, 0xc1, 0x58, 0x06] => { + // approve(bytes32 source, bytes32 target, uint64 amount) + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let source = read_pubkey(input)?; + let target = read_pubkey(&input[32..])?; + let amount = read_u64(&input[64..])?; + approve(context, state, source, target, amount).await + } + [0xb7, 0x5c, 0x7d, 0xc6] => { + // revoke(bytes32 source) + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let source = read_pubkey(input)?; + revoke(context, state, source).await + } + [0x78, 0x42, 0x3b, 0xcf] => { + // transfer(bytes32 source, bytes32 target, uint64 amount) + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let source = read_pubkey(input)?; + let target = read_pubkey(&input[32..])?; + let amount = read_u64(&input[64..])?; + transfer(context, state, source, target, amount).await + } + [0x7c, 0x0e, 0xb8, 0x10] => { + // transferWithSeed(bytes32,bytes32,bytes32,uint64) + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let seed = read_salt(input)?; + let source = read_pubkey(&input[32..])?; + let target = read_pubkey(&input[64..])?; + let amount = read_u64(&input[96..])?; + + transfer_with_seed(context, state, seed, source, target, amount).await + } + [0xc9, 0xd0, 0xe2, 0xfd] => { + // mintTo(bytes32 mint, bytes32 account, uint64 amount) + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let mint = read_pubkey(input)?; + let account = read_pubkey(&input[32..])?; + let amount = read_u64(&input[64..])?; + mint_to(context, state, mint, account, amount).await + } + [0xc0, 0x67, 0xee, 0xbb] => { + // burn(bytes32 mint, bytes32 account, uint64 amount) + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let mint = read_pubkey(input)?; + let account = read_pubkey(&input[32..])?; + let amount = read_u64(&input[64..])?; + burn(context, state, mint, account, amount).await + } + [0x44, 0xef, 0x32, 0x44] => { + // freeze(bytes32 mint, bytes32 account) + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let mint = read_pubkey(input)?; + let account = read_pubkey(&input[32..])?; + freeze(context, state, mint, account).await + } + [0x3d, 0x71, 0x8c, 0x9a] => { + // thaw(bytes32 mint, bytes32 account) + if is_static { + return Err(Error::StaticModeViolation(*address)); + } + + let mint = read_pubkey(input)?; + let account = read_pubkey(&input[32..])?; + thaw(context, state, mint, account).await + } + [0xeb, 0x7d, 0xa7, 0x8c] => { + // findAccount(bytes32 seed) + let seed = read_salt(input)?; + find_account(context, state, seed) + } + [0x6d, 0xa9, 0xde, 0x75] => { + // isSystemAccount(bytes32 account) + let account = read_pubkey(input)?; + is_system_account(context, state, account).await + } + [0xd1, 0xde, 0x50, 0x11] => { + // getAccount(bytes32 account) + let account = read_pubkey(input)?; + get_account(context, state, account).await + } + [0xa2, 0xce, 0x9c, 0x1f] => { + // getMint(bytes32 account) + let account = read_pubkey(input)?; + get_mint(context, state, account).await + } + _ => Err(Error::UnknownPrecompileMethodSelector(*address, selector)), + } +} + #[inline] fn read_u8(input: &[u8]) -> Result { U256::from_be_bytes(*arrayref::array_ref![input, 0, 32]) @@ -63,668 +257,507 @@ fn read_salt(input: &[u8]) -> Result<&[u8; 32]> { Ok(arrayref::array_ref![input, 0, 32]) } -impl ExecutorState<'_, B> { - #[allow(clippy::too_many_lines)] - #[maybe_async] - pub async fn spl_token( - &mut self, - address: &Address, - input: &[u8], - context: &crate::evm::Context, - is_static: bool, - ) -> Result> { - if context.value != 0 { - return Err(Error::Custom("SplToken: value != 0".to_string())); - } - - if &context.contract != address { - return Err(Error::Custom( - "SplToken: callcode or delegatecall is not allowed".to_string(), - )); - } - - let (selector, input) = input.split_at(4); - let selector: [u8; 4] = selector.try_into()?; - - match selector { - [0xb1, 0x1e, 0xcc, 0x50] => { - // initializeMint(bytes32 seed, uint8 decimals) - if is_static { - return Err(Error::StaticModeViolation(*address)); - } - - let seed = read_salt(input)?; - let decimals = read_u8(&input[32..])?; - - self.initialize_mint(context, seed, decimals, None, None) - .await - } - [0xc3, 0xf3, 0xf2, 0xf2] => { - // initializeMint(bytes32 seed, uint8 decimals, bytes32 mint_authority, bytes32 freeze_authority) - if is_static { - return Err(Error::StaticModeViolation(*address)); - } - - let seed = read_salt(input)?; - let decimals = read_u8(&input[32..])?; - let mint_authority = read_pubkey(&input[64..])?; - let freeze_authority = read_pubkey(&input[96..])?; - self.initialize_mint( - context, - seed, - decimals, - Some(mint_authority), - Some(freeze_authority), - ) - .await - } - [0xda, 0xa1, 0x2c, 0x5c] => { - // initializeAccount(bytes32 seed, bytes32 mint) - if is_static { - return Err(Error::StaticModeViolation(*address)); - } - - let seed = read_salt(input)?; - let mint = read_pubkey(&input[32..])?; +#[maybe_async] +async fn initialize_mint( + context: &crate::evm::Context, + state: &mut State, + seed: &[u8], + decimals: u8, + mint_authority: Option, + freeze_authority: Option, +) -> Result> { + let signer = context.caller; + let (signer_pubkey, _) = state.contract_pubkey(signer); + + let (mint_key, bump_seed) = Pubkey::find_program_address( + &[ + &[ACCOUNT_SEED_VERSION], + b"ContractData", + signer.as_bytes(), + seed, + ], + state.program_id(), + ); - self.initialize_account(context, seed, mint, None).await - } - [0xfc, 0x86, 0xb7, 0x17] => { - // initializeAccount(bytes32 seed, bytes32 mint, bytes32 owner) - if is_static { - return Err(Error::StaticModeViolation(*address)); - } - - let seed = read_salt(input)?; - let mint = read_pubkey(&input[32..])?; - let owner = read_pubkey(&input[64..])?; - self.initialize_account(context, seed, mint, Some(owner)) - .await - } - [0x57, 0x82, 0xa0, 0x43] => { - // closeAccount(bytes32 account) - if is_static { - return Err(Error::StaticModeViolation(*address)); - } - - let account = read_pubkey(input)?; - self.close_account(context, account) - } - [0xa9, 0xc1, 0x58, 0x06] => { - // approve(bytes32 source, bytes32 target, uint64 amount) - if is_static { - return Err(Error::StaticModeViolation(*address)); - } - - let source = read_pubkey(input)?; - let target = read_pubkey(&input[32..])?; - let amount = read_u64(&input[64..])?; - self.approve(context, source, target, amount) - } - [0xb7, 0x5c, 0x7d, 0xc6] => { - // revoke(bytes32 source) - if is_static { - return Err(Error::StaticModeViolation(*address)); - } - - let source = read_pubkey(input)?; - self.revoke(context, source) - } - [0x78, 0x42, 0x3b, 0xcf] => { - // transfer(bytes32 source, bytes32 target, uint64 amount) - if is_static { - return Err(Error::StaticModeViolation(*address)); - } - - let source = read_pubkey(input)?; - let target = read_pubkey(&input[32..])?; - let amount = read_u64(&input[64..])?; - self.transfer(context, source, target, amount) - } - [0x7c, 0x0e, 0xb8, 0x10] => { - // transferWithSeed(bytes32,bytes32,bytes32,uint64) - if is_static { - return Err(Error::StaticModeViolation(*address)); - } - - let seed = read_salt(input)?; - let source = read_pubkey(&input[32..])?; - let target = read_pubkey(&input[64..])?; - let amount = read_u64(&input[96..])?; - - self.transfer_with_seed(context, seed, source, target, amount) - } - [0xc9, 0xd0, 0xe2, 0xfd] => { - // mintTo(bytes32 mint, bytes32 account, uint64 amount) - if is_static { - return Err(Error::StaticModeViolation(*address)); - } - - let mint = read_pubkey(input)?; - let account = read_pubkey(&input[32..])?; - let amount = read_u64(&input[64..])?; - self.mint_to(context, mint, account, amount) - } - [0xc0, 0x67, 0xee, 0xbb] => { - // burn(bytes32 mint, bytes32 account, uint64 amount) - if is_static { - return Err(Error::StaticModeViolation(*address)); - } - - let mint = read_pubkey(input)?; - let account = read_pubkey(&input[32..])?; - let amount = read_u64(&input[64..])?; - self.burn_spl_token(context, mint, account, amount) - } - [0x44, 0xef, 0x32, 0x44] => { - // freeze(bytes32 mint, bytes32 account) - if is_static { - return Err(Error::StaticModeViolation(*address)); - } - - let mint = read_pubkey(input)?; - let account = read_pubkey(&input[32..])?; - self.freeze(context, mint, account) - } - [0x3d, 0x71, 0x8c, 0x9a] => { - // thaw(bytes32 mint, bytes32 account) - if is_static { - return Err(Error::StaticModeViolation(*address)); - } - - let mint = read_pubkey(input)?; - let account = read_pubkey(&input[32..])?; - self.thaw(context, mint, account) - } - [0xeb, 0x7d, 0xa7, 0x8c] => { - // findAccount(bytes32 seed) - let seed = read_salt(input)?; - self.find_account(context, seed) - } - [0x6d, 0xa9, 0xde, 0x75] => { - // isSystemAccount(bytes32 account) - let account = read_pubkey(input)?; - self.is_system_account(context, account).await - } - [0xd1, 0xde, 0x50, 0x11] => { - // getAccount(bytes32 account) - let account = read_pubkey(input)?; - self.get_account(context, account).await - } - [0xa2, 0xce, 0x9c, 0x1f] => { - // getMint(bytes32 account) - let account = read_pubkey(input)?; - self.get_mint(context, account).await - } - _ => Err(Error::UnknownPrecompileMethodSelector(*address, selector)), - } + let account = state.external_account(mint_key).await?; + if !system_program::check_id(&account.owner) { + return Err(Error::AccountInvalidOwner(mint_key, system_program::ID)); } - fn create_account(&mut self, account: &OwnedAccountInfo, space: usize, seeds: Vec>) { - let minimum_balance = self.backend.rent().minimum_balance(space); - - let required_lamports = minimum_balance.saturating_sub(account.lamports); - - if required_lamports > 0 { - let transfer = system_instruction::transfer( - &self.backend.operator(), - &account.key, - required_lamports, - ); - self.queue_external_instruction(transfer, vec![], required_lamports); - } + let seeds: Vec> = vec![ + vec![ACCOUNT_SEED_VERSION], + b"ContractData".to_vec(), + signer.as_bytes().to_vec(), + seed.to_vec(), + vec![bump_seed], + ]; + + create_account( + state, + &account, + spl_token::state::Mint::LEN, + &spl_token::ID, + seeds, + ) + .await?; + + let initialize_mint = spl_token::instruction::initialize_mint( + &spl_token::ID, + &mint_key, + &mint_authority.unwrap_or(signer_pubkey), + Some(&freeze_authority.unwrap_or(signer_pubkey)), + decimals, + )?; + state + .queue_external_instruction(initialize_mint, vec![], 0, true) + .await?; + + Ok(mint_key.to_bytes().to_vec()) +} - let allocate = system_instruction::allocate(&account.key, space.try_into().unwrap()); - self.queue_external_instruction(allocate, seeds.clone(), 0); +#[maybe_async] +async fn initialize_account( + context: &crate::evm::Context, + state: &mut State, + seed: &[u8], + mint: Pubkey, + owner: Option, +) -> Result> { + let signer = context.caller; + let (signer_pubkey, _) = state.contract_pubkey(signer); + + let (account_key, bump_seed) = Pubkey::find_program_address( + &[ + &[ACCOUNT_SEED_VERSION], + b"ContractData", + signer.as_bytes(), + seed, + ], + state.program_id(), + ); - let assign = system_instruction::assign(&account.key, &spl_token::ID); - self.queue_external_instruction(assign, seeds, 0); + let account = state.external_account(account_key).await?; + if !system_program::check_id(&account.owner) { + return Err(Error::AccountInvalidOwner(account_key, system_program::ID)); } - #[maybe_async] - async fn initialize_mint( - &mut self, - context: &crate::evm::Context, - seed: &[u8], - decimals: u8, - mint_authority: Option, - freeze_authority: Option, - ) -> Result> { - let signer = context.caller; - let (signer_pubkey, _) = self.backend.contract_pubkey(signer); - - let (mint_key, bump_seed) = Pubkey::find_program_address( - &[ - &[ACCOUNT_SEED_VERSION], - b"ContractData", - signer.as_bytes(), - seed, - ], - self.backend.program_id(), - ); - - let account = self.external_account(mint_key).await?; - if !system_program::check_id(&account.owner) { - return Err(Error::AccountInvalidOwner(mint_key, system_program::ID)); - } - - let seeds: Vec> = vec![ - vec![ACCOUNT_SEED_VERSION], - b"ContractData".to_vec(), - signer.as_bytes().to_vec(), - seed.to_vec(), - vec![bump_seed], - ]; - - self.create_account(&account, spl_token::state::Mint::LEN, seeds); - - let initialize_mint = spl_token::instruction::initialize_mint( - &spl_token::ID, - &mint_key, - &mint_authority.unwrap_or(signer_pubkey), - Some(&freeze_authority.unwrap_or(signer_pubkey)), - decimals, - )?; - self.queue_external_instruction(initialize_mint, vec![], 0); - - Ok(mint_key.to_bytes().to_vec()) - } + let seeds: Vec> = vec![ + vec![ACCOUNT_SEED_VERSION], + b"ContractData".to_vec(), + signer.as_bytes().to_vec(), + seed.to_vec(), + vec![bump_seed], + ]; + + create_account( + state, + &account, + spl_token::state::Account::LEN, + &spl_token::ID, + seeds, + ) + .await?; + + let initialize_mint = spl_token::instruction::initialize_account2( + &spl_token::ID, + &account_key, + &mint, + &owner.unwrap_or(signer_pubkey), + )?; + state + .queue_external_instruction(initialize_mint, vec![], 0, true) + .await?; + + Ok(account_key.to_bytes().to_vec()) +} - #[maybe_async] - async fn initialize_account( - &mut self, - context: &crate::evm::Context, - seed: &[u8], - mint: Pubkey, - owner: Option, - ) -> Result> { - let signer = context.caller; - let (signer_pubkey, _) = self.backend.contract_pubkey(signer); - - let (account_key, bump_seed) = Pubkey::find_program_address( - &[ - &[ACCOUNT_SEED_VERSION], - b"ContractData", - signer.as_bytes(), - seed, - ], - self.backend.program_id(), - ); +#[maybe_async] +async fn close_account( + context: &crate::evm::Context, + state: &mut State, + account: Pubkey, +) -> Result> { + let signer = context.caller; + let (signer_pubkey, bump_seed) = state.contract_pubkey(signer); + + let seeds = vec![ + vec![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vec(), + vec![bump_seed], + ]; + + let close_account = spl_token::instruction::close_account( + &spl_token::ID, + &account, + &state.operator(), + &signer_pubkey, + &[], + )?; + state + .queue_external_instruction(close_account, vec![seeds], 0, true) + .await?; + + Ok(vec![]) +} - let account = self.external_account(account_key).await?; - if !system_program::check_id(&account.owner) { - return Err(Error::AccountInvalidOwner(account_key, system_program::ID)); - } +#[maybe_async] +async fn approve( + context: &crate::evm::Context, + state: &mut State, + source: Pubkey, + target: Pubkey, + amount: u64, +) -> Result> { + let signer = context.caller; + let (signer_pubkey, bump_seed) = state.contract_pubkey(signer); + + let seeds = vec![ + vec![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vec(), + vec![bump_seed], + ]; + + let approve = spl_token::instruction::approve( + &spl_token::ID, + &source, + &target, + &signer_pubkey, + &[], + amount, + )?; + state + .queue_external_instruction(approve, vec![seeds], 0, true) + .await?; + + Ok(vec![]) +} - let seeds: Vec> = vec![ - vec![ACCOUNT_SEED_VERSION], - b"ContractData".to_vec(), - signer.as_bytes().to_vec(), - seed.to_vec(), - vec![bump_seed], - ]; - - self.create_account(&account, spl_token::state::Account::LEN, seeds); - - let initialize_mint = spl_token::instruction::initialize_account2( - &spl_token::ID, - &account_key, - &mint, - &owner.unwrap_or(signer_pubkey), - )?; - self.queue_external_instruction(initialize_mint, vec![], 0); - - Ok(account_key.to_bytes().to_vec()) - } +#[maybe_async] +async fn revoke( + context: &crate::evm::Context, + state: &mut State, + account: Pubkey, +) -> Result> { + let signer = context.caller; + let (signer_pubkey, bump_seed) = state.contract_pubkey(signer); + + let seeds = vec![ + vec![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vec(), + vec![bump_seed], + ]; + + let revoke = spl_token::instruction::revoke(&spl_token::ID, &account, &signer_pubkey, &[])?; + state + .queue_external_instruction(revoke, vec![seeds], 0, true) + .await?; + + Ok(vec![]) +} - fn close_account(&mut self, context: &crate::evm::Context, account: Pubkey) -> Result> { - let signer = context.caller; - let (signer_pubkey, bump_seed) = self.backend.contract_pubkey(signer); - - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], - ]; - - let close_account = spl_token::instruction::close_account( - &spl_token::ID, - &account, - &self.backend.operator(), - &signer_pubkey, - &[], - )?; - self.queue_external_instruction(close_account, seeds, 0); - - Ok(vec![]) - } +#[maybe_async] +async fn transfer( + context: &crate::evm::Context, + state: &mut State, + source: Pubkey, + target: Pubkey, + amount: u64, +) -> Result> { + let signer = context.caller; + let (signer_pubkey, bump_seed) = state.contract_pubkey(signer); + + let seeds = vec![ + vec![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vec(), + vec![bump_seed], + ]; + + let transfer = spl_token::instruction::transfer( + &spl_token::ID, + &source, + &target, + &signer_pubkey, + &[], + amount, + )?; + state + .queue_external_instruction(transfer, vec![seeds], 0, true) + .await?; + + Ok(vec![]) +} - fn approve( - &mut self, - context: &crate::evm::Context, - source: Pubkey, - target: Pubkey, - amount: u64, - ) -> Result> { - let signer = context.caller; - let (signer_pubkey, bump_seed) = self.backend.contract_pubkey(signer); - - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], - ]; - - let approve = spl_token::instruction::approve( - &spl_token::ID, - &source, - &target, - &signer_pubkey, - &[], - amount, - )?; - self.queue_external_instruction(approve, seeds, 0); - - Ok(vec![]) - } +#[maybe_async] +async fn transfer_with_seed( + context: &crate::evm::Context, + state: &mut State, + seed: &[u8; 32], + source: Pubkey, + target: Pubkey, + amount: u64, +) -> Result> { + let seeds: &[&[u8]] = &[ + &[ACCOUNT_SEED_VERSION], + b"AUTH", + context.caller.as_bytes(), + seed, + ]; + let (signer_pubkey, signer_seed) = Pubkey::find_program_address(seeds, state.program_id()); + + let seeds = vec![ + vec![ACCOUNT_SEED_VERSION], + b"AUTH".to_vec(), + context.caller.as_bytes().to_vec(), + seed.to_vec(), + vec![signer_seed], + ]; + + let transfer = spl_token::instruction::transfer( + &spl_token::ID, + &source, + &target, + &signer_pubkey, + &[], + amount, + )?; + state + .queue_external_instruction(transfer, vec![seeds], 0, true) + .await?; + + Ok(vec![]) +} - fn revoke(&mut self, context: &crate::evm::Context, account: Pubkey) -> Result> { - let signer = context.caller; - let (signer_pubkey, bump_seed) = self.backend.contract_pubkey(signer); +#[maybe_async] +async fn mint_to( + context: &crate::evm::Context, + state: &mut State, + mint: Pubkey, + target: Pubkey, + amount: u64, +) -> Result> { + let signer = context.caller; + let (signer_pubkey, bump_seed) = state.contract_pubkey(signer); + + let seeds = vec![ + vec![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vec(), + vec![bump_seed], + ]; + + let mint_to = spl_token::instruction::mint_to( + &spl_token::ID, + &mint, + &target, + &signer_pubkey, + &[], + amount, + )?; + state + .queue_external_instruction(mint_to, vec![seeds], 0, true) + .await?; + + Ok(vec![]) +} - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], - ]; +#[maybe_async] +async fn burn( + context: &crate::evm::Context, + state: &mut State, + mint: Pubkey, + source: Pubkey, + amount: u64, +) -> Result> { + let signer = context.caller; + let (signer_pubkey, bump_seed) = state.contract_pubkey(signer); + + let seeds = vec![ + vec![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vec(), + vec![bump_seed], + ]; + + #[rustfmt::skip] + let burn = spl_token::instruction::burn( + &spl_token::ID, + &source, + &mint, + &signer_pubkey, + &[], + amount + )?; + state + .queue_external_instruction(burn, vec![seeds], 0, true) + .await?; + + Ok(vec![]) +} - let revoke = spl_token::instruction::revoke(&spl_token::ID, &account, &signer_pubkey, &[])?; - self.queue_external_instruction(revoke, seeds, 0); +#[maybe_async] +async fn freeze( + context: &crate::evm::Context, + state: &mut State, + mint: Pubkey, + target: Pubkey, +) -> Result> { + let signer = context.caller; + let (signer_pubkey, bump_seed) = state.contract_pubkey(signer); + + let seeds = vec![ + vec![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vec(), + vec![bump_seed], + ]; + + let freeze = spl_token::instruction::freeze_account( + &spl_token::ID, + &target, + &mint, + &signer_pubkey, + &[], + )?; + state + .queue_external_instruction(freeze, vec![seeds], 0, true) + .await?; + + Ok(vec![]) +} - Ok(vec![]) - } +#[maybe_async] +async fn thaw( + context: &crate::evm::Context, + state: &mut State, + mint: Pubkey, + target: Pubkey, +) -> Result> { + let signer = context.caller; + let (signer_pubkey, bump_seed) = state.contract_pubkey(signer); + + let seeds = vec![ + vec![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vec(), + vec![bump_seed], + ]; + + #[rustfmt::skip] + let thaw = spl_token::instruction::thaw_account( + &spl_token::ID, + &target, + &mint, + &signer_pubkey, + &[] + )?; + state + .queue_external_instruction(thaw, vec![seeds], 0, true) + .await?; + + Ok(vec![]) +} - fn transfer( - &mut self, - context: &crate::evm::Context, - source: Pubkey, - target: Pubkey, - amount: u64, - ) -> Result> { - let signer = context.caller; - let (signer_pubkey, bump_seed) = self.backend.contract_pubkey(signer); - - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], - ]; - - let transfer = spl_token::instruction::transfer( - &spl_token::ID, - &source, - &target, - &signer_pubkey, - &[], - amount, - )?; - self.queue_external_instruction(transfer, seeds, 0); - - Ok(vec![]) - } +#[allow(clippy::unnecessary_wraps)] +fn find_account( + context: &crate::evm::Context, + state: &State, + seed: &[u8], +) -> Result> { + let signer = context.caller; - fn transfer_with_seed( - &mut self, - context: &crate::evm::Context, - seed: &[u8; 32], - source: Pubkey, - target: Pubkey, - amount: u64, - ) -> Result> { - let seeds: &[&[u8]] = &[ + let (account_key, _) = Pubkey::find_program_address( + &[ &[ACCOUNT_SEED_VERSION], - b"AUTH", - context.caller.as_bytes(), + b"ContractData", + signer.as_bytes(), seed, - ]; - let (signer_pubkey, signer_seed) = - Pubkey::find_program_address(seeds, self.backend.program_id()); - - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - b"AUTH".to_vec(), - context.caller.as_bytes().to_vec(), - seed.to_vec(), - vec![signer_seed], - ]; - - let transfer = spl_token::instruction::transfer( - &spl_token::ID, - &source, - &target, - &signer_pubkey, - &[], - amount, - )?; - self.queue_external_instruction(transfer, seeds, 0); - - Ok(vec![]) - } - - fn mint_to( - &mut self, - context: &crate::evm::Context, - mint: Pubkey, - target: Pubkey, - amount: u64, - ) -> Result> { - let signer = context.caller; - let (signer_pubkey, bump_seed) = self.backend.contract_pubkey(signer); - - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], - ]; - - let mint_to = spl_token::instruction::mint_to( - &spl_token::ID, - &mint, - &target, - &signer_pubkey, - &[], - amount, - )?; - self.queue_external_instruction(mint_to, seeds, 0); - - Ok(vec![]) - } + ], + state.program_id(), + ); - fn burn_spl_token( - &mut self, - context: &crate::evm::Context, - mint: Pubkey, - source: Pubkey, - amount: u64, - ) -> Result> { - let signer = context.caller; - let (signer_pubkey, bump_seed) = self.backend.contract_pubkey(signer); - - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], - ]; - - let burn = spl_token::instruction::burn( - &spl_token::ID, - &source, - &mint, - &signer_pubkey, - &[], - amount, - )?; - self.queue_external_instruction(burn, seeds, 0); - - Ok(vec![]) - } - - fn freeze( - &mut self, - context: &crate::evm::Context, - mint: Pubkey, - target: Pubkey, - ) -> Result> { - let signer = context.caller; - let (signer_pubkey, bump_seed) = self.backend.contract_pubkey(signer); - - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], - ]; - - let freeze = spl_token::instruction::freeze_account( - &spl_token::ID, - &target, - &mint, - &signer_pubkey, - &[], - )?; - self.queue_external_instruction(freeze, seeds, 0); - - Ok(vec![]) - } - - fn thaw( - &mut self, - context: &crate::evm::Context, - mint: Pubkey, - target: Pubkey, - ) -> Result> { - let signer = context.caller; - let (signer_pubkey, bump_seed) = self.backend.contract_pubkey(signer); - - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], - ]; - - let thaw = spl_token::instruction::thaw_account( - &spl_token::ID, - &target, - &mint, - &signer_pubkey, - &[], - )?; - self.queue_external_instruction(thaw, seeds, 0); - - Ok(vec![]) - } - - #[allow(clippy::unnecessary_wraps)] - fn find_account(&mut self, context: &crate::evm::Context, seed: &[u8]) -> Result> { - let signer = context.caller; - - let (account_key, _) = Pubkey::find_program_address( - &[ - &[ACCOUNT_SEED_VERSION], - b"ContractData", - signer.as_bytes(), - seed, - ], - self.backend.program_id(), - ); - - Ok(account_key.to_bytes().to_vec()) - } + Ok(account_key.to_bytes().to_vec()) +} - #[maybe_async] - async fn is_system_account( - &mut self, - _context: &crate::evm::Context, - account: Pubkey, - ) -> Result> { - let account = self.external_account(account).await?; - if system_program::check_id(&account.owner) { - let mut result = vec![0_u8; 32]; - result[31] = 1; // return true - - Ok(result) - } else { - Ok(vec![0_u8; 32]) - } +#[maybe_async] +async fn is_system_account( + _context: &crate::evm::Context, + state: &State, + account: Pubkey, +) -> Result> { + let account = state.external_account(account).await?; + if system_program::check_id(&account.owner) { + let mut result = vec![0_u8; 32]; + result[31] = 1; // return true + + Ok(result) + } else { + Ok(vec![0_u8; 32]) } +} - #[maybe_async] - async fn get_account( - &mut self, - _context: &crate::evm::Context, - account: Pubkey, - ) -> Result> { - let account = self.external_account(account).await?; - let token = if spl_token::check_id(&account.owner) { - spl_token::state::Account::unpack(&account.data)? - } else if system_program::check_id(&account.owner) { - spl_token::state::Account::default() - } else { - return Err(ProgramError::IllegalOwner.into()); - }; - - debug_print!("spl_token get_account: {:?}", token); - - let mut result = [0_u8; 7 * 32]; - let (mint, owner, _, amount, delegate, _, delegated_amount, close_authority, state) = - arrayref::mut_array_refs![&mut result, 32, 32, 24, 8, 32, 24, 8, 32, 32]; - - *mint = token.mint.to_bytes(); - *owner = token.owner.to_bytes(); - *amount = token.amount.to_be_bytes(); - *delegate = token.delegate.map(Pubkey::to_bytes).unwrap_or_default(); - *delegated_amount = token.delegated_amount.to_be_bytes(); - *close_authority = token - .close_authority - .map(Pubkey::to_bytes) - .unwrap_or_default(); - state[31] = token.state as u8; - - Ok(result.to_vec()) - } +#[maybe_async] +async fn get_account( + _context: &crate::evm::Context, + state: &State, + account: Pubkey, +) -> Result> { + let account = state.external_account(account).await?; + let token = if spl_token::check_id(&account.owner) { + spl_token::state::Account::unpack(&account.data)? + } else if system_program::check_id(&account.owner) { + spl_token::state::Account::default() + } else { + return Err(ProgramError::IllegalOwner.into()); + }; + + debug_print!("spl_token get_account: {:?}", token); + + let mut result = [0_u8; 7 * 32]; + let (mint, owner, _, amount, delegate, _, delegated_amount, close_authority, state) = + arrayref::mut_array_refs![&mut result, 32, 32, 24, 8, 32, 24, 8, 32, 32]; + + *mint = token.mint.to_bytes(); + *owner = token.owner.to_bytes(); + *amount = token.amount.to_be_bytes(); + *delegate = token.delegate.map(Pubkey::to_bytes).unwrap_or_default(); + *delegated_amount = token.delegated_amount.to_be_bytes(); + *close_authority = token + .close_authority + .map(Pubkey::to_bytes) + .unwrap_or_default(); + state[31] = token.state as u8; + + Ok(result.to_vec()) +} - #[maybe_async] - async fn get_mint( - &mut self, - _context: &crate::evm::Context, - account: Pubkey, - ) -> Result> { - let account = self.external_account(account).await?; - let mint = if spl_token::check_id(&account.owner) { - spl_token::state::Mint::unpack(&account.data)? - } else if system_program::check_id(&account.owner) { - spl_token::state::Mint::default() - } else { - return Err(ProgramError::IllegalOwner.into()); - }; - - debug_print!("spl_token get_mint: {:?}", mint); - - let mut result = [0_u8; 5 * 32]; - let (_, supply, _, decimals, _, is_initialized, freeze_authority, mint_authority) = - arrayref::mut_array_refs![&mut result, 24, 8, 31, 1, 31, 1, 32, 32]; - - *supply = mint.supply.to_be_bytes(); - *decimals = mint.decimals.to_be_bytes(); - *is_initialized = if mint.is_initialized { [1_u8] } else { [0_u8] }; - *freeze_authority = mint - .freeze_authority - .map(Pubkey::to_bytes) - .unwrap_or_default(); - *mint_authority = mint - .mint_authority - .map(Pubkey::to_bytes) - .unwrap_or_default(); - - Ok(result.to_vec()) - } +#[maybe_async] +async fn get_mint( + _context: &crate::evm::Context, + state: &State, + account: Pubkey, +) -> Result> { + let account = state.external_account(account).await?; + let mint = if spl_token::check_id(&account.owner) { + spl_token::state::Mint::unpack(&account.data)? + } else if system_program::check_id(&account.owner) { + spl_token::state::Mint::default() + } else { + return Err(ProgramError::IllegalOwner.into()); + }; + + debug_print!("spl_token get_mint: {:?}", mint); + + let mut result = [0_u8; 5 * 32]; + let (_, supply, _, decimals, _, is_initialized, freeze_authority, mint_authority) = + arrayref::mut_array_refs![&mut result, 24, 8, 31, 1, 31, 1, 32, 32]; + + *supply = mint.supply.to_be_bytes(); + *decimals = mint.decimals.to_be_bytes(); + *is_initialized = if mint.is_initialized { [1_u8] } else { [0_u8] }; + *freeze_authority = mint + .freeze_authority + .map(Pubkey::to_bytes) + .unwrap_or_default(); + *mint_authority = mint + .mint_authority + .map(Pubkey::to_bytes) + .unwrap_or_default(); + + Ok(result.to_vec()) } diff --git a/evm_loader/program/src/executor/state.rs b/evm_loader/program/src/executor/state.rs index 5a953d3ad..e7ec6bc52 100644 --- a/evm_loader/program/src/executor/state.rs +++ b/evm_loader/program/src/executor/state.rs @@ -16,6 +16,7 @@ use crate::types::Address; use super::action::Action; use super::cache::{cache_get_or_insert_account, cache_get_or_insert_balance, Cache}; +use super::precompile_extension::PrecompiledContracts; use super::OwnedAccountInfo; /// Represents the state of executor abstracted away from a self.backend. @@ -83,106 +84,23 @@ impl<'a, B: AccountStorage> ExecutorState<'a, B> { pub fn call_depth(&self) -> usize { self.stack.len() } +} - pub fn burn(&mut self, source: Address, chain_id: u64, value: U256) { - let burn = Action::Burn { - source, - chain_id, - value, - }; - self.actions.push(burn); +#[maybe_async(?Send)] +impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { + fn program_id(&self) -> &Pubkey { + self.backend.program_id() } - - pub fn queue_external_instruction( - &mut self, - instruction: Instruction, - seeds: Vec>, - fee: u64, - ) { - let action = Action::ExternalInstruction { - program_id: instruction.program_id, - data: instruction.data, - accounts: instruction.accounts, - seeds, - fee, - }; - - self.actions.push(action); + fn operator(&self) -> Pubkey { + self.backend.operator() } - - #[maybe_async] - pub async fn external_account(&self, address: Pubkey) -> Result { - let metas = self - .actions - .iter() - .filter_map(|a| { - if let Action::ExternalInstruction { accounts, .. } = a { - Some(accounts) - } else { - None - } - }) - .flatten() - .collect::>(); - - if !metas.iter().any(|m| (m.pubkey == address) && m.is_writable) { - let account = cache_get_or_insert_account(&self.cache, address, self.backend).await; - return Ok(account); - } - - let mut accounts = BTreeMap::::new(); - - for m in metas { - let account = cache_get_or_insert_account(&self.cache, m.pubkey, self.backend).await; - accounts.insert(account.key, account); - } - - for action in &self.actions { - if let Action::ExternalInstruction { - program_id, - data, - accounts: meta, - .. - } = action - { - match program_id { - program_id if solana_program::system_program::check_id(program_id) => { - crate::external_programs::system::emulate(data, meta, &mut accounts)?; - } - program_id if spl_token::check_id(program_id) => { - crate::external_programs::spl_token::emulate(data, meta, &mut accounts)?; - } - program_id if spl_associated_token_account::check_id(program_id) => { - crate::external_programs::spl_associated_token::emulate( - data, - meta, - &mut accounts, - self.rent(), - )?; - } - program_id if &MPL_TOKEN_METADATA_ID == program_id => { - crate::external_programs::metaplex::emulate( - data, - meta, - &mut accounts, - self.rent(), - )?; - } - _ => { - return Err(Error::Custom(format!( - "Unknown external program: {program_id}" - ))); - } - } - } - } - - Ok(accounts[&address].clone()) + fn chain_id_to_token(&self, chain_id: u64) -> Pubkey { + self.backend.chain_id_to_token(chain_id) + } + fn contract_pubkey(&self, address: Address) -> (Pubkey, u8) { + self.backend.contract_pubkey(address) } -} -#[maybe_async(?Send)] -impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { async fn nonce(&self, from_address: Address, from_chain_id: u64) -> Result { let mut nonce = self.backend.nonce(from_address, from_chain_id).await; let mut increment = 0_u64; @@ -200,7 +118,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { Ok(nonce) } - fn increment_nonce(&mut self, address: Address, chain_id: u64) -> Result<()> { + async fn increment_nonce(&mut self, address: Address, chain_id: u64) -> Result<()> { let increment = Action::EvmIncrementNonce { address, chain_id }; self.actions.push(increment); @@ -277,8 +195,19 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { Ok(()) } + async fn burn(&mut self, source: Address, chain_id: u64, value: U256) -> Result<()> { + let burn = Action::Burn { + source, + chain_id, + value, + }; + self.actions.push(burn); + + Ok(()) + } + async fn code_size(&self, from_address: Address) -> Result { - if self.is_precompile_extension(&from_address) { + if PrecompiledContracts::is_precompile_extension(&from_address) { return Ok(1); // This is required in order to make a normal call to an extension contract } @@ -305,7 +234,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { Ok(self.backend.code(from_address).await) } - fn set_code(&mut self, address: Address, chain_id: u64, code: Vec) -> Result<()> { + async fn set_code(&mut self, address: Address, chain_id: u64, code: Vec) -> Result<()> { if code.starts_with(&[0xEF]) { // https://eips.ethereum.org/EIPS/eip-3541 return Err(Error::EVMObjectFormatNotSupported(address)); @@ -343,7 +272,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { Ok(self.backend.storage(from_address, from_index).await) } - fn set_storage(&mut self, address: Address, index: U256, value: [u8; 32]) -> Result<()> { + async fn set_storage(&mut self, address: Address, index: U256, value: [u8; 32]) -> Result<()> { let set_storage = Action::EvmSetStorage { address, index, @@ -422,6 +351,80 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { Ok(cache.block_timestamp) } + async fn external_account(&self, address: Pubkey) -> Result { + let metas = self + .actions + .iter() + .filter_map(|a| { + if let Action::ExternalInstruction { accounts, .. } = a { + Some(accounts) + } else { + None + } + }) + .flatten() + .collect::>(); + + if !metas.iter().any(|m| (m.pubkey == address) && m.is_writable) { + let account = cache_get_or_insert_account(&self.cache, address, self.backend).await; + return Ok(account); + } + + let mut accounts = BTreeMap::::new(); + + for m in metas { + let account = cache_get_or_insert_account(&self.cache, m.pubkey, self.backend).await; + accounts.insert(account.key, account); + } + + for action in &self.actions { + if let Action::ExternalInstruction { + program_id, + data, + accounts: meta, + emulated_internally, + .. + } = action + { + if !emulated_internally { + unreachable!(); + } + + match program_id { + program_id if solana_program::system_program::check_id(program_id) => { + crate::external_programs::system::emulate(data, meta, &mut accounts)?; + } + program_id if spl_token::check_id(program_id) => { + crate::external_programs::spl_token::emulate(data, meta, &mut accounts)?; + } + program_id if spl_associated_token_account::check_id(program_id) => { + crate::external_programs::spl_associated_token::emulate( + data, + meta, + &mut accounts, + self.rent(), + )?; + } + program_id if &MPL_TOKEN_METADATA_ID == program_id => { + crate::external_programs::metaplex::emulate( + data, + meta, + &mut accounts, + self.rent(), + )?; + } + _ => { + return Err(Error::Custom(format!( + "Unknown external program for emulate: {program_id}" + ))); + } + } + } + } + + Ok(accounts[&address].clone()) + } + fn rent(&self) -> &Rent { self.backend.rent() } @@ -430,6 +433,10 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { self.backend.return_data() } + fn set_return_data(&mut self, data: &[u8]) { + self.backend.set_return_data(data); + } + async fn map_solana_account(&self, address: &Pubkey, action: F) -> R where F: FnOnce(&solana_program::account_info::AccountInfo) -> R, @@ -468,7 +475,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { data: &[u8], is_static: bool, ) -> Option>> { - self.call_precompile_extension(context, address, data, is_static) + PrecompiledContracts::call_precompile_extension(self, context, address, data, is_static) .await } @@ -494,4 +501,29 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { self.backend.contract_chain_id(contract).await } + + async fn queue_external_instruction( + &mut self, + instruction: Instruction, + seeds: Vec>>, + fee: u64, + emulated_internally: bool, + ) -> Result<()> { + #[cfg(target_os = "solana")] + if !emulated_internally { + return Err(Error::UnavalableExternalSolanaCall); + } + + let action = Action::ExternalInstruction { + program_id: instruction.program_id, + data: instruction.data, + accounts: instruction.accounts, + seeds, + fee, + emulated_internally, + }; + + self.actions.push(action); + Ok(()) + } } diff --git a/evm_loader/program/src/executor/synced_state.rs b/evm_loader/program/src/executor/synced_state.rs new file mode 100644 index 000000000..9c31db97a --- /dev/null +++ b/evm_loader/program/src/executor/synced_state.rs @@ -0,0 +1,295 @@ +use ethnum::{AsU256, U256}; +use maybe_async::maybe_async; +use solana_program::instruction::Instruction; +use solana_program::pubkey::Pubkey; +use solana_program::rent::Rent; + +use crate::account_storage::{AccountStorage, SyncedAccountStorage}; +use crate::error::{Error, Result}; +use crate::evm::database::Database; +use crate::evm::Context; +use crate::types::Address; + +use super::precompile_extension::PrecompiledContracts; +use super::OwnedAccountInfo; + +enum Action { + SetTransientStorage { + address: Address, + index: U256, + value: [u8; 32], + }, +} + +pub struct SyncedExecutorState<'a, B: AccountStorage> { + pub backend: &'a mut B, + actions: Vec, + stack: Vec, +} + +impl<'a, B: AccountStorage + SyncedAccountStorage> SyncedExecutorState<'a, B> { + #[must_use] + pub fn new(backend: &'a mut B) -> Self { + Self { + backend, + actions: Vec::with_capacity(64), + stack: Vec::with_capacity(16), + } + } +} + +#[maybe_async(?Send)] +impl<'a, B: AccountStorage + SyncedAccountStorage> Database for SyncedExecutorState<'a, B> { + fn program_id(&self) -> &Pubkey { + self.backend.program_id() + } + fn operator(&self) -> Pubkey { + self.backend.operator() + } + fn chain_id_to_token(&self, chain_id: u64) -> Pubkey { + self.backend.chain_id_to_token(chain_id) + } + fn contract_pubkey(&self, address: Address) -> (Pubkey, u8) { + self.backend.contract_pubkey(address) + } + + async fn nonce(&self, from_address: Address, from_chain_id: u64) -> Result { + let nonce = self.backend.nonce(from_address, from_chain_id).await; + Ok(nonce) + } + + async fn increment_nonce(&mut self, address: Address, chain_id: u64) -> Result<()> { + self.backend.increment_nonce(address, chain_id).await?; + Ok(()) + } + + async fn balance(&self, from_address: Address, from_chain_id: u64) -> Result { + let balance = self.backend.balance(from_address, from_chain_id).await; + Ok(balance) + } + + async fn transfer( + &mut self, + source: Address, + target: Address, + chain_id: u64, + value: U256, + ) -> Result<()> { + if value == U256::ZERO { + return Ok(()); + } + + let target_chain_id = self.contract_chain_id(target).await.unwrap_or(chain_id); + + if (self.code_size(target).await? > 0) && (target_chain_id != chain_id) { + return Err(Error::InvalidTransferToken(source, chain_id)); + } + + if source == target { + return Ok(()); + } + + if self.balance(source, chain_id).await? < value { + return Err(Error::InsufficientBalance(source, chain_id, value)); + } + + self.backend + .transfer(source, target, chain_id, value) + .await?; + Ok(()) + } + + async fn burn(&mut self, source: Address, chain_id: u64, value: U256) -> Result<()> { + self.backend.burn(source, chain_id, value).await?; + Ok(()) + } + + async fn code_size(&self, from_address: Address) -> Result { + if PrecompiledContracts::is_precompile_extension(&from_address) { + return Ok(1); // This is required in order to make a normal call to an extension contract + } + + Ok(self.backend.code_size(from_address).await) + } + + async fn code(&self, from_address: Address) -> Result { + Ok(self.backend.code(from_address).await) + } + + async fn set_code(&mut self, address: Address, chain_id: u64, code: Vec) -> Result<()> { + if code.starts_with(&[0xEF]) { + // https://eips.ethereum.org/EIPS/eip-3541 + return Err(Error::EVMObjectFormatNotSupported(address)); + } + + if code.len() > 0x6000 { + // https://eips.ethereum.org/EIPS/eip-170 + return Err(Error::ContractCodeSizeLimit(address, code.len())); + } + + self.backend.set_code(address, chain_id, code).await?; + Ok(()) + } + + async fn storage(&self, from_address: Address, from_index: U256) -> Result<[u8; 32]> { + Ok(self.backend.storage(from_address, from_index).await) + } + + async fn set_storage(&mut self, address: Address, index: U256, value: [u8; 32]) -> Result<()> { + self.backend.set_storage(address, index, value).await?; + Ok(()) + } + + async fn transient_storage(&self, from_address: Address, from_index: U256) -> Result<[u8; 32]> { + for action in self.actions.iter().rev() { + #[allow(irrefutable_let_patterns)] + if let Action::SetTransientStorage { + address, + index, + value, + } = action + { + if (&from_address == address) && (&from_index == index) { + return Ok(*value); + } + } + } + + Ok([0; 32]) + } + + fn set_transient_storage( + &mut self, + address: Address, + index: U256, + value: [u8; 32], + ) -> Result<()> { + self.actions.push(Action::SetTransientStorage { + address, + index, + value, + }); + Ok(()) + } + + async fn block_hash(&self, number: U256) -> Result<[u8; 32]> { + // geth: + // - checks the overflow + // - converts to u64 + // - checks on last 256 blocks + + if number >= u64::MAX.as_u256() { + return Ok(<[u8; 32]>::default()); + } + + let number = number.as_u64(); + let block_slot = self.backend.block_number().as_u64(); + let lower_block_slot = if block_slot < 257 { + 0 + } else { + block_slot - 256 + }; + + if number >= block_slot || lower_block_slot > number { + return Ok(<[u8; 32]>::default()); + } + + Ok(self.backend.block_hash(number).await) + } + + fn block_number(&self) -> Result { + Ok(self.backend.block_number()) + } + + fn block_timestamp(&self) -> Result { + Ok(self.backend.block_timestamp()) + } + + async fn external_account(&self, address: Pubkey) -> Result { + let account = self.backend.clone_solana_account(&address).await; + return Ok(account); + } + + fn rent(&self) -> &Rent { + self.backend.rent() + } + + fn return_data(&self) -> Option<(Pubkey, Vec)> { + self.backend.return_data() + } + + fn set_return_data(&mut self, data: &[u8]) { + self.backend.set_return_data(data); + } + + async fn map_solana_account(&self, address: &Pubkey, action: F) -> R + where + F: FnOnce(&solana_program::account_info::AccountInfo) -> R, + { + self.backend.map_solana_account(address, action).await + } + + fn snapshot(&mut self) { + self.stack.push(self.actions.len()); + self.backend.snapshot(); + } + + fn revert_snapshot(&mut self) { + let actions_len = self + .stack + .pop() + .expect("Fatal Error: Inconsistent EVM Call Stack"); + + self.actions.truncate(actions_len); + + if self.stack.is_empty() { + // sanity check + assert!(self.actions.is_empty()); + } + + self.backend.revert_snapshot(); + } + + fn commit_snapshot(&mut self) { + self.stack + .pop() + .expect("Fatal Error: Inconsistent EVM Call Stack"); + self.backend.commit_snapshot(); + } + + async fn precompile_extension( + &mut self, + context: &Context, + address: &Address, + data: &[u8], + is_static: bool, + ) -> Option>> { + PrecompiledContracts::call_precompile_extension(self, context, address, data, is_static) + .await + } + + fn default_chain_id(&self) -> u64 { + self.backend.default_chain_id() + } + + fn is_valid_chain_id(&self, chain_id: u64) -> bool { + self.backend.is_valid_chain_id(chain_id) + } + + async fn contract_chain_id(&self, contract: Address) -> Result { + self.backend.contract_chain_id(contract).await + } + + async fn queue_external_instruction( + &mut self, + instruction: Instruction, + seeds: Vec>>, + fee: u64, + emulated_internally: bool, + ) -> Result<()> { + self.backend + .execute_external_instruction(instruction, seeds, fee, emulated_internally) + .await?; + Ok(()) + } +} diff --git a/evm_loader/program/src/instruction/mod.rs b/evm_loader/program/src/instruction/mod.rs index 3a805e782..a46695e0d 100644 --- a/evm_loader/program/src/instruction/mod.rs +++ b/evm_loader/program/src/instruction/mod.rs @@ -169,6 +169,32 @@ pub enum EvmInstruction { /// 20..28 - chain id in little endian AccountCreateBalance, + /// Execute Transaction from Instruction in a single iteration with a call to Solana programs + /// + /// Accounts: + /// `[WRITE,SIGNER]` Operator + /// `[WRITE]` Treasury + /// `[WRITE]` Operator Balance + /// `[]` System program + /// `[WRITE?]` Other accounts + /// Instruction data: + /// 0..4 - treasury index in little-endian + /// 4.. - transaction data + TransactionExecuteFromInstructionWithSolanaCall, + + /// Execute Transaction from Account in a single iteration + /// + /// Accounts: + /// `[]` Holder + /// `[WRITE,SIGNER]` Operator + /// `[WRITE]` Treasury + /// `[WRITE]` Operator Balance + /// `[]` System program + /// `[WRITE?]` Other accounts + /// Instruction data: + /// 0..4 - treasury index in little-endian + TransactionExecuteFromAccountWithSolanaCall, + ConfigGetChainCount, ConfigGetChainInfo, ConfigGetEnvironment, @@ -200,6 +226,8 @@ impl EvmInstruction { 0x35 => Self::TransactionStepFromAccount, // 53 0x36 => Self::TransactionStepFromAccountNoChainId, // 54 0x37 => Self::Cancel, // 55 + 0x38 => Self::TransactionExecuteFromInstructionWithSolanaCall, // 56 + 0x39 => Self::TransactionExecuteFromAccountWithSolanaCall, // 57 0xA0 => Self::ConfigGetChainCount, // 160 0xA1 => Self::ConfigGetChainInfo, @@ -232,7 +260,9 @@ pub mod neon_tokens_deposit; pub mod transaction_cancel; pub mod transaction_execute; pub mod transaction_execute_from_account; +pub mod transaction_execute_from_account_solana_call; pub mod transaction_execute_from_instruction; +pub mod transaction_execute_from_instruction_solana_call; pub mod transaction_step; pub mod transaction_step_from_account; pub mod transaction_step_from_account_no_chainid; diff --git a/evm_loader/program/src/instruction/transaction_execute.rs b/evm_loader/program/src/instruction/transaction_execute.rs index cf790ae97..cfe292672 100644 --- a/evm_loader/program/src/instruction/transaction_execute.rs +++ b/evm_loader/program/src/instruction/transaction_execute.rs @@ -4,7 +4,7 @@ use crate::debug::log_data; use crate::error::{Error, Result}; use crate::evm::tracing::NoopEventListener; use crate::evm::Machine; -use crate::executor::ExecutorState; +use crate::executor::{ExecutorState, SyncedExecutorState}; use crate::gasometer::Gasometer; use crate::instruction::transaction_step::log_return_value; use crate::types::{Address, Transaction}; @@ -65,3 +65,53 @@ pub fn execute( Ok(()) } + +pub fn execute_with_solana_call( + accounts: AccountsDB<'_>, + mut gasometer: Gasometer, + trx: Transaction, + origin: Address, +) -> Result<()> { + let chain_id = trx.chain_id().unwrap_or(crate::config::DEFAULT_CHAIN_ID); + let gas_limit = trx.gas_limit(); + let gas_price = trx.gas_price(); + + let mut account_storage = ProgramAccountStorage::new(accounts)?; + + trx.validate(origin, &account_storage)?; + + account_storage.origin(origin, &trx)?.increment_nonce()?; + + let (exit_reason, steps_executed) = { + let mut backend = SyncedExecutorState::new(&mut account_storage); + + let mut evm = Machine::new(&trx, origin, &mut backend, None::)?; + let (result, steps_executed, _) = evm.execute(u64::MAX, &mut backend)?; + + (result, steps_executed) + }; + + log_data(&[ + b"STEPS", + &steps_executed.to_le_bytes(), // Iteration steps + &steps_executed.to_le_bytes(), // Total steps is the same as iteration steps + ]); + + account_storage.increment_revision_for_modified_contracts()?; + account_storage.transfer_treasury_payment()?; + + gasometer.record_operator_expenses(account_storage.operator()); + let used_gas = gasometer.used_gas(); + if used_gas > gas_limit { + return Err(Error::OutOfGas(gas_limit, used_gas)); + } + + log_data(&[b"GAS", &used_gas.to_le_bytes(), &used_gas.to_le_bytes()]); + + let gas_cost = used_gas.saturating_mul(gas_price); + account_storage.transfer_gas_payment(origin, chain_id, gas_cost)?; + + log_return_value(&exit_reason); + + Ok(()) +} diff --git a/evm_loader/program/src/instruction/transaction_execute_from_account_solana_call.rs b/evm_loader/program/src/instruction/transaction_execute_from_account_solana_call.rs new file mode 100644 index 000000000..95fa8019a --- /dev/null +++ b/evm_loader/program/src/instruction/transaction_execute_from_account_solana_call.rs @@ -0,0 +1,50 @@ +use crate::account::{program, AccountsDB, BalanceAccount, Holder, Operator, Treasury}; +use crate::debug::log_data; +use crate::error::Result; +use crate::gasometer::Gasometer; +use crate::types::Transaction; +use arrayref::array_ref; +use ethnum::U256; +use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; + +/// Execute Ethereum transaction in a single Solana transaction +pub fn process<'a>( + program_id: &'a Pubkey, + accounts: &'a [AccountInfo<'a>], + instruction: &[u8], +) -> Result<()> { + log_msg!("Instruction: Execute Transaction from Account with Solana call"); + + let treasury_index = u32::from_le_bytes(*array_ref![instruction, 0, 4]); + + let holder = Holder::from_account(program_id, accounts[0].clone())?; + + let operator = unsafe { Operator::from_account_not_whitelisted(&accounts[1])? }; + let treasury = Treasury::from_account(program_id, treasury_index, &accounts[2])?; + let operator_balance = BalanceAccount::from_account(program_id, accounts[3].clone())?; + let system = program::System::from_account(&accounts[4])?; + + holder.validate_owner(&operator)?; + let trx = Transaction::from_rlp(&holder.transaction())?; + holder.validate_transaction(&trx)?; + + let origin = trx.recover_caller_address()?; + + log_data(&[b"HASH", &trx.hash()]); + log_data(&[b"MINER", operator_balance.address().as_bytes()]); + + let accounts_db = AccountsDB::new( + &accounts[5..], + operator, + Some(operator_balance), + Some(system), + Some(treasury), + ); + + let mut gasometer = Gasometer::new(U256::ZERO, accounts_db.operator())?; + gasometer.record_solana_transaction_cost(); + gasometer.record_address_lookup_table(accounts); + gasometer.record_write_to_holder(&trx); + + super::transaction_execute::execute_with_solana_call(accounts_db, gasometer, trx, origin) +} diff --git a/evm_loader/program/src/instruction/transaction_execute_from_instruction_solana_call.rs b/evm_loader/program/src/instruction/transaction_execute_from_instruction_solana_call.rs new file mode 100644 index 000000000..3bae7620f --- /dev/null +++ b/evm_loader/program/src/instruction/transaction_execute_from_instruction_solana_call.rs @@ -0,0 +1,45 @@ +use crate::account::{program, AccountsDB, BalanceAccount, Operator, Treasury}; +use crate::debug::log_data; +use crate::error::Result; +use crate::gasometer::Gasometer; +use crate::types::Transaction; +use arrayref::array_ref; +use ethnum::U256; +use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; + +/// Execute Ethereum transaction in a single Solana transaction +pub fn process<'a>( + program_id: &'a Pubkey, + accounts: &'a [AccountInfo<'a>], + instruction: &[u8], +) -> Result<()> { + log_msg!("Instruction: Execute Transaction from Instruction with Solana call"); + + let treasury_index = u32::from_le_bytes(*array_ref![instruction, 0, 4]); + let messsage = &instruction[4..]; + + let operator = unsafe { Operator::from_account_not_whitelisted(&accounts[0])? }; + let treasury = Treasury::from_account(program_id, treasury_index, &accounts[1])?; + let operator_balance = BalanceAccount::from_account(program_id, accounts[2].clone())?; + let system = program::System::from_account(&accounts[3])?; + + let trx = Transaction::from_rlp(messsage)?; + let origin = trx.recover_caller_address()?; + + log_data(&[b"HASH", &trx.hash()]); + log_data(&[b"MINER", operator_balance.address().as_bytes()]); + + let accounts_db = AccountsDB::new( + &accounts[4..], + operator, + Some(operator_balance), + Some(system), + Some(treasury), + ); + + let mut gasometer = Gasometer::new(U256::ZERO, accounts_db.operator())?; + gasometer.record_solana_transaction_cost(); + gasometer.record_address_lookup_table(accounts); + + super::transaction_execute::execute_with_solana_call(accounts_db, gasometer, trx, origin) +} diff --git a/solidity/call_solana.sol b/solidity/call_solana.sol new file mode 100644 index 000000000..96539d035 --- /dev/null +++ b/solidity/call_solana.sol @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >= 0.7.0; +pragma abicoder v2; + +interface CallSolana { + + struct Instruction { + bytes32 program_id; + AccountMeta[] accounts; + bytes instruction_data; + } + + struct AccountMeta { + bytes32 account; + bool is_signer; + bool is_writable; + } + + // Returns Solana address for Neon address. + // Calculates as PDA([ACCOUNT_SEED_VERSION, Neon-address], evm_loader_id) + function getNeonAddress(address) external view returns (bytes32); + + + // Returns Solana address of resource for contracts. + // Calculates as PDA([ACCONT_SEED_VERSION, "ContractData", msg.sender, salt], evm_loader_id) + function getResourceAddress(bytes32 salt) external view returns (bytes32); + + + // Creates resource with specified salt. + // Return the Solana address of the created resource (see `getResourceAddress`) + function createResource(bytes32 salt, uint64 space, uint64 lamports, bytes32 owner) external returns (bytes32); + + + // Returns Solana PDA generated from specified program_id and seeds + function getSolanaPDA(bytes32 program_id, bytes memory seeds) external view returns (bytes32); + + + // Returns Solana address of the external authority. + // Calculates as PDA([ACCOUNT_SEED_VERSION, "AUTH", msg.sender, salt], evm_loader_id) + function getExtAuthority(bytes32 salt) external view returns (bytes32); + + + // Return Solana address for payer account (if instruction required some account to funding new created accounts) + // Calculates as PDA([ACCOUNT_SEED_VERSION, "PAYER", msg.sender], evm_loader_id) + function getPayer() external view returns (bytes32); + + + // Execute the instruction with a call to the Solana program. + // Guarantees successful execution of call after a success return. + // Note: If the call was unsuccessful, the transaction fails (due to Solana's behaviour). + // The `lamports` parameter specifies the amount of lamports that can be required to create new accounts during execution. + // This lamports transferred to `payer`-account (see `getPayer()` function) before the call. + // - `instruction` - instruction which should be executed + // This method uses PDA for sender to authorize the operation (`getNeonAddress(msg.sender)`) + // Returns the returned data of the executed instruction (if program returned the data is equal to the program_id of the instruction) + function execute(uint64 lamports, Instruction memory instruction) external returns (bytes memory); + + + // Execute the instruction with call to the Solana program. + // Guarantees successful execution of call after a success return. + // Note: If the call was unsuccessful, the transaction fails (due to Solana's behaviour). + // The `lamports` parameter specifies the amount of lamports that can be required to create new accounts during execution. + // This lamports transferred to `payer`-account (see `getPayer()` function) before the call. + // - `salt` - the salt to generate an address of external authority (see `getExtAuthority()` function) + // - `instruction` - instruction which should be executed + // This method uses external authority to authorize the operation (`getExtAuthority(salt)`) + // Returns the returned data of the executed instruction (if program returned the data is equal to the program_id of the instruction) + function executeWithSeed(uint64 lamports, bytes32 salt, Instruction memory instruction) external returns (bytes memory); + + + // Execute the instruction with a call to the Solana program. + // Guarantees successful execution of call after a success return. + // Note: If the call was unsuccessful, the transaction fails (due to Solana's behaviour). + // The `lamports` parameter specifies the amount of lamports that can be required to create new accounts during execution. + // This lamports transferred to `payer`-account (see `getPayer()` function) before the call. + // - `instruction` - bincode serialized instruction which should be executed + // This method uses PDA for sender to authorize the operation (`getNeonAddress(msg.sender)`) + // Returns the returned data of the executed instruction (if program returned the data is equal to the program_id of the instruction) + function execute(uint64 lamports, bytes memory instruction) external returns (bytes memory); + + + // Execute the instruction with call to the Solana program. + // Guarantees successful execution of call after a success return. + // Note: If the call was unsuccessful, the transaction fails (due to Solana's behaviour). + // The `lamports` parameter specifies the amount of lamports that can be required to create new accounts during execution. + // This lamports transferred to `payer`-account (see `getPayer()` function) before the call. + // - `salt` - the salt to generate an address of external authority (see `getExtAuthority()` function) + // - `instruction` - bincode serialized instruction which should be executed + // This method uses external authority to authorize the operation (`getExtAuthority(salt)`) + // Returns the returned data of the executed instruction (if program returned the data is equal to the program_id of the instruction) + function executeWithSeed(uint64 lamports, bytes32 salt, bytes memory instruction) external returns (bytes memory); + + + // Returns the program_id and returned data of the last executed instruction (if no return data was set returns zeroed bytes) + // For more information see: https://docs.rs/solana-program/latest/solana_program/program/fn.get_return_data.html + // Note: This method should be called after a call to `execute`/`executeWithSeed` methods + function getReturnData() external view returns (bytes32, bytes memory); +} + + +/* Note: + For `execute`/`executeWithSeed` methods which gets instruction in bincode serialized format + the instruction should be serialized according to Solana bincode serialize rules. It requires + serialized data in the following form: + + program_id as bytes32 + len(accounts) as uint64le + account as bytes32 + is_signer as bool + is_writable as bool + len(data) as uint64le + data (see instruction to Solana program) + +The optimized way to serailize instruction is write this code on the solidity assembler. +To perform a call to `execute()` and `executeWithSeed()` methods the next code-sample can be helpful: +```solidity + { + // TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA + bytes32 program_id = 0x06ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9; + bytes32 owner = getNeonAddress(address(this)); + + bytes4 selector = bytes4(keccak256("execute(uint64,bytes)")); + bool success; + assembly { + let buff := mload(0x40) // the head of heap + let pos := buff // current write position + + // selector + mstore(pos, selector) // write the method selector + pos := add(pos, 4) + + // Write arguments to call the method + // lamports + mstore(pos, 0) // write required lamports + pos := add(pos, 32) + + // offset for instruction + // specify the position of serialized instruction relative to start of arguments + mstore(pos, sub(add(pos, 28), buff)) + pos := add(pos, 32) + let size_pos := pos // Save size position of serialized instruction + pos := add(pos, 32) + + // program_id + mstore(pos, program_id) + pos := add(pos, 32) + + // len(accounts) + mstore(pos, 0) + mstore8(pos, 4) + pos := add(pos, 8) + + // For each account in accounts array: + // AccountMeta(resource, false, true) + mstore(pos, owner) // pubkey + mstore8(add(pos, 32), 1) // is_signer + mstore8(add(pos, 33), 0) // is_writable + pos := add(pos, 34) + + // len(instruction_data) if it shorter than 256 bytes + mstore(pos, 0) // fill with zero next 32 bytes + mstore8(pos, 1) // write the length of data + pos := add(pos, 8) + + // instruction_data: InitializeAccount + mstore8(pos, 1) // Use Solana program instruction to detailed info + pos := add(pos, 1) + + mstore(size_pos, sub(sub(pos, size_pos), 32)) // write the size of serialized instruction + let length := sub(pos, buff) // calculate the length of arguments + mstore(0x40, pos) // update head of heap + success := call(5000, 0xFF00000000000000000000000000000000000006, 0, buff, length, buff, 0x20) + mstore(0x40, buff) // restore head of heap + } + if (success == false) { + revert("Can't execute instruction"); + } + } +``` +*/ diff --git a/solidity/call_solana_test.sol b/solidity/call_solana_test.sol new file mode 100644 index 000000000..ea3f45b6d --- /dev/null +++ b/solidity/call_solana_test.sol @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: MIT + +pragma solidity >= 0.7.0; +pragma abicoder v2; +import './SPLToken.sol'; +import './call_solana.sol'; + +SPLToken constant _splToken = SPLToken(0xFf00000000000000000000000000000000000004); +CallSolana constant _callSolana = CallSolana(0xFF00000000000000000000000000000000000006); + +contract Test { + uint256 balance; + + function reverse(uint64 input) internal pure returns (uint64 v) { + v = input; + + // swap bytes + v = ((v & 0xFF00FF00FF00FF00) >> 8) | + ((v & 0x00FF00FF00FF00FF) << 8); + + // swap 2-byte long pairs + v = ((v & 0xFFFF0000FFFF0000) >> 16) | + ((v & 0x0000FFFF0000FFFF) << 16); + + // swap 4-byte long pairs + v = (v >> 32) | (v << 32); + } + + function getNeonAddress(address addr) internal returns (bytes32 owner) { + bytes4 selector = bytes4(keccak256("getNeonAddress(address)")); + assembly { + let buff := mload(0x40) + let pos := buff + + mstore(pos, selector) + pos := add(pos, 4) + + mstore(pos, addr) + pos := add(pos, 32) + + let length := sub(pos, buff) + mstore(0x40, pos) + + let success := call(5000, 0xFF00000000000000000000000000000000000006, 0, buff, length, buff, 0x20) + owner := mload(buff) + + mstore(0x40, buff) + } + } + + constructor() { + // TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA + bytes32 program_id = 0x06ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9; + + // bytes32 d = 0x6134f00584594e09f9f664be8195ce25deb2a92e3022ef6e5b1d9ad9c2a03a33; + // bytes memory data = abi.encodePacked(d, true, false); + + bytes32 salt = _salt(msg.sender); + + // //bytes32 resource = _callSolana.getResourceAddress(0x00); + bytes32 resource = _callSolana.createResource(salt, 165, 6960*165, program_id); // FwBENPdrTaxftBCnvXNDAyMAk4yYgZjhwqd7xvDNEDpG + bytes32 mint = 0xf396da383e57418540f8caa598584f49a3b50d256f75cb6d94d101681d6d9d21; // HPsV9Deocecw3GeZv1FkAPNCBRfuVyfw9MMwjwRe1xaU + //bytes32 owner = _callSolana.getNeonAddress(address(this)); // 4rcXs8Z5PJCdiR6nj6G8BiGCwsf16wseYCyE54o7t7UA + bytes32 owner = getNeonAddress(address(this)); + bytes32 rent = 0x06a7d517192c5c51218cc94c3d4af17f58daee089ba1fd44e3dbd98a00000000; // SysvarRent111111111111111111111111111111111 + + { // Call SPLToken::InitailizeAccount() for resource,mint,owner,rent accounts + bytes4 selector = bytes4(keccak256("execute(uint64,bytes)")); + bool success; + assembly { + let buff := mload(0x40) // the head of heap + let pos := buff + + // selector + mstore(pos, selector) + pos := add(pos, 4) + + // required_lamports + mstore(pos, 0) + pos := add(pos, 32) + + // offset for instruction + mstore(pos, sub(add(pos, 28), buff)) + pos := add(pos, 32) + let size_pos := pos + pos := add(pos, 32) + + // program_id + mstore(pos, program_id) + pos := add(pos, 32) + + // len(accounts) + mstore(pos, 0) + mstore8(pos, 4) + pos := add(pos, 8) + + // AccountMeta(resource, false, true) + mstore(pos, resource) + mstore8(add(pos, 32), 0) + mstore8(add(pos, 33), 1) + pos := add(pos, 34) + + // AccountMeta(mint, false, false) + mstore(pos, mint) + mstore8(add(pos, 32), 0) + mstore8(add(pos, 33), 0) + pos := add(pos, 34) + + // AccountMeta(owner, false, false) + mstore(pos, owner) + mstore8(add(pos, 32), 0) + mstore8(add(pos, 33), 0) + pos := add(pos, 34) + + // AccountMeta(rent, false, false) + mstore(pos, rent) + mstore8(add(pos, 32), 0) + mstore8(add(pos, 33), 0) + pos := add(pos, 34) + + // len(instruction_data) + mstore(pos, 0) + mstore8(pos, 1) + pos := add(pos, 8) + + // instruction_data: InitializeAccount + mstore8(pos, 1) + pos := add(pos, 1) + + mstore(size_pos, sub(sub(pos, size_pos), 32)) + let length := sub(pos, buff) + mstore(0x40, pos) + success := call(5000, 0xFF00000000000000000000000000000000000006, 0, buff, length, buff, 0x20) + mstore(0x40, buff) + } + if (success == false) { + revert("Can't initailize resource"); + } + } + + bytes32 source = 0xf567a23ec5b9f6a543bb3fd8d5ab7f2d4682fcb1908b755b477f116ec2925af8; // HWxYLBFfPxzrtGTKZL3VEN9dTDBz7qDgFXJVcw8zFkfq + { + bytes4 selector = bytes4(keccak256("execute(uint64,bytes)")); + uint amount = uint(reverse(1000)) << (256-64); + bool success; + assembly { + let buff := mload(0x40) + let pos := buff + + // selector + mstore(pos, selector) + pos := add(pos, 4) + + // required_lamports + mstore(pos, 0) + pos := add(pos, 32) + + // offset for instruction + mstore(pos, sub(add(pos, 28), buff)) + pos := add(pos, 32) + let size_pos := pos + pos := add(pos, 32) + + // program_id + mstore(pos, program_id) + pos := add(pos, 32) + + // len(accounts) + mstore(pos, 0) + mstore8(pos, 3) + pos := add(pos, 8) + + // AccountMeta(resource, false, true) + mstore(pos, source) + mstore8(add(pos, 32), 0) + mstore8(add(pos, 33), 1) + pos := add(pos, 34) + + // AccountMeta(mint, false, false) + mstore(pos, resource) + mstore8(add(pos, 32), 0) + mstore8(add(pos, 33), 1) + pos := add(pos, 34) + + // AccountMeta(owner, false, false) + mstore(pos, owner) + mstore8(add(pos, 32), 1) + mstore8(add(pos, 33), 0) + pos := add(pos, 34) + + // len(instruction_data) + mstore(pos, 0) + mstore8(pos, 9) + pos := add(pos, 8) + + // instruction_data: Transfer + mstore8(pos, 3) + mstore(add(pos, 1), amount) + pos := add(pos, 9) + + mstore(size_pos, sub(sub(pos, size_pos), 32)) + let length := sub(pos, buff) + mstore(0x40, pos) + success := call(5000, 0xFF00000000000000000000000000000000000006, 0, buff, length, buff, 0x20) + mstore(0x40, buff) + } + if (success == false) { + revert("Can't initailize resource"); + } + } + + balance = balanceOf(msg.sender); + } + + function balanceOf(address who) public view returns (uint256) { + bytes32 account = _solanaAccount(who); + return _splToken.getAccount(account).amount; + } + + function _salt(address account) internal pure returns (bytes32) { + return bytes32(uint256(uint160(account))); + } + + function _solanaAccount(address account) internal pure returns (bytes32) { + return _splToken.findAccount(_salt(account)); + } +} + + +/* +solana airdrop 1 +spl-token create-account HPsV9Deocecw3GeZv1FkAPNCBRfuVyfw9MMwjwRe1xaU +spl-token mint HPsV9Deocecw3GeZv1FkAPNCBRfuVyfw9MMwjwRe1xaU 1000000 HWxYLBFfPxzrtGTKZL3VEN9dTDBz7qDgFXJVcw8zFkfq --mint-authority ~/neonlabs/neon-evm.git/ci/evm_loader-keypair.json +spl-token approve HWxYLBFfPxzrtGTKZL3VEN9dTDBz7qDgFXJVcw8zFkfq 1000000 4rcXs8Z5PJCdiR6nj6G8BiGCwsf16wseYCyE54o7t7UA +spl-token display HWxYLBFfPxzrtGTKZL3VEN9dTDBz7qDgFXJVcw8zFkfq +*/ From a9669c385e888020f70fe78d9de136fe05a83cbd Mon Sep 17 00:00:00 2001 From: Stanislav Tkach Date: Mon, 29 Apr 2024 14:03:42 +0200 Subject: [PATCH 171/318] NDEV-2899: Make PrestateTracerDiffModeResult public (#395) --- evm_loader/lib/src/tracing/tracers/prestate_tracer/mod.rs | 2 ++ .../lib/src/tracing/tracers/prestate_tracer/state_diff.rs | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/evm_loader/lib/src/tracing/tracers/prestate_tracer/mod.rs b/evm_loader/lib/src/tracing/tracers/prestate_tracer/mod.rs index a18ea1d3c..bca8669c3 100644 --- a/evm_loader/lib/src/tracing/tracers/prestate_tracer/mod.rs +++ b/evm_loader/lib/src/tracing/tracers/prestate_tracer/mod.rs @@ -1,2 +1,4 @@ mod state_diff; pub mod tracer; + +pub use state_diff::{PrestateTracerAccount, PrestateTracerDiffModeResult, PrestateTracerState}; diff --git a/evm_loader/lib/src/tracing/tracers/prestate_tracer/state_diff.rs b/evm_loader/lib/src/tracing/tracers/prestate_tracer/state_diff.rs index d070aee9f..de4dd245c 100644 --- a/evm_loader/lib/src/tracing/tracers/prestate_tracer/state_diff.rs +++ b/evm_loader/lib/src/tracing/tracers/prestate_tracer/state_diff.rs @@ -7,7 +7,7 @@ use crate::tracing::tracers::state_diff::StateMap; use evm_loader::types::Address; /// See -type PrestateTracerState = BTreeMap; +pub type PrestateTracerState = BTreeMap; /// See #[derive(Debug, Clone, Serialize, Deserialize, Default)] @@ -18,6 +18,7 @@ pub struct PrestateTracerAccount { pub code: Option, #[serde(skip_serializing_if = "Option::is_none")] pub nonce: Option, + #[serde(default)] #[serde(skip_serializing_if = "BTreeMap::is_empty")] pub storage: BTreeMap, } From 9a1f994341ecb4f6ac7c9a1657f8bb8cea82247a Mon Sep 17 00:00:00 2001 From: Stanislav Tkach Date: Thu, 2 May 2024 12:46:04 +0200 Subject: [PATCH 172/318] NDEV-2950: Remove unused dependencies (#399) --- evm_loader/Cargo.lock | 3 --- evm_loader/api/Cargo.toml | 1 - evm_loader/rpc-client/Cargo.toml | 1 - 3 files changed, 5 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 6871d2fe9..980726f45 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -3293,7 +3293,6 @@ dependencies = [ "solana-client", "solana-sdk", "tokio", - "tower", "tracing", "tracing-appender", "tracing-subscriber", @@ -3407,7 +3406,6 @@ version = "0.1.0" dependencies = [ "async-trait", "build-info", - "jsonrpc-v2", "jsonrpsee-core", "jsonrpsee-http-client", "jsonrpsee-types", @@ -6747,7 +6745,6 @@ dependencies = [ "futures-util", "pin-project", "pin-project-lite", - "tokio", "tower-layer", "tower-service", "tracing", diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index f878b793f..648eef842 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -17,7 +17,6 @@ tokio = { version = "1", features = ["full"] } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } tracing-appender = "0.2.3" -tower = { version = "0.4", features = ["make"] } neon-lib = { path = "../lib" } actix-web = "4.5.1" actix-request-identifier = "4.1.0" diff --git a/evm_loader/rpc-client/Cargo.toml b/evm_loader/rpc-client/Cargo.toml index 7eb22c560..5a2e5f318 100644 --- a/evm_loader/rpc-client/Cargo.toml +++ b/evm_loader/rpc-client/Cargo.toml @@ -8,7 +8,6 @@ edition = "2021" [dependencies] serde = "1.0.189" serde_json = "1.0.115" -jsonrpc-v2 = "0.13.0" neon-lib = { path = "../lib" } thiserror = "1.0.58" async-trait = "0.1.79" From 8c95d800c82009a5a8b52d12f0d0306e573ebe80 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 May 2024 10:47:32 +0300 Subject: [PATCH 173/318] Bump actix-request-identifier from 4.1.0 to 4.2.0 in /evm_loader (#393) Bumps [actix-request-identifier](https://github.com/vbrandl/actix-request-identifier) from 4.1.0 to 4.2.0. - [Release notes](https://github.com/vbrandl/actix-request-identifier/releases) - [Changelog](https://github.com/vbrandl/actix-request-identifier/blob/master/CHANGELOG.md) - [Commits](https://github.com/vbrandl/actix-request-identifier/compare/v4.1.0...v4.2.0) --- updated-dependencies: - dependency-name: actix-request-identifier dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 8 ++++---- evm_loader/api/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 980726f45..3eced8eab 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -128,9 +128,9 @@ dependencies = [ [[package]] name = "actix-request-identifier" -version = "4.1.0" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f620de7c806297b88cf39da5ef4293a59f7dc219a9838433e83238e53a9c7057" +checksum = "901b615d14f5272a2451016a3718c75bed90f3e0b44a7757208809a384c34166" dependencies = [ "actix-web", "futures", @@ -7001,9 +7001,9 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] name = "uuid" -version = "1.5.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" dependencies = [ "getrandom 0.2.12", ] diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 648eef842..10f053491 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -19,7 +19,7 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] } tracing-appender = "0.2.3" neon-lib = { path = "../lib" } actix-web = "4.5.1" -actix-request-identifier = "4.1.0" +actix-request-identifier = "4.2.0" hex = "0.4.2" build-info = { version = "0.0.31", features = ["serde"] } From d9d09fe3fe084efd1daea30106f71b3765972b27 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Fri, 10 May 2024 10:19:51 +0300 Subject: [PATCH 174/318] Support ALT in simulate_solana request --- .../lib/src/commands/simulate_solana.rs | 86 +++++++++++++++---- evm_loader/lib/src/solana_simulator/mod.rs | 32 ++++--- evm_loader/lib/src/types/mod.rs | 1 + 3 files changed, 91 insertions(+), 28 deletions(-) diff --git a/evm_loader/lib/src/commands/simulate_solana.rs b/evm_loader/lib/src/commands/simulate_solana.rs index ae32fbadb..019f20334 100644 --- a/evm_loader/lib/src/commands/simulate_solana.rs +++ b/evm_loader/lib/src/commands/simulate_solana.rs @@ -5,7 +5,10 @@ use serde::{Deserialize, Serialize}; use serde_with::serde_as; use solana_program_runtime::compute_budget::ComputeBudget; use solana_runtime::runtime_config::RuntimeConfig; -use solana_sdk::{pubkey::Pubkey, transaction::VersionedTransaction}; +use solana_sdk::{ + pubkey::Pubkey, + transaction::{SanitizedTransaction, Transaction, VersionedTransaction}, +}; use crate::{ rpc::Rpc, solana_simulator::SolanaSimulator, types::SimulateSolanaRequest, NeonResult, @@ -25,40 +28,89 @@ pub struct SimulateSolanaResponse { transactions: Vec, } -pub async fn execute( - rpc: &impl Rpc, - request: SimulateSolanaRequest, -) -> NeonResult { - let mut transactions: Vec = vec![]; - for data in request.transactions { - let tx = bincode::options() - .with_fixint_encoding() - .allow_trailing_bytes() - .deserialize(&data)?; +fn decode_transaction(data: &[u8]) -> NeonResult { + let tx_result = bincode::options() + .with_fixint_encoding() + .allow_trailing_bytes() + .deserialize::(data); - transactions.push(tx); + if let Ok(tx) = tx_result { + return Ok(tx); } + let tx = bincode::options() + .with_fixint_encoding() + .allow_trailing_bytes() + .deserialize::(data)?; + + Ok(tx.into()) +} + +fn address_table_lookups(txs: &[VersionedTransaction]) -> Vec { + let mut accounts: HashSet = HashSet::::new(); + for tx in txs { + let Some(address_table_lookups) = tx.message.address_table_lookups() else { + continue; + }; + + for alt in address_table_lookups { + accounts.insert(alt.account_key); + } + } + + accounts.into_iter().collect() +} + +fn account_keys(txs: &[SanitizedTransaction]) -> Vec { let mut accounts: HashSet = HashSet::::new(); - for tx in &transactions { - let keys = tx.message.static_account_keys(); - accounts.extend(keys); + for tx in txs { + let keys = tx.message().account_keys(); + accounts.extend(keys.iter()); } + accounts.into_iter().collect() +} + +pub async fn execute( + rpc: &impl Rpc, + request: SimulateSolanaRequest, +) -> NeonResult { let config = RuntimeConfig { compute_budget: request.compute_units.map(ComputeBudget::new), log_messages_bytes_limit: Some(100 * 1024), transaction_account_lock_limit: request.account_limit, }; + let verify = request.verify.unwrap_or(true); + let mut simulator = SolanaSimulator::new_with_config(rpc, config).await?; - let accounts: Vec = accounts.into_iter().collect(); + // Decode transactions from bytes + let mut transactions: Vec = vec![]; + for data in request.transactions { + let tx = decode_transaction(&data)?; + transactions.push(tx); + } + + // Download ALT + let alt = address_table_lookups(&transactions); + simulator.sync_accounts(rpc, &alt).await?; + + // Sanitize transactions (verify tx and decode ALT) + let mut sanitized_transactions: Vec = vec![]; + for tx in transactions { + let sanitized = simulator.sanitize_transaction(tx, verify)?; + sanitized_transactions.push(sanitized); + } + + // Download accounts + let accounts = account_keys(&sanitized_transactions); simulator.sync_accounts(rpc, &accounts).await?; + // Process transactions simulator.replace_blockhash(&request.blockhash.into()); let results = simulator - .process_multiple_transactions(transactions)? + .process_multiple_transactions(&sanitized_transactions)? .into_iter() .map(|r| SimulateSolanaTransactionResult { error: r.status.err(), diff --git a/evm_loader/lib/src/solana_simulator/mod.rs b/evm_loader/lib/src/solana_simulator/mod.rs index 47b052ccd..29ad34216 100644 --- a/evm_loader/lib/src/solana_simulator/mod.rs +++ b/evm_loader/lib/src/solana_simulator/mod.rs @@ -180,29 +180,39 @@ impl SolanaSimulator { .map(Account::from) } + pub fn sanitize_transaction( + &self, + tx: VersionedTransaction, + verify: bool, + ) -> Result { + let bank = self.bank(); + + let sanitized = if verify { + bank.verify_transaction(tx, TransactionVerificationMode::FullVerification)? + } else { + let hash = tx.message.hash(); + SanitizedTransaction::try_create(tx, hash, None, bank)? + }; + + Ok(sanitized) + } + pub fn process_transaction( &mut self, - tx: VersionedTransaction, + tx: SanitizedTransaction, ) -> Result { - let mut result = self.process_multiple_transactions(vec![tx])?; + let mut result = self.process_multiple_transactions(&[tx])?; Ok(result.remove(0)) } pub fn process_multiple_transactions( &mut self, - txs: Vec, + txs: &[SanitizedTransaction], ) -> Result, Error> { let bank = self.bank(); - let mut sanitized_transactions = vec![]; - for tx in txs { - let sanitized = - bank.verify_transaction(tx, TransactionVerificationMode::FullVerification)?; - sanitized_transactions.push(sanitized); - } - - let batch = bank.prepare_sanitized_batch(&sanitized_transactions); + let batch = bank.prepare_sanitized_batch(txs); let ( solana_accounts_db::transaction_results::TransactionResults { diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index 13d9e5555..c6b8f62ed 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -239,6 +239,7 @@ pub struct GetHolderRequest { pub struct SimulateSolanaRequest { pub compute_units: Option, pub account_limit: Option, + pub verify: Option, #[serde_as(as = "Hex")] pub blockhash: [u8; 32], #[serde_as(as = "Vec")] From fdd275b9aae2481b1966834c0bb4e35106afa5db Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 May 2024 13:25:52 +0300 Subject: [PATCH 175/318] Bump syn from 2.0.58 to 2.0.61 in /evm_loader (#403) Bumps [syn](https://github.com/dtolnay/syn) from 2.0.58 to 2.0.61. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.58...2.0.61) --- updated-dependencies: - dependency-name: syn dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 78 +++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 3eced8eab..84ed367a3 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -123,7 +123,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -247,7 +247,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -628,7 +628,7 @@ checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -982,7 +982,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.58", + "syn 2.0.61", "xz2", ] @@ -1025,7 +1025,7 @@ checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -1552,7 +1552,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -1569,7 +1569,7 @@ checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -1593,7 +1593,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -1604,7 +1604,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -1776,7 +1776,7 @@ checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -1867,7 +1867,7 @@ checksum = "eecf8589574ce9b895052fa12d69af7a233f99e6107f5cb8dd1044f2a17bfdcb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -1879,7 +1879,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -2018,7 +2018,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.58", + "syn 2.0.61", "toml 0.8.2", ] @@ -2193,7 +2193,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -3133,7 +3133,7 @@ checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -3525,7 +3525,7 @@ checksum = "cfb77679af88f8b125209d354a202862602672222e7f2313fdd6dc349bad4712" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -3607,7 +3607,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -3619,7 +3619,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -3681,7 +3681,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -3851,7 +3851,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -4011,7 +4011,7 @@ checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -4661,7 +4661,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -4745,7 +4745,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -4757,7 +4757,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -5358,7 +5358,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -5827,7 +5827,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -6147,7 +6147,7 @@ checksum = "fadbefec4f3c678215ca72bd71862697bb06b41fd77c0088902dd3203354387b" dependencies = [ "quote", "spl-discriminator-syn", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -6159,7 +6159,7 @@ dependencies = [ "proc-macro2", "quote", "sha2 0.10.8", - "syn 2.0.58", + "syn 2.0.61", "thiserror", ] @@ -6207,7 +6207,7 @@ dependencies = [ "proc-macro2", "quote", "sha2 0.10.8", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -6381,7 +6381,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -6409,9 +6409,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.58" +version = "2.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" +checksum = "c993ed8ccba56ae856363b1845da7266a7cb78e1d146c8a32d54b45a8b831fc9" dependencies = [ "proc-macro2", "quote", @@ -6500,7 +6500,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -6617,7 +6617,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -6794,7 +6794,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -7091,7 +7091,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", "wasm-bindgen-shared", ] @@ -7125,7 +7125,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -7567,7 +7567,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] @@ -7587,7 +7587,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.61", ] [[package]] From 14981ca39b9ec569831ce8648bacae0dd3d14089 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 May 2024 15:50:49 +0300 Subject: [PATCH 176/318] Bump rustls from 0.21.7 to 0.21.12 in /evm_loader (#406) Bumps [rustls](https://github.com/rustls/rustls) from 0.21.7 to 0.21.12. - [Release notes](https://github.com/rustls/rustls/releases) - [Changelog](https://github.com/rustls/rustls/blob/main/CHANGELOG.md) - [Commits](https://github.com/rustls/rustls/compare/v/0.21.7...v/0.21.12) --- updated-dependencies: - dependency-name: rustls dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 53 ++++++++++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 84ed367a3..7121f161c 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -4039,7 +4039,7 @@ checksum = "141bf7dfde2fbc246bfd3fe12f2455aa24b0fbd9af535d8c86c7bd1381ff2b1a" dependencies = [ "bytes", "rand 0.8.5", - "ring", + "ring 0.16.20", "rustc-hash", "rustls", "rustls-native-certs", @@ -4214,7 +4214,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" dependencies = [ "pem", - "ring", + "ring 0.16.20", "time", "yasna", ] @@ -4363,12 +4363,27 @@ dependencies = [ "cc", "libc", "once_cell", - "spin", - "untrusted", + "spin 0.5.2", + "untrusted 0.7.1", "web-sys", "winapi", ] +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.12", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys 0.52.0", +] + [[package]] name = "ripemd" version = "0.1.3" @@ -4460,12 +4475,12 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.7" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", - "ring", + "ring 0.17.8", "rustls-webpki", "sct", ] @@ -4493,12 +4508,12 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.101.4" +version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d93931baf2d282fff8d3a532bbfd7653f734643161b87e3e01e59a04439bf0d" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring", - "untrusted", + "ring 0.17.8", + "untrusted 0.9.0", ] [[package]] @@ -4569,8 +4584,8 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" dependencies = [ - "ring", - "untrusted", + "ring 0.16.20", + "untrusted 0.7.1", ] [[package]] @@ -6102,6 +6117,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "spki" version = "0.5.4" @@ -6972,6 +6993,12 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "uriparse" version = "0.6.4" From 1478d6e6a50bd294fd3afee175eeee27a7af1c5a Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Mon, 13 May 2024 01:04:11 +0300 Subject: [PATCH 177/318] NDEV-3007: Update Solana to v1.17.33 (#407) --- .github/workflows/deploy.py | 4 +- evm_loader/Cargo.lock | 188 ++++++++++++++++++------------------ evm_loader/Cargo.toml | 18 ++-- 3 files changed, 105 insertions(+), 105 deletions(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index 7a2c26d79..c4909e0a7 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -32,8 +32,8 @@ IMAGE_NAME = os.environ.get("IMAGE_NAME") RUN_LINK_REPO = os.environ.get("RUN_LINK_REPO") DOCKERHUB_ORG_NAME = os.environ.get("DOCKERHUB_ORG_NAME") -SOLANA_NODE_VERSION = 'v1.17.31' -SOLANA_BPF_VERSION = 'v1.17.31' +SOLANA_NODE_VERSION = 'v1.17.33' +SOLANA_BPF_VERSION = 'v1.17.33' VERSION_BRANCH_TEMPLATE = r"[vt]{1}\d{1,2}\.\d{1,2}\.x.*" docker_client = docker.APIClient() diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 7121f161c..719e338d6 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -4956,9 +4956,9 @@ dependencies = [ [[package]] name = "solana-account-decoder" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4e29f060cabd0e1bd90a63f8e1517ddd3365d3dc2eaa05f9a9fa542f4adeaaa" +checksum = "ed136199e67867bea960ab65895e150b0f767b1f6d9e7093a62a875f7f33d207" dependencies = [ "Inflector", "base64 0.21.7", @@ -4981,9 +4981,9 @@ dependencies = [ [[package]] name = "solana-accounts-db" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e32ca00e7785d0fde702aa6c9fa749d33d1c275980baee85de0543357cae28" +checksum = "bbb104530ea601d2dad1232449589c6198e26e70c1c9d0be1fb0ba1a40a546df" dependencies = [ "arrayref", "bincode", @@ -5040,9 +5040,9 @@ dependencies = [ [[package]] name = "solana-address-lookup-table-program" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71a93d1c1a0c13de20e13a0c9bd7275b00bb901b8b7c55424fea98f71cb37778" +checksum = "5152bcbdcd1dd698cd3182ce4e810f6f4ff18ce3260e934005dba4c5d53293db" dependencies = [ "bincode", "bytemuck", @@ -5061,9 +5061,9 @@ dependencies = [ [[package]] name = "solana-bpf-loader-program" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a396f4190c9bc81ec2d697673a571d7f064634916105fdf9efecb6fa5bec818" +checksum = "60bdb8a5c42a514b00605ec184870aee7230a0610b46d56aa19e8a77928a0d80" dependencies = [ "bincode", "byteorder", @@ -5080,9 +5080,9 @@ dependencies = [ [[package]] name = "solana-bucket-map" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4efb7bc86741650dc2a942d23e7e714d41bbc46eff5555784ec87ee7a591615" +checksum = "4bee6b54dc14d1cdf80334934745ae5011dda936cdcd5316b9d393a912dc2132" dependencies = [ "bv", "bytemuck", @@ -5098,9 +5098,9 @@ dependencies = [ [[package]] name = "solana-clap-utils" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62e5cdc0ae0c8ae79c39a4a362066d0d61764bc7ea7e033961fd7510fd24da2a" +checksum = "ae9cafd23f6641f118dd11148f950309139849b74b28ec9dfafbfa00457761b9" dependencies = [ "chrono", "clap 2.34.0", @@ -5115,9 +5115,9 @@ dependencies = [ [[package]] name = "solana-cli" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "599b8cac742270ddc097458623d9688b3ad03e6adb19987e993f47ec51b330eb" +checksum = "598d94119670b731a168e72f343260e37e38d221a116db974a6553d4da1be74a" dependencies = [ "bincode", "bs58 0.4.0", @@ -5166,9 +5166,9 @@ dependencies = [ [[package]] name = "solana-cli-config" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6de25e2f3e00901ffbe09e625303fdda62baaa584992027bdc92fc3fca04e1a" +checksum = "632f34d4a96028066250b48f4255fa53ab561dab145cc0c2db8f1e403c48e33b" dependencies = [ "dirs-next", "lazy_static", @@ -5182,9 +5182,9 @@ dependencies = [ [[package]] name = "solana-cli-output" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b3aca5a25e1ca04b5b1107bcdc26fcc69d167df0f617dbca5967df62e0d42" +checksum = "4c20066a01daa20b7b31d44318558517ed9e7da1c7e4e017210d2b659fce255f" dependencies = [ "Inflector", "base64 0.21.7", @@ -5209,9 +5209,9 @@ dependencies = [ [[package]] name = "solana-client" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1e2301c2af7e5a1dba0855f710329a2bb993829ed9fdf8f6207d02ee6fc54a4" +checksum = "d221979e0ee0f8133e9a02a6a9d54a004c59a6857e9b245e4cb4a7541826a662" dependencies = [ "async-trait", "bincode", @@ -5242,9 +5242,9 @@ dependencies = [ [[package]] name = "solana-compute-budget-program" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773ae3c4d99f9ed06d9dc5c6541df1db16bc42d77f91c46b9c9b117fc5e129b3" +checksum = "e7056e3d37696525e1257090ec9af4ee8667aac3fbda313f801b712b3b5bce11" dependencies = [ "solana-program-runtime", "solana-sdk", @@ -5252,9 +5252,9 @@ dependencies = [ [[package]] name = "solana-config-program" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595118948b966b110aad3f9d8d8464958abe379ecfa7a813b4fc82659c8259bc" +checksum = "e66d677aafa8822aae006cebe3b55587b610541e4f8f4e34987463d0640d05ad" dependencies = [ "bincode", "chrono", @@ -5266,9 +5266,9 @@ dependencies = [ [[package]] name = "solana-connection-cache" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d363d6bb43e618b6010b47c2eb0579777ce4ed388ca15b84a610a738edf0b97e" +checksum = "716f64f1c9ed455729a8de412b7b3ad200b47997b4f68408a1bb65c2a61ccf80" dependencies = [ "async-trait", "bincode", @@ -5288,9 +5288,9 @@ dependencies = [ [[package]] name = "solana-cost-model" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1e8673cd74543895f310eb2dfd497c7ffc970a799923bd0f8fd6e0320e14ab" +checksum = "47c669f8432952cfe1fa50a6e26827a4b99a3fdfdff229b218f4882668ea89f0" dependencies = [ "lazy_static", "log", @@ -5312,9 +5312,9 @@ dependencies = [ [[package]] name = "solana-faucet" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ad19317b6d6302967fe8946a27eb95ba9df67167a7ddf5f538ede312d899471" +checksum = "c7b988b2989fa6c0c0ff9feafa0f1e4b2571fb1953e88fcb109112219e5edf4b" dependencies = [ "bincode", "byteorder", @@ -5336,9 +5336,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96734b05823c8b515f8e3cc02641a27aee2c9760b1a43c74cb20f2a1ab0ab76c" +checksum = "ef1d4f626d41690e30273990808709fa189f32d2ab55724870e9dbf03107b8a7" dependencies = [ "ahash 0.8.5", "blake3", @@ -5366,9 +5366,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi-macro" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a0f1291a464fd046135d019d57a81be165ee3d23aa7df880b47dac683a0582a" +checksum = "b82e46dc5348003a010c8b05b494d800a7cfd5793b3dd843a4d664306fce2edc" dependencies = [ "proc-macro2", "quote", @@ -5378,9 +5378,9 @@ dependencies = [ [[package]] name = "solana-loader-v4-program" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a437265099d9782e1f95eee2feb3b9b4f0247a177d0c0646148da738ae3b1f" +checksum = "331541db807a0a2bfd29fbc39b2c5f17779d3cc9bc29ea70fe0a719689a2c580" dependencies = [ "log", "solana-measure", @@ -5391,9 +5391,9 @@ dependencies = [ [[package]] name = "solana-logger" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5977c8f24b83cf50e7139ffdb25d70bad6a177f18ccc79ca2293d6a987fa81c" +checksum = "be76f972b4863c350a408f112979ee607950640d58c164b3c3437c0fbc347867" dependencies = [ "env_logger", "lazy_static", @@ -5402,9 +5402,9 @@ dependencies = [ [[package]] name = "solana-measure" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a39ef01b2c65552d05013b2642ffd73258f2c80e3a59e44c499762047df9456" +checksum = "abd540426200a9bb393de5640ae91c2d39909cefca902e529e6fe20709526cf5" dependencies = [ "log", "solana-sdk", @@ -5412,9 +5412,9 @@ dependencies = [ [[package]] name = "solana-metrics" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ad30ff3775412f2929d440446aef8b070676920bc5df495ea6398a8f28ce91f" +checksum = "aa7fe468cdc1113b181f5958414c897593f484e9feaef35c96f8c26c9d39bbdd" dependencies = [ "crossbeam-channel", "gethostname", @@ -5427,9 +5427,9 @@ dependencies = [ [[package]] name = "solana-net-utils" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafd5178a38a039e12c14780f1b6a74f1e672d62357343e0aee6d0fc7e5bd18" +checksum = "8508f0496a42a469c9ffa9b4e9e81a40bc71b93248a8fa759f27b3e9865208bd" dependencies = [ "bincode", "clap 3.2.23", @@ -5449,9 +5449,9 @@ dependencies = [ [[package]] name = "solana-perf" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10d6293cddcc98ae092d00f43f741405da30aa083acb96666606130810b064f3" +checksum = "1b80387cc3b7e2b0c26c67cdd67e08bc461fccb3f62a363e8e1fc32e8270f64d" dependencies = [ "ahash 0.8.5", "bincode", @@ -5478,9 +5478,9 @@ dependencies = [ [[package]] name = "solana-program" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6412447793f8a3ef7526655906728325093b472e481791ac5c584e8d272166dc" +checksum = "85f79df075d0cf539285c529a683bb0a8cfe819b9ccefad0c9eb6fe567b3528a" dependencies = [ "ark-bn254", "ark-ec", @@ -5532,9 +5532,9 @@ dependencies = [ [[package]] name = "solana-program-runtime" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1977e741a6793fca27413507457d797df0f41bc0ae634247d112bc77ab2b0325" +checksum = "be80e2669f3659165f389d1049c5f4ca7305be44cd743ef7c79a5aed09635058" dependencies = [ "base64 0.21.7", "bincode", @@ -5560,9 +5560,9 @@ dependencies = [ [[package]] name = "solana-pubsub-client" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad21dd5d6fe09116dbc29aec279b7cf08d250b564899dc87437bd780ed26290" +checksum = "df12f8912a05adb1672de27d4509e35389bc29a46cf2253ecaf6e3ce76fba09c" dependencies = [ "crossbeam-channel", "futures-util", @@ -5585,9 +5585,9 @@ dependencies = [ [[package]] name = "solana-quic-client" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6201869768fe133ce9b8088e4f718f53ff164b8e5df3d0d46a6563a22545924f" +checksum = "e0b3cc12f0dce18f7c020363d876aa9258aa403404afcac29d7cf498c2d0d653" dependencies = [ "async-mutex", "async-trait", @@ -5612,9 +5612,9 @@ dependencies = [ [[package]] name = "solana-rayon-threadlimit" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f100d0c3214d67bb847a1eefc7079f6bb755534266423f4c994ad3b40c685ed" +checksum = "c5d3a9d5f8e6d4c35f1833c61c3afbe138dded89dc91842176f4734f5e56ee66" dependencies = [ "lazy_static", "num_cpus", @@ -5622,9 +5622,9 @@ dependencies = [ [[package]] name = "solana-remote-wallet" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3328c891079086b408a04e701470a346d517c9c51c0a96f2f166f616a3e1c3c8" +checksum = "7ecaac75eae288354b765125238ce6ecc46b405de2dd8e851e389e2b0c7fa9d2" dependencies = [ "console", "dialoguer", @@ -5642,9 +5642,9 @@ dependencies = [ [[package]] name = "solana-rpc-client" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfacf1163a375d98c29779a03ba278b2ef43494f77e33826a33f9460563c0887" +checksum = "cde5066e74eff9a714122012683f82ea8bf630b0112b9e83104d5685a9f2bf1b" dependencies = [ "async-trait", "base64 0.21.7", @@ -5668,9 +5668,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-api" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fab293a88113511e66607d76bd027edfe0b1372b467fd76bbb5af03448539a2" +checksum = "9f6ebb85cdcdb7c4f20806b29023c4ee5c7cacc0124478a3d309af52997a4773" dependencies = [ "base64 0.21.7", "bs58 0.4.0", @@ -5690,9 +5690,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-nonce-utils" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e43cb51374a6ec8fd401b3387334ef93e04f6d8ae87bbb29892aff42aeb1061" +checksum = "20426894bebb53f7b32dc5cf871e58ba381433c2858cb6338d00d4beb68f6cd6" dependencies = [ "clap 2.34.0", "solana-clap-utils", @@ -5703,9 +5703,9 @@ dependencies = [ [[package]] name = "solana-runtime" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c00486a8cc4fd4beddc5e22fdb1836c38a1280b6c708329bcfdfc61be39e377" +checksum = "e3790ebeb675aec5576251a7a71b0ab23e3aaa138d24bef0e83e13e8d64ee3a8" dependencies = [ "arrayref", "base64 0.21.7", @@ -5780,9 +5780,9 @@ dependencies = [ [[package]] name = "solana-sdk" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de1ce8848de4198f9bc7e4574252be02b1ed86ecbc2fff506780d5f8d6e4c4a8" +checksum = "9e2722c05330a72ba707715861e365d6b38e8bae0c6dc481032bc53b370469b5" dependencies = [ "assert_matches", "base64 0.21.7", @@ -5834,9 +5834,9 @@ dependencies = [ [[package]] name = "solana-sdk-macro" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cc46bbda0a5472d8d0a4c846b22941436ac45c31456d3e885a387a5f264f7" +checksum = "ae8907d340ee8f10d6c9e9530db93ead2a82c8e21da95d8f96e0298071faffea" dependencies = [ "bs58 0.4.0", "proc-macro2", @@ -5853,9 +5853,9 @@ checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" [[package]] name = "solana-stake-program" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d94e05db9762c5fc6114e788570c4645dbe7e7ea5da2e39269128944b3a200" +checksum = "c574ada0989783887f963d68a4889774d6b5397551c87030eee555a324c5859c" dependencies = [ "bincode", "log", @@ -5868,9 +5868,9 @@ dependencies = [ [[package]] name = "solana-streamer" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f02b475fc20c55ebbcfa5638ff93f9b780414cc6185e3a6d0992bca0ae81ee" +checksum = "b08adda24e6b06d6848bf0376f0641725b29d8c2710d980506c18190299a5b04" dependencies = [ "async-channel", "bytes", @@ -5901,9 +5901,9 @@ dependencies = [ [[package]] name = "solana-system-program" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eec04b67da2f353fe18dcf7e8bcdd6d8ddcece8598de55a6a7671fd01e9188f" +checksum = "a98b513f36cbc7a0ee120280b968010a958ef4e04e1e282b711a4d117d217c12" dependencies = [ "bincode", "log", @@ -5915,9 +5915,9 @@ dependencies = [ [[package]] name = "solana-thin-client" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6ce2304764b8bb699db734fde9cd19ace038d3895d828a557ea0ec2a9e0ecd" +checksum = "f878baf1685d7bf4ccd9edf53a863bde06ece1bb08c8306a3f623c84ee1be951" dependencies = [ "bincode", "log", @@ -5930,9 +5930,9 @@ dependencies = [ [[package]] name = "solana-tpu-client" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa3e2351625e26f55e5e08f8e5aadaa2380fd0649f25641d6ba3f3848dbe5c9a" +checksum = "66a0f44fcaf0fef6f077b03386242d60dad64a861e3dee3d3312f19f194cfb03" dependencies = [ "async-trait", "bincode", @@ -5954,9 +5954,9 @@ dependencies = [ [[package]] name = "solana-transaction-status" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0841bbd1845c87043e4184961e45cc7c08b36d96d0d146256b26ea5c74630a0f" +checksum = "cb26713d10ecdd8b2524e227736b3a80d2b8105afc17890b2592eaa83005b253" dependencies = [ "Inflector", "base64 0.21.7", @@ -5979,9 +5979,9 @@ dependencies = [ [[package]] name = "solana-udp-client" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bae54a100f0b0b5be065f5d05f2259f6d4a7b39f5866d579927f3ca35a01773b" +checksum = "0035cd922f58537b4754867ad3f9b0f5428815f4e1835a90b73e89cf17209fe5" dependencies = [ "async-trait", "solana-connection-cache", @@ -5994,9 +5994,9 @@ dependencies = [ [[package]] name = "solana-version" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f69945e38d7440221e2fac0aaa57a9d72adb329b0de705ca5bd9ba981aedc16" +checksum = "4f5f943a8bf30efba1fea89a157eaabd6753d6afa8d595b7b1449526a221f8ea" dependencies = [ "log", "rustc_version", @@ -6010,9 +6010,9 @@ dependencies = [ [[package]] name = "solana-vote" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0122b117497cac299cd52bbfcb9f3732d882833f5c87ee87d2d3541ba77057" +checksum = "14e09c7281abdba4a8cab1f413feaafaa8599a5d4eafa6c37790214f1531c11a" dependencies = [ "crossbeam-channel", "itertools 0.10.5", @@ -6029,9 +6029,9 @@ dependencies = [ [[package]] name = "solana-vote-program" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e574aafc3c5adc7106ab4605d8ad378c9a12f2cf1dec2e8ba1aa6fd97a5d5490" +checksum = "d235dd88b21d78bf5a341c7a80a0730ca078bece366305f53fad9dbd7e72c116" dependencies = [ "bincode", "log", @@ -6051,9 +6051,9 @@ dependencies = [ [[package]] name = "solana-zk-token-proof-program" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de791a3bb992976029ead33017d4d994614b10d3028c7598632019fdb432dcad" +checksum = "02967e947d0f17d10cc037fdb5e9ffbac90cd1e390270f765e93dabf82f46b38" dependencies = [ "bytemuck", "num-derive 0.3.3", @@ -6065,9 +6065,9 @@ dependencies = [ [[package]] name = "solana-zk-token-sdk" -version = "1.17.31" +version = "1.17.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597dddc8ab46852dea7fc3d22e031fa4ffdb1b2291ac24d960605424a510a5f5" +checksum = "229fbe8647285712f672ff6f61b32d04158a216c45d9094acecd07446665e791" dependencies = [ "aes-gcm-siv", "base64 0.21.7", diff --git a/evm_loader/Cargo.toml b/evm_loader/Cargo.toml index 26f1fa50b..371b5a7fa 100644 --- a/evm_loader/Cargo.toml +++ b/evm_loader/Cargo.toml @@ -12,12 +12,12 @@ members = [ ] [workspace.dependencies] -solana-clap-utils = "=1.17.31" -solana-cli = "=1.17.31" -solana-cli-config = "=1.17.31" -solana-client = "=1.17.31" -solana-program = { version = "=1.17.31", default-features = false } -solana-sdk = "=1.17.31" -solana-program-runtime = "=1.17.31" -solana-runtime = "=1.17.31" -solana-accounts-db = "=1.17.31" +solana-clap-utils = "=1.17.33" +solana-cli = "=1.17.33" +solana-cli-config = "=1.17.33" +solana-client = "=1.17.33" +solana-program = { version = "=1.17.33", default-features = false } +solana-sdk = "=1.17.33" +solana-program-runtime = "=1.17.33" +solana-runtime = "=1.17.33" +solana-accounts-db = "=1.17.33" From 96e5fab25d5c0aa5def02d71db170ac52cb6ba29 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Mon, 13 May 2024 12:16:55 +0300 Subject: [PATCH 178/318] NDEV-3013 Add `heap_size` to `simulate_solana` API request (#408) --- .../lib/src/commands/simulate_solana.rs | 20 ++++++++++++++----- evm_loader/lib/src/types/mod.rs | 1 + 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/evm_loader/lib/src/commands/simulate_solana.rs b/evm_loader/lib/src/commands/simulate_solana.rs index 019f20334..2d4bb3b11 100644 --- a/evm_loader/lib/src/commands/simulate_solana.rs +++ b/evm_loader/lib/src/commands/simulate_solana.rs @@ -71,16 +71,26 @@ fn account_keys(txs: &[SanitizedTransaction]) -> Vec { accounts.into_iter().collect() } +fn runtime_config(request: &SimulateSolanaRequest) -> RuntimeConfig { + let compute_units = request.compute_units.unwrap_or(1_400_000); + let heap_size = request.heap_size.unwrap_or(256 * 1024); + + let mut compute_budget = ComputeBudget::new(compute_units); + compute_budget.heap_size = heap_size; + + RuntimeConfig { + compute_budget: Some(compute_budget), + log_messages_bytes_limit: Some(100 * 1024), + transaction_account_lock_limit: request.account_limit, + } +} + pub async fn execute( rpc: &impl Rpc, request: SimulateSolanaRequest, ) -> NeonResult { - let config = RuntimeConfig { - compute_budget: request.compute_units.map(ComputeBudget::new), - log_messages_bytes_limit: Some(100 * 1024), - transaction_account_lock_limit: request.account_limit, - }; let verify = request.verify.unwrap_or(true); + let config = runtime_config(&request); let mut simulator = SolanaSimulator::new_with_config(rpc, config).await?; diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index c6b8f62ed..4420fc651 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -238,6 +238,7 @@ pub struct GetHolderRequest { #[derive(Deserialize, Serialize, Debug, Default)] pub struct SimulateSolanaRequest { pub compute_units: Option, + pub heap_size: Option, pub account_limit: Option, pub verify: Option, #[serde_as(as = "Hex")] From 9a0f281a10d1fbaea7f08bb33d7d3d38d8ac7595 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 May 2024 14:53:38 +0300 Subject: [PATCH 179/318] Bump serde_with from 3.7.0 to 3.8.1 in /evm_loader (#405) Bumps [serde_with](https://github.com/jonasbb/serde_with) from 3.7.0 to 3.8.1. - [Release notes](https://github.com/jonasbb/serde_with/releases) - [Commits](https://github.com/jonasbb/serde_with/compare/v3.7.0...v3.8.1) --- updated-dependencies: - dependency-name: serde_with dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 14 +++++++------- evm_loader/lib/Cargo.toml | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 719e338d6..7b3f6ff03 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -3350,7 +3350,7 @@ dependencies = [ "scroll", "serde", "serde_json", - "serde_with 3.7.0", + "serde_with 3.8.1", "solana-accounts-db", "solana-cli", "solana-cli-config", @@ -4735,11 +4735,11 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.7.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee80b0e361bbf88fd2f6e242ccd19cfda072cb0faa6ae694ecee08199938569a" +checksum = "0ad483d2ab0149d5a5ebcd9972a3852711e0153d863bf5a5d0391d28883c4a20" dependencies = [ - "base64 0.21.7", + "base64 0.22.0", "chrono", "hex", "indexmap 1.9.3", @@ -4747,7 +4747,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "serde_with_macros 3.7.0", + "serde_with_macros 3.8.1", "time", ] @@ -4765,9 +4765,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.7.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6561dc161a9224638a31d876ccdfefbc1df91d3f3a8342eddb35f055d48c7655" +checksum = "65569b702f41443e8bc8bbb1c5779bd0450bbe723b56198980e80ec45780bce2" dependencies = [ "darling", "proc-macro2", diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 47fe11e71..1b61f02d4 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -24,7 +24,7 @@ base64 = "0.22" hex = { version = "0.4", features = ["serde"] } serde = "1.0" serde_json = { version = "1.0", features = ["preserve_order"] } -serde_with = { version = "3.7", features = ["hex"] } +serde_with = { version = "3.8", features = ["hex"] } log = "0.4.21" rand = "0.8" ethnum = { version = "1.5", default-features = false, features = ["serde"] } From 2d0153c35d5b90639b4f99fff066bc41183bde53 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Mon, 13 May 2024 18:44:07 +0300 Subject: [PATCH 180/318] NDEV-3012 Fix ALT support in `simulate_solana` request (#411) --- evm_loader/lib/src/commands/simulate_solana.rs | 12 ++++++------ evm_loader/lib/src/solana_simulator/error.rs | 2 ++ evm_loader/lib/src/solana_simulator/mod.rs | 16 ++++++++++------ evm_loader/lib/src/solana_simulator/utils.rs | 18 ++++++++++++++++++ 4 files changed, 36 insertions(+), 12 deletions(-) diff --git a/evm_loader/lib/src/commands/simulate_solana.rs b/evm_loader/lib/src/commands/simulate_solana.rs index 2d4bb3b11..de9402d16 100644 --- a/evm_loader/lib/src/commands/simulate_solana.rs +++ b/evm_loader/lib/src/commands/simulate_solana.rs @@ -116,18 +116,18 @@ pub async fn execute( let accounts = account_keys(&sanitized_transactions); simulator.sync_accounts(rpc, &accounts).await?; - // Process transactions simulator.replace_blockhash(&request.blockhash.into()); - let results = simulator - .process_multiple_transactions(&sanitized_transactions)? - .into_iter() - .map(|r| SimulateSolanaTransactionResult { + // Process transactions + let mut results = Vec::new(); + for tx in sanitized_transactions { + let r = simulator.process_transaction(tx)?; + results.push(SimulateSolanaTransactionResult { error: r.status.err(), logs: r.log_messages.unwrap_or_default(), executed_units: r.executed_units, }) - .collect(); + } Ok(SimulateSolanaResponse { transactions: results, diff --git a/evm_loader/lib/src/solana_simulator/error.rs b/evm_loader/lib/src/solana_simulator/error.rs index 405ebf230..f863ea2fa 100644 --- a/evm_loader/lib/src/solana_simulator/error.rs +++ b/evm_loader/lib/src/solana_simulator/error.rs @@ -18,4 +18,6 @@ pub enum Error { SanitizeError(#[from] solana_sdk::sanitize::SanitizeError), #[error("Instruction error {0:?}")] InstructionError(#[from] solana_sdk::instruction::InstructionError), + #[error("Invalid ALT")] + InvalidALT, } diff --git a/evm_loader/lib/src/solana_simulator/mod.rs b/evm_loader/lib/src/solana_simulator/mod.rs index 29ad34216..8e9981853 100644 --- a/evm_loader/lib/src/solana_simulator/mod.rs +++ b/evm_loader/lib/src/solana_simulator/mod.rs @@ -9,7 +9,7 @@ use solana_runtime::{ }; use solana_sdk::{ account::Account, - bpf_loader, bpf_loader_upgradeable, + address_lookup_table, bpf_loader, bpf_loader_upgradeable, hash::Hash, pubkey::Pubkey, signature::Keypair, @@ -79,12 +79,12 @@ impl SolanaSimulator { } pub async fn sync_accounts(&mut self, rpc: &impl Rpc, keys: &[Pubkey]) -> Result<(), Error> { - let mut storable_accounts = vec![]; + let mut storable_accounts: Vec<(&Pubkey, &Account)> = vec![]; let mut programdata_keys = vec![]; - let accounts = rpc.get_multiple_accounts(keys).await?; - for (key, account) in keys.iter().zip(&accounts) { + let mut accounts = rpc.get_multiple_accounts(keys).await?; + for (key, account) in keys.iter().zip(&mut accounts) { let Some(account) = account else { continue; }; @@ -94,6 +94,10 @@ impl SolanaSimulator { programdata_keys.push(programdata_address); } + if account.owner == address_lookup_table::program::id() { + utils::reset_alt_slot(account).map_err(|_| Error::InvalidALT)?; + } + storable_accounts.push((key, account)); } @@ -201,12 +205,12 @@ impl SolanaSimulator { &mut self, tx: SanitizedTransaction, ) -> Result { - let mut result = self.process_multiple_transactions(&[tx])?; + let mut result = self.process_multiple_not_intersected_transactions(&[tx])?; Ok(result.remove(0)) } - pub fn process_multiple_transactions( + pub fn process_multiple_not_intersected_transactions( &mut self, txs: &[SanitizedTransaction], ) -> Result, Error> { diff --git a/evm_loader/lib/src/solana_simulator/utils.rs b/evm_loader/lib/src/solana_simulator/utils.rs index ff751766a..35612bd75 100644 --- a/evm_loader/lib/src/solana_simulator/utils.rs +++ b/evm_loader/lib/src/solana_simulator/utils.rs @@ -6,6 +6,10 @@ use solana_runtime::{ use solana_sdk::{ account::Account, account_utils::StateMut, + address_lookup_table::{ + self, + state::{AddressLookupTable, LookupTableMeta}, + }, bpf_loader_upgradeable::{self, UpgradeableLoaderState}, fee_calculator::DEFAULT_TARGET_LAMPORTS_PER_SIGNATURE, native_token::sol_to_lamports, @@ -190,3 +194,17 @@ pub fn reset_program_data_slot(account: &mut Account) -> Result<(), Error> { Ok(()) } + +pub fn reset_alt_slot(account: &mut Account) -> Result<(), Error> { + assert!(account.owner == address_lookup_table::program::id()); + + let lookup_table = AddressLookupTable::deserialize(&account.data)?; + let metadata = LookupTableMeta { + last_extended_slot: 0, + ..lookup_table.meta + }; + + AddressLookupTable::overwrite_meta_data(&mut account.data, metadata)?; + + Ok(()) +} From ea96f6122ca07e74ae117c140591fe0c260e9dcd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 May 2024 10:42:25 +0300 Subject: [PATCH 181/318] Bump semver from 1.0.22 to 1.0.23 in /evm_loader (#410) Bumps [semver](https://github.com/dtolnay/semver) from 1.0.22 to 1.0.23. - [Release notes](https://github.com/dtolnay/semver/releases) - [Commits](https://github.com/dtolnay/semver/compare/1.0.22...1.0.23) --- updated-dependencies: - dependency-name: semver dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- evm_loader/rpc/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 7b3f6ff03..1d48d4a39 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -4643,9 +4643,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" dependencies = [ "serde", ] diff --git a/evm_loader/rpc/Cargo.toml b/evm_loader/rpc/Cargo.toml index aa6a64581..8670468de 100644 --- a/evm_loader/rpc/Cargo.toml +++ b/evm_loader/rpc/Cargo.toml @@ -11,7 +11,7 @@ clap = "2.33.3" jsonrpc-v2 = "0.13.0" neon-lib-interface = { path = "../lib-interface" } neon-lib = { path = "../lib" } -semver = "1.0.18" +semver = "1.0.23" serde = "1.0.188" serde_json = "1.0.115" tokio = { version = "1", features = ["full"] } From 8ecd2200911c365074cdb07f2fefa7139ad04232 Mon Sep 17 00:00:00 2001 From: sergei poletaev Date: Mon, 13 May 2024 18:22:59 +0300 Subject: [PATCH 182/318] Enable cargo test for evm_loader --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 66594c001..fe30d7f1d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,6 +19,7 @@ ENV NEON_REVISION=${REVISION} RUN cargo fmt --check && \ cargo clippy --release && \ cargo build --release && \ + cargo test && \ cargo build-bpf --manifest-path program/Cargo.toml --features devnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-devnet.so && \ cargo build-bpf --manifest-path program/Cargo.toml --features testnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-testnet.so && \ cargo build-bpf --manifest-path program/Cargo.toml --features govertest && cp target/deploy/evm_loader.so target/deploy/evm_loader-govertest.so && \ From 448ea067d3053a483320850d10b5ab0eefcda252 Mon Sep 17 00:00:00 2001 From: sergei poletaev Date: Mon, 13 May 2024 20:54:44 +0300 Subject: [PATCH 183/318] Run tests in release mode --- Dockerfile | 2 +- evm_loader/program/Cargo.toml | 3 +++ evm_loader/program/src/evm/buffer.rs | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index fe30d7f1d..62716af14 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,7 +19,7 @@ ENV NEON_REVISION=${REVISION} RUN cargo fmt --check && \ cargo clippy --release && \ cargo build --release && \ - cargo test && \ + cargo test --release && \ cargo build-bpf --manifest-path program/Cargo.toml --features devnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-devnet.so && \ cargo build-bpf --manifest-path program/Cargo.toml --features testnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-testnet.so && \ cargo build-bpf --manifest-path program/Cargo.toml --features govertest && cp target/deploy/evm_loader.so target/deploy/evm_loader-govertest.so && \ diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 59329254b..c58acf84a 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -72,3 +72,6 @@ crate-type = ["cdylib", "lib"] [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] + +[profile.test] +debug = true diff --git a/evm_loader/program/src/evm/buffer.rs b/evm_loader/program/src/evm/buffer.rs index 23f5a2e7a..2eb4169c9 100644 --- a/evm_loader/program/src/evm/buffer.rs +++ b/evm_loader/program/src/evm/buffer.rs @@ -300,6 +300,7 @@ mod tests { } #[test] + #[cfg(debug_assertions)] #[should_panic(expected = "assertion failed: !self.ptr.is_null()")] fn test_deref_account_uninit() { let _: &[u8] = &Buffer::new(Inner::AccountUninit { From 865e2f468e2e6f8d8ecddfb9861518c30d4706eb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 May 2024 13:38:27 +0300 Subject: [PATCH 184/318] Bump async-trait from 0.1.79 to 0.1.80 in /evm_loader (#414) Bumps [async-trait](https://github.com/dtolnay/async-trait) from 0.1.79 to 0.1.80. - [Release notes](https://github.com/dtolnay/async-trait/releases) - [Commits](https://github.com/dtolnay/async-trait/compare/0.1.79...0.1.80) --- updated-dependencies: - dependency-name: async-trait dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- evm_loader/lib/Cargo.toml | 2 +- evm_loader/program/Cargo.toml | 2 +- evm_loader/rpc-client/Cargo.toml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 1d48d4a39..692f12b9e 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -622,9 +622,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.79" +version = "0.1.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" +checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 1b61f02d4..19acef3f9 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -33,7 +33,7 @@ scroll = "0.11.0" tokio = { version = "1", features = ["full"] } clickhouse = "0.11.6" tracing = "0.1" -async-trait = "0.1.79" +async-trait = "0.1.80" build-info = { version = "0.0.31", features = ["serde"] } enum_dispatch = "0.3.13" web3 = "0.19.0" diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index c58acf84a..a8a6d6ac6 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -55,7 +55,7 @@ ethnum = { version = "1.5", default-features = false, features = ["serde"] } cfg-if = { version = "1.0" } log = { version = "0.4", default-features = false, optional = true } maybe-async = "0.2.10" -async-trait = { version = "0.1.79", optional = true } +async-trait = { version = "0.1.80", optional = true } [target.'cfg(target_os = "solana")'.dependencies.maybe-async] version = "0.2.7" diff --git a/evm_loader/rpc-client/Cargo.toml b/evm_loader/rpc-client/Cargo.toml index 5a2e5f318..437a08f36 100644 --- a/evm_loader/rpc-client/Cargo.toml +++ b/evm_loader/rpc-client/Cargo.toml @@ -10,7 +10,7 @@ serde = "1.0.189" serde_json = "1.0.115" neon-lib = { path = "../lib" } thiserror = "1.0.58" -async-trait = "0.1.79" +async-trait = "0.1.80" jsonrpsee-core = "0.22.3" jsonrpsee-http-client = "0.22.3" jsonrpsee-types = "0.22.3" From d5df47e0e171c2a52f328a2e521508a43c6b4d9b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 May 2024 15:40:32 +0300 Subject: [PATCH 185/318] Bump serde from 1.0.197 to 1.0.201 in /evm_loader (#416) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.197 to 1.0.201. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.197...v1.0.201) --- updated-dependencies: - dependency-name: serde dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 8 ++++---- evm_loader/api/Cargo.toml | 2 +- evm_loader/cli/Cargo.toml | 2 +- evm_loader/lib-interface/Cargo.toml | 2 +- evm_loader/program/Cargo.toml | 2 +- evm_loader/rpc-client/Cargo.toml | 2 +- evm_loader/rpc/Cargo.toml | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 692f12b9e..90d59d593 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -4652,9 +4652,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.197" +version = "1.0.201" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" dependencies = [ "serde_derive", ] @@ -4670,9 +4670,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.201" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" dependencies = [ "proc-macro2", "quote", diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 10f053491..d7e7bf3c8 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -10,7 +10,7 @@ clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } solana-sdk.workspace = true solana-client.workspace = true -serde = "1.0.186" +serde = "1.0.201" serde_json = { version = "1.0.115", features = ["preserve_order"] } ethnum = { version = "1.5", default-features = false, features = ["serde"] } tokio = { version = "1", features = ["full"] } diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index e146ca0ca..abb2cf256 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -13,7 +13,7 @@ solana-client.workspace = true solana-clap-utils.workspace = true solana-cli-config.workspace = true hex = "0.4.2" -serde = "1.0.186" +serde = "1.0.201" serde_json = { version = "1.0.115", features = ["preserve_order"] } log = "0.4.21" fern = "0.6" diff --git a/evm_loader/lib-interface/Cargo.toml b/evm_loader/lib-interface/Cargo.toml index 9684f5d38..25b2f2866 100644 --- a/evm_loader/lib-interface/Cargo.toml +++ b/evm_loader/lib-interface/Cargo.toml @@ -9,5 +9,5 @@ edition = "2021" abi_stable = "0.11.1" thiserror = "1" async-ffi = { version = "0.5.0", features = ["abi_stable"] } -serde = "1.0.147" +serde = "1.0.201" serde_json = "1.0.115" diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index a8a6d6ac6..3faab3a24 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -50,7 +50,7 @@ static_assertions = "1" borsh = "0.10" bincode = "1" serde_bytes = "0.11.14" -serde = { version = "1.0.186", default-features = false, features = ["derive", "rc"] } +serde = { version = "1.0.201", default-features = false, features = ["derive", "rc"] } ethnum = { version = "1.5", default-features = false, features = ["serde"] } cfg-if = { version = "1.0" } log = { version = "0.4", default-features = false, optional = true } diff --git a/evm_loader/rpc-client/Cargo.toml b/evm_loader/rpc-client/Cargo.toml index 437a08f36..eef1e13e9 100644 --- a/evm_loader/rpc-client/Cargo.toml +++ b/evm_loader/rpc-client/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -serde = "1.0.189" +serde = "1.0.201" serde_json = "1.0.115" neon-lib = { path = "../lib" } thiserror = "1.0.58" diff --git a/evm_loader/rpc/Cargo.toml b/evm_loader/rpc/Cargo.toml index 8670468de..35f39dd6c 100644 --- a/evm_loader/rpc/Cargo.toml +++ b/evm_loader/rpc/Cargo.toml @@ -12,7 +12,7 @@ jsonrpc-v2 = "0.13.0" neon-lib-interface = { path = "../lib-interface" } neon-lib = { path = "../lib" } semver = "1.0.23" -serde = "1.0.188" +serde = "1.0.201" serde_json = "1.0.115" tokio = { version = "1", features = ["full"] } build-info = { version = "0.0.31", features = ["serde"] } From 923b647c34984260841a7487e98cbcef336f9f14 Mon Sep 17 00:00:00 2001 From: sergei poletaev Date: Wed, 8 May 2024 14:35:51 +0300 Subject: [PATCH 186/318] Apply nonce from state_overrides --- evm_loader/lib/src/account_storage.rs | 27 +++++++++++++++++++ .../program/src/account/ether_balance.rs | 6 +++++ 2 files changed, 33 insertions(+) diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index 53460e74c..9df6a154f 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -289,6 +289,29 @@ impl<'rpc, T: Rpc + BuildConfigSimulator> EmulatorAccountStorage<'rpc, T> { } impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { + async fn apply_state_overrides(&self, state_overrides: &AccountOverrides) -> NeonResult<()> { + for (address, overrides) in state_overrides.into_iter() { + if let Some(nonce) = overrides.nonce { + let target_chain_id = self + .contract_chain_id(*address) + .await + .unwrap_or(self.default_chain_id()); + let mut balance_data = self + .get_balance_account(*address, target_chain_id) + .await? + .borrow_mut(); + let mut balance = self.get_or_create_ethereum_balance( + &mut balance_data, + *address, + target_chain_id, + )?; + info!("apply_state_overrides {address} -> {nonce}"); + balance.override_nonce_by(nonce); + } + } + Ok(()) + } + async fn download_accounts(&self, pubkeys: &[Pubkey]) -> Result<(), NeonError> { let accounts = self.rpc.get_multiple_accounts(pubkeys).await?; @@ -296,6 +319,10 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { self.accounts_cache.insert(*key, Box::new(account)); } + if let Some(overrides) = &self._state_overrides { + self.apply_state_overrides(&overrides).await?; + } + Ok(()) } diff --git a/evm_loader/program/src/account/ether_balance.rs b/evm_loader/program/src/account/ether_balance.rs index e59f01700..4018ab461 100644 --- a/evm_loader/program/src/account/ether_balance.rs +++ b/evm_loader/program/src/account/ether_balance.rs @@ -146,6 +146,12 @@ impl<'a> BalanceAccount<'a> { header.trx_count } + pub fn override_nonce_by(&mut self, value: u64) { + let mut header = super::header_mut::
(&self.account); + + header.trx_count = value; + } + #[must_use] pub fn exists(&self) -> bool { let header = super::header::
(&self.account); From a5e14fb4ea0f673cc7955db9e21c39d9817e33a3 Mon Sep 17 00:00:00 2001 From: sergei poletaev Date: Wed, 8 May 2024 17:42:42 +0300 Subject: [PATCH 187/318] Take chain id from TxParams --- evm_loader/lib/src/account_storage.rs | 47 +++++++++++--------------- evm_loader/lib/src/commands/emulate.rs | 1 + 2 files changed, 20 insertions(+), 28 deletions(-) diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index 9df6a154f..553d556a7 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -271,6 +271,7 @@ impl<'rpc, T: Rpc + BuildConfigSimulator> EmulatorAccountStorage<'rpc, T> { block_overrides: Option, state_overrides: Option, solana_overrides: Option, + tx_chain_id: Option, ) -> Result, NeonError> { let storage = Self::new( rpc, @@ -283,30 +284,30 @@ impl<'rpc, T: Rpc + BuildConfigSimulator> EmulatorAccountStorage<'rpc, T> { .await?; storage.download_accounts(accounts).await?; + storage.apply_overrides(tx_chain_id).await?; Ok(storage) } } impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { - async fn apply_state_overrides(&self, state_overrides: &AccountOverrides) -> NeonResult<()> { - for (address, overrides) in state_overrides.into_iter() { - if let Some(nonce) = overrides.nonce { - let target_chain_id = self - .contract_chain_id(*address) - .await - .unwrap_or(self.default_chain_id()); - let mut balance_data = self - .get_balance_account(*address, target_chain_id) - .await? - .borrow_mut(); - let mut balance = self.get_or_create_ethereum_balance( - &mut balance_data, - *address, - target_chain_id, - )?; - info!("apply_state_overrides {address} -> {nonce}"); - balance.override_nonce_by(nonce); + async fn apply_overrides(&self, tx_chain_id: Option) -> NeonResult<()> { + if let Some(state_overrides) = self._state_overrides.as_ref() { + for (address, overrides) in state_overrides.into_iter() { + if let Some(nonce) = overrides.nonce { + let target_chain_id = tx_chain_id.unwrap_or(self.default_chain_id()); + let mut balance_data = self + .get_balance_account(*address, target_chain_id) + .await? + .borrow_mut(); + let mut balance = self.get_or_create_ethereum_balance( + &mut balance_data, + *address, + target_chain_id, + )?; + info!("apply nonce overrides {address} -> {nonce}"); + balance.override_nonce_by(nonce); + } } } Ok(()) @@ -319,10 +320,6 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { self.accounts_cache.insert(*key, Box::new(account)); } - if let Some(overrides) = &self._state_overrides { - self.apply_state_overrides(&overrides).await?; - } - Ok(()) } @@ -957,12 +954,6 @@ impl AccountStorage for EmulatorAccountStorage<'_, T> { async fn nonce(&self, address: Address, chain_id: u64) -> u64 { info!("nonce {address} {chain_id}"); - // TODO: move to reading data from Solana node - // let nonce_override = self.account_override(address, |a| a.nonce); - // if let Some(nonce_override) = nonce_override { - // return nonce_override; - // } - self.ethereum_balance_map_or(address, chain_id, u64::default(), |account| account.nonce()) .await .unwrap() diff --git a/evm_loader/lib/src/commands/emulate.rs b/evm_loader/lib/src/commands/emulate.rs index 719b11df3..bcbd78aec 100644 --- a/evm_loader/lib/src/commands/emulate.rs +++ b/evm_loader/lib/src/commands/emulate.rs @@ -92,6 +92,7 @@ pub async fn execute( block_overrides, state_overrides, solana_overrides, + emulate_request.tx.chain_id.clone(), ) .await?; From c8e6793ed2ae9d70d866d3d14345bd1ae9866d97 Mon Sep 17 00:00:00 2001 From: sergei poletaev Date: Wed, 8 May 2024 17:48:43 +0300 Subject: [PATCH 188/318] Apply balance override --- evm_loader/lib/src/account_storage.rs | 33 +++++++++++-------- .../program/src/account/ether_balance.rs | 6 +++- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index 553d556a7..98aafd767 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -284,30 +284,37 @@ impl<'rpc, T: Rpc + BuildConfigSimulator> EmulatorAccountStorage<'rpc, T> { .await?; storage.download_accounts(accounts).await?; - storage.apply_overrides(tx_chain_id).await?; + let target_chain_id = tx_chain_id.unwrap_or(storage.default_chain_id()); + storage.apply_balance_overrides(target_chain_id).await?; Ok(storage) } } impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { - async fn apply_overrides(&self, tx_chain_id: Option) -> NeonResult<()> { - if let Some(state_overrides) = self._state_overrides.as_ref() { + async fn apply_balance_overrides(&self, target_chain_id: u64) -> NeonResult<()> { + if let Some(state_overrides) = self.state_overrides.as_ref() { for (address, overrides) in state_overrides.into_iter() { + if overrides.nonce.is_none() && overrides.balance.is_none() { + continue; + } + let mut balance_data = self + .get_balance_account(*address, target_chain_id) + .await? + .borrow_mut(); + let mut balance = self.get_or_create_ethereum_balance( + &mut balance_data, + *address, + target_chain_id, + )?; if let Some(nonce) = overrides.nonce { - let target_chain_id = tx_chain_id.unwrap_or(self.default_chain_id()); - let mut balance_data = self - .get_balance_account(*address, target_chain_id) - .await? - .borrow_mut(); - let mut balance = self.get_or_create_ethereum_balance( - &mut balance_data, - *address, - target_chain_id, - )?; info!("apply nonce overrides {address} -> {nonce}"); balance.override_nonce_by(nonce); } + if let Some(expected_balance) = overrides.balance { + info!("apply balance overrides {address} -> {expected_balance}"); + balance.override_balance_by(expected_balance); + } } } Ok(()) diff --git a/evm_loader/program/src/account/ether_balance.rs b/evm_loader/program/src/account/ether_balance.rs index 4018ab461..400e052e9 100644 --- a/evm_loader/program/src/account/ether_balance.rs +++ b/evm_loader/program/src/account/ether_balance.rs @@ -148,10 +148,14 @@ impl<'a> BalanceAccount<'a> { pub fn override_nonce_by(&mut self, value: u64) { let mut header = super::header_mut::
(&self.account); - header.trx_count = value; } + pub fn override_balance_by(&mut self, value: U256) { + let mut header = super::header_mut::
(&self.account); + header.balance = value; + } + #[must_use] pub fn exists(&self) -> bool { let header = super::header::
(&self.account); From e738474e1e010d04cfb1eb7e2f013e0ad754adf9 Mon Sep 17 00:00:00 2001 From: sergei poletaev Date: Wed, 8 May 2024 18:25:20 +0300 Subject: [PATCH 189/318] Move account storage tests to a separate file --- evm_loader/lib/src/account_storage.rs | 1598 +------------------ evm_loader/lib/src/account_storage_tests.rs | 1581 ++++++++++++++++++ 2 files changed, 1583 insertions(+), 1596 deletions(-) create mode 100644 evm_loader/lib/src/account_storage_tests.rs diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index 98aafd767..062ac2f07 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -1415,1599 +1415,5 @@ pub fn account_info<'a>(key: &'a Pubkey, account: &'a mut Account) -> AccountInf } #[cfg(test)] -mod tests { - use super::*; - use crate::tracing::AccountOverride; - use hex_literal::hex; - use std::collections::HashMap; - use std::str::FromStr; - - mod mock_rpc_client { - use crate::commands::get_config::BuildConfigSimulator; - use crate::NeonResult; - use crate::{commands::get_config::ConfigSimulator, rpc::Rpc}; - use async_trait::async_trait; - use solana_client::client_error::Result as ClientResult; - use solana_client::rpc_response::{Response, RpcResponseContext, RpcResult}; - use solana_sdk::account::Account; - use solana_sdk::clock::{Slot, UnixTimestamp}; - use solana_sdk::commitment_config::CommitmentConfig; - use solana_sdk::pubkey::Pubkey; - use std::collections::HashMap; - - pub struct MockRpcClient { - accounts: HashMap, - } - - impl MockRpcClient { - pub fn new(accounts: &[(Pubkey, Account)]) -> Self { - Self { - accounts: accounts.iter().cloned().collect(), - } - } - } - - #[async_trait(?Send)] - impl Rpc for MockRpcClient { - async fn get_account(&self, key: &Pubkey) -> RpcResult> { - let result = self.accounts.get(key).cloned(); - Ok(Response { - context: RpcResponseContext { - slot: 0, - api_version: None, - }, - value: result, - }) - } - - async fn get_account_with_commitment( - &self, - key: &Pubkey, - _commitment: CommitmentConfig, - ) -> RpcResult> { - self.get_account(key).await - } - - async fn get_multiple_accounts( - &self, - pubkeys: &[Pubkey], - ) -> ClientResult>> { - let result = pubkeys - .iter() - .map(|key| self.accounts.get(key).cloned()) - .collect::>(); - Ok(result) - } - - async fn get_block_time(&self, _slot: Slot) -> ClientResult { - Ok(UnixTimestamp::default()) - } - - async fn get_slot(&self) -> ClientResult { - Ok(Slot::default()) - } - } - - #[async_trait(?Send)] - impl BuildConfigSimulator for MockRpcClient { - async fn build_config_simulator( - &self, - _program_id: Pubkey, - ) -> NeonResult { - unimplemented!(); - } - } - } - - fn create_legacy_ether_contract( - program_id: &Pubkey, - rent: &Rent, - address: Address, - balance: U256, - trx_count: u64, - generation: u32, - code: &[u8], - storage: &[[u8; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT], - ) -> Account { - let data_length = if (code.len() > 0) || (generation > 0) { - 1 + LegacyEtherData::SIZE + 32 * STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT + code.len() - } else { - 1 + LegacyEtherData::SIZE - }; - let mut data = vec![0u8; data_length]; - - let data_ref = arrayref::array_mut_ref![data, 0, 1 + LegacyEtherData::SIZE]; - let ( - tag_ptr, - address_ptr, - bump_seed_ptr, - trx_count_ptr, - balance_ptr, - generation_ptr, - code_size_ptr, - rw_blocked_ptr, - ) = arrayref::mut_array_refs![data_ref, 1, 20, 1, 8, 32, 4, 4, 1]; - - *tag_ptr = LegacyEtherData::TAG.to_le_bytes(); - *address_ptr = *address.as_bytes(); - *bump_seed_ptr = 0u8.to_le_bytes(); - *trx_count_ptr = trx_count.to_le_bytes(); - *balance_ptr = balance.to_le_bytes(); - *generation_ptr = generation.to_le_bytes(); - *code_size_ptr = (code.len() as u32).to_le_bytes(); - *rw_blocked_ptr = 0u8.to_le_bytes(); - - if (generation > 0) || (code.len() > 0) { - let storage_offset = 1 + LegacyEtherData::SIZE; - const STORAGE_LENGTH: usize = 32 * STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT; - let storage_ptr = &mut data[storage_offset..][..STORAGE_LENGTH]; - let storage_source = unsafe { - let ptr: *const u8 = storage.as_ptr().cast(); - std::slice::from_raw_parts(ptr, 32 * STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT) - }; - storage_ptr.copy_from_slice(storage_source); - - let code_offset = storage_offset + STORAGE_LENGTH; - let code_ptr = &mut data[code_offset..][..code.len()]; - code_ptr.copy_from_slice(code); - } - - Account { - lamports: rent.minimum_balance(data.len()), - data: data, - owner: *program_id, - executable: false, - rent_epoch: 0, - } - } - - fn create_legacy_ether_account( - program_id: &Pubkey, - rent: &Rent, - address: Address, - balance: U256, - trx_count: u64, - ) -> Account { - let storage = [[0u8; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT]; - create_legacy_ether_contract( - program_id, - rent, - address, - balance, - trx_count, - 0u32, - &[], - &storage, - ) - } - - struct ActualStorage { - index: U256, - values: &'static [(u8, [u8; 32])], - } - - struct LegacyStorage { - generation: u32, - index: U256, - values: &'static [(u8, [u8; 32])], - } - - impl ActualStorage { - pub fn account_with_pubkey( - &self, - program_id: &Pubkey, - rent: &Rent, - address: Address, - ) -> (Pubkey, Account) { - let (contract, _) = address.find_solana_address(program_id); - let cell_address = StorageCellAddress::new(program_id, &contract, &self.index); - let cell_pubkey = *cell_address.pubkey(); - let mut account_data = AccountData::new(cell_pubkey); - account_data.assign(*program_id).unwrap(); - account_data.expand(StorageCell::required_account_size(self.values.len())); - account_data.lamports = rent.minimum_balance(account_data.get_length()); - let mut storage = - StorageCell::initialize(account_data.into_account_info(), program_id).unwrap(); - for (cell, (index, value)) in storage.cells_mut().iter_mut().zip(self.values.iter()) { - cell.subindex = *index; - cell.value.copy_from_slice(value); - } - ( - cell_pubkey, - Account { - lamports: rent.minimum_balance(account_data.get_length()), - data: account_data.data().to_vec(), - owner: *program_id, - executable: false, - rent_epoch: 0, - }, - ) - } - } - - impl LegacyStorage { - pub fn required_account_size(count: usize) -> usize { - 1 + LegacyStorageData::SIZE + std::mem::size_of::<(u8, [u8; 32])>() * count - } - pub fn account_with_pubkey( - &self, - program_id: &Pubkey, - rent: &Rent, - address: Address, - ) -> (Pubkey, Account) { - let (contract, _) = address.find_solana_address(program_id); - let cell_address = StorageCellAddress::new(program_id, &contract, &self.index); - let cell_pubkey = *cell_address.pubkey(); - let mut data = vec![0u8; Self::required_account_size(self.values.len())]; - - let data_ref = arrayref::array_mut_ref![data, 0, 1 + LegacyStorageData::SIZE]; - let (tag_ptr, address_ptr, generation_ptr, index_ptr) = - arrayref::mut_array_refs![data_ref, 1, 20, 4, 32]; - - *tag_ptr = LegacyStorageData::TAG.to_le_bytes(); - *address_ptr = *address.as_bytes(); - *generation_ptr = self.generation.to_le_bytes(); - *index_ptr = self.index.to_le_bytes(); - - let storage = unsafe { - let data = &mut data[1 + LegacyStorageData::SIZE..]; - let ptr = data.as_mut_ptr().cast::<(u8, [u8; 32])>(); - std::slice::from_raw_parts_mut(ptr, self.values.len()) - }; - storage.copy_from_slice(self.values); - - let account = Account { - lamports: rent.minimum_balance(data.len()), - data: data, - owner: *program_id, - executable: false, - rent_epoch: 0, - }; - - (cell_pubkey, account) - } - } - - struct LegacyAccount { - pub address: Address, - pub balance: U256, - pub nonce: u64, - } - - impl LegacyAccount { - pub fn account_with_pubkey(&self, program_id: &Pubkey, rent: &Rent) -> (Pubkey, Account) { - ( - self.address.find_solana_address(&program_id).0, - create_legacy_ether_account( - &program_id, - &rent, - self.address, - self.balance, - self.nonce, - ), - ) - } - } - struct LegacyContract { - pub address: Address, - pub balance: U256, - pub nonce: u64, - pub generation: u32, - pub code: &'static [u8], - pub storage: [[u8; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT], - - pub legacy_storage: LegacyStorage, - pub outdate_storage: LegacyStorage, - } - - impl LegacyContract { - fn account_with_pubkey(&self, program_id: &Pubkey, rent: &Rent) -> (Pubkey, Account) { - ( - self.address.find_solana_address(&program_id).0, - create_legacy_ether_contract( - &program_id, - &rent, - self.address, - self.balance, - self.nonce, - self.generation, - &self.code, - &self.storage, - ), - ) - } - - pub fn legacy_storage_with_pubkey( - &self, - program_id: &Pubkey, - rent: &Rent, - ) -> (Pubkey, Account) { - self.legacy_storage - .account_with_pubkey(program_id, rent, self.address) - } - - pub fn outdate_storage_with_pubkey( - &self, - program_id: &Pubkey, - rent: &Rent, - ) -> (Pubkey, Account) { - self.outdate_storage - .account_with_pubkey(program_id, rent, self.address) - } - } - - struct ActualBalance { - pub address: Address, - pub chain_id: u64, - pub balance: U256, - pub nonce: u64, - } - - impl ActualBalance { - pub fn account_with_pubkey(&self, program_id: &Pubkey, rent: &Rent) -> (Pubkey, Account) { - let (pubkey, _) = self - .address - .find_balance_address(&program_id, self.chain_id); - let mut account_data = AccountData::new(pubkey); - account_data.assign(*program_id).unwrap(); - account_data.expand(BalanceAccount::required_account_size()); - account_data.lamports = rent.minimum_balance(account_data.get_length()); - - let mut balance = BalanceAccount::initialize( - account_data.into_account_info(), - program_id, - self.address, - self.chain_id, - ) - .unwrap(); - balance.mint(self.balance).unwrap(); - balance.increment_nonce_by(self.nonce).unwrap(); - - ( - pubkey, - Account { - lamports: rent.minimum_balance(account_data.get_length()), - data: account_data.data().to_vec(), - owner: *program_id, - executable: false, - rent_epoch: 0, - }, - ) - } - } - - struct ActualContract { - pub address: Address, - pub chain_id: u64, - pub generation: u32, - pub code: &'static [u8], - pub storage: [[u8; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT], - - pub actual_storage: ActualStorage, - pub legacy_storage: LegacyStorage, - pub outdate_storage: LegacyStorage, - } - - impl ActualContract { - pub fn account_with_pubkey(&self, program_id: &Pubkey, rent: &Rent) -> (Pubkey, Account) { - let (pubkey, _) = self.address.find_solana_address(&program_id); - let mut account_data = AccountData::new(pubkey); - account_data.assign(*program_id).unwrap(); - account_data.expand(ContractAccount::required_account_size(self.code)); - account_data.lamports = rent.minimum_balance(account_data.get_length()); - - let mut contract = ContractAccount::initialize( - account_data.into_account_info(), - program_id, - self.address, - self.chain_id, - self.generation, - self.code, - ) - .unwrap(); - contract.set_storage_multiple_values(0, &self.storage); - - ( - pubkey, - Account { - lamports: rent.minimum_balance(account_data.get_length()), - data: account_data.data().to_vec(), - owner: *program_id, - executable: false, - rent_epoch: 0, - }, - ) - } - - pub fn actual_storage_with_pubkey( - &self, - program_id: &Pubkey, - rent: &Rent, - ) -> (Pubkey, Account) { - self.actual_storage - .account_with_pubkey(program_id, rent, self.address) - } - - pub fn legacy_storage_with_pubkey( - &self, - program_id: &Pubkey, - rent: &Rent, - ) -> (Pubkey, Account) { - self.legacy_storage - .account_with_pubkey(program_id, rent, self.address) - } - - pub fn outdate_storage_with_pubkey( - &self, - program_id: &Pubkey, - rent: &Rent, - ) -> (Pubkey, Account) { - self.outdate_storage - .account_with_pubkey(program_id, rent, self.address) - } - } - - const LEGACY_CHAIN_ID: u64 = 1; - const EXTRA_CHAIN_ID: u64 = 2; - const MISSING_ADDRESS: Address = Address(hex!("7a250d5630b4cf539739df2c5dacb4c659f24800")); - - const MISSING_STORAGE_INDEX: U256 = U256::new(1 * 256u128); - const ACTUAL_STORAGE_INDEX: U256 = U256::new(2 * 256u128); - const LEGACY_STORAGE_INDEX: U256 = U256::new(3 * 256u128); - const OUTDATE_STORAGE_INDEX: U256 = U256::new(4 * 256u128); - - const ACTUAL_BALANCE: ActualBalance = ActualBalance { - address: Address(hex!("7a250d5630b4cf539739df2c5dacb4c659f24810")), - chain_id: LEGACY_CHAIN_ID, - balance: U256::new(1513), - nonce: 41, - }; - - const ACTUAL_BALANCE2: ActualBalance = ActualBalance { - address: Address(hex!("7a250d5630b4cf539739df2c5dacb4c659f24811")), - chain_id: EXTRA_CHAIN_ID, - balance: U256::new(5134), - nonce: 14, - }; - - const ACTUAL_CONTRACT: ActualContract = ActualContract { - address: Address(hex!("7a250d5630b4cf539739df2c5dacb4c659f24c11")), - chain_id: LEGACY_CHAIN_ID, - generation: 4, - code: &[0x03, 0x04, 0x05], - storage: [[14u8; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT], - actual_storage: ActualStorage { - index: ACTUAL_STORAGE_INDEX, - values: &[(0u8, [64u8; 32])], - }, - legacy_storage: LegacyStorage { - generation: 4, - index: LEGACY_STORAGE_INDEX, - values: &[(0u8, [54u8; 32])], - }, - outdate_storage: LegacyStorage { - generation: 3, - index: OUTDATE_STORAGE_INDEX, - values: &[(0u8, [34u8; 32])], - }, - }; - - const ACTUAL_SUICIDE: ActualContract = ActualContract { - address: Address(hex!("7a250d5630b4cf539739df2c5dacb4c659f24d10")), - chain_id: LEGACY_CHAIN_ID, - generation: 12, - code: &[], - storage: [[0u8; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT], // It's matter that suicide contract doesn't contains any values in storage! - actual_storage: ActualStorage { - index: U256::ZERO, - values: &[], - }, - legacy_storage: LegacyStorage { - generation: 0, - index: U256::ZERO, - values: &[], - }, - outdate_storage: LegacyStorage { - generation: 11, - index: LEGACY_STORAGE_INDEX, - values: &[(0u8, [13u8; 32])], - }, - }; - - const LEGACY_ACCOUNT: LegacyAccount = LegacyAccount { - address: Address(hex!("7a250d5630b4cf539739df2c5dacb4c659f24820")), - balance: U256::new(10234), - nonce: 123, - }; - - const LEGACY_CONTRACT: LegacyContract = LegacyContract { - address: Address(hex!("7a250d5630b4cf539739df2c5dacb4c659f24c21")), - balance: U256::new(6153), - nonce: 1, - generation: 3, - code: &[0x01, 0x02, 0x03], - storage: [[0u8; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT], - - legacy_storage: LegacyStorage { - generation: 3, - index: LEGACY_STORAGE_INDEX, - values: &[(0u8, [23u8; 32])], - }, - outdate_storage: LegacyStorage { - generation: 2, - index: OUTDATE_STORAGE_INDEX, - values: &[(0u8, [43u8; 32])], - }, - }; - - const LEGACY_CONTRACT_NO_BALANCE: LegacyContract = LegacyContract { - address: Address(hex!("7a250d5630b4cf539739df2c5dacb4c659f24c20")), - balance: U256::ZERO, - nonce: 0, - generation: 2, - code: &[0x01, 0x02, 0x03, 0x04], - storage: [[53u8; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT], - legacy_storage: LegacyStorage { - generation: 0, - index: U256::ZERO, - values: &[], - }, - outdate_storage: LegacyStorage { - generation: 1, - index: U256::ZERO, - values: &[], - }, - }; - - const LEGACY_SUICIDE: LegacyContract = LegacyContract { - address: Address(hex!("7a250d5630b4cf539739df2c5dacb4c659f24d21")), - balance: U256::new(41234), - nonce: 413, - generation: 5, - code: &[], - storage: [[42u8; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT], - - legacy_storage: LegacyStorage { - generation: 413, - index: LEGACY_STORAGE_INDEX, - values: &[(0u8, [65u8; 32])], - }, - outdate_storage: LegacyStorage { - generation: 412, - index: OUTDATE_STORAGE_INDEX, - values: &[(0u8, [76u8; 32])], - }, - }; - - struct Fixture { - program_id: Pubkey, - chains: Vec, - rent: Rent, - mock_rpc: mock_rpc_client::MockRpcClient, - block_overrides: Option, - state_overrides: Option>, - solana_overrides: Option, - } - - impl Fixture { - pub async fn new() -> Self { - let rent = Rent::default(); - let program_id = - Pubkey::from_str("53DfF883gyixYNXnM7s5xhdeyV8mVk9T4i2hGV9vG9io").unwrap(); - let accounts = vec![ - ( - Pubkey::from_str("SysvarRent111111111111111111111111111111111").unwrap(), - Account { - lamports: 1009200, - data: bincode::serialize(&rent).unwrap(), - owner: Pubkey::from_str("Sysvar1111111111111111111111111111111111111") - .unwrap(), - executable: false, - rent_epoch: 0, - }, - ), - ACTUAL_BALANCE.account_with_pubkey(&program_id, &rent), - ACTUAL_BALANCE2.account_with_pubkey(&program_id, &rent), - LEGACY_ACCOUNT.account_with_pubkey(&program_id, &rent), - ACTUAL_CONTRACT.account_with_pubkey(&program_id, &rent), - ACTUAL_CONTRACT.actual_storage_with_pubkey(&program_id, &rent), - ACTUAL_CONTRACT.legacy_storage_with_pubkey(&program_id, &rent), - ACTUAL_CONTRACT.outdate_storage_with_pubkey(&program_id, &rent), - ACTUAL_SUICIDE.account_with_pubkey(&program_id, &rent), - ACTUAL_SUICIDE.outdate_storage_with_pubkey(&program_id, &rent), - LEGACY_CONTRACT.account_with_pubkey(&program_id, &rent), - LEGACY_CONTRACT.legacy_storage_with_pubkey(&program_id, &rent), - LEGACY_CONTRACT.outdate_storage_with_pubkey(&program_id, &rent), - LEGACY_CONTRACT_NO_BALANCE.account_with_pubkey(&program_id, &rent), - LEGACY_SUICIDE.account_with_pubkey(&program_id, &rent), - LEGACY_SUICIDE.outdate_storage_with_pubkey(&program_id, &rent), - ]; - - let rpc_client = mock_rpc_client::MockRpcClient::new(&accounts); - - Self { - program_id, - chains: vec![ - ChainInfo { - id: LEGACY_CHAIN_ID, - name: "neon".to_string(), - token: Pubkey::new_unique(), - }, - ChainInfo { - id: EXTRA_CHAIN_ID, - name: "usdt".to_string(), - token: Pubkey::new_unique(), - }, - ], - rent, - mock_rpc: rpc_client, - block_overrides: None, - state_overrides: None, - solana_overrides: None, - } - } - - pub async fn build_account_storage( - &self, - ) -> EmulatorAccountStorage<'_, mock_rpc_client::MockRpcClient> { - EmulatorAccountStorage::new( - &self.mock_rpc, - self.program_id, - Some(self.chains.clone()), - self.block_overrides.clone(), - self.state_overrides.clone(), - self.solana_overrides.clone(), - ) - .await - .unwrap() - } - - pub fn balance_pubkey(&self, address: Address, chain_id: u64) -> Pubkey { - address.find_balance_address(&self.program_id, chain_id).0 - } - - pub fn legacy_pubkey(&self, address: Address) -> Pubkey { - address.find_solana_address(&self.program_id).0 - } - - pub fn contract_pubkey(&self, address: Address) -> Pubkey { - address.find_solana_address(&self.program_id).0 - } - - pub fn storage_pubkey(&self, address: Address, index: U256) -> Pubkey { - if index < U256::new(STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT as u128) { - self.contract_pubkey(address) - } else { - let index = index & !U256::new(0xFF); - let base = self.contract_pubkey(address); - let cell_address = StorageCellAddress::new(&self.program_id, &base, &index); - *cell_address.pubkey() - } - } - - pub fn storage_rent(&self, count: usize) -> u64 { - self.rent - .minimum_balance(StorageCell::required_account_size(count)) - } - - pub fn legacy_storage_rent(&self, count: usize) -> u64 { - self.rent - .minimum_balance(LegacyStorage::required_account_size(count)) - } - - pub fn balance_rent(&self) -> u64 { - self.rent - .minimum_balance(BalanceAccount::required_account_size()) - } - - pub fn legacy_rent(&self, code_len: Option) -> u64 { - let data_length = code_len - .map(|len| { - 1 + LegacyEtherData::SIZE + 32 * STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT + len - }) - .unwrap_or(1 + LegacyEtherData::SIZE); - self.rent.minimum_balance(data_length) - } - - pub fn contract_rent(&self, code: &[u8]) -> u64 { - self.rent - .minimum_balance(ContractAccount::required_account_size(code)) - } - } - - impl<'rpc, T: Rpc> EmulatorAccountStorage<'rpc, T> { - pub fn verify_used_accounts(&self, expected: &[(Pubkey, bool, bool)]) { - let mut expected = expected.to_vec(); - expected.sort_by_key(|(k, _, _)| *k); - let mut actual = self - .used_accounts() - .iter() - .map(|v| (v.pubkey, v.is_writable, v.is_legacy)) - .collect::>(); - actual.sort_by_key(|(k, _, _)| *k); - assert_eq!(actual, expected); - } - - pub fn verify_upgrade_rent(&self, added_rent: u64, removed_rent: u64) { - assert_eq!( - self.get_upgrade_rent().unwrap(), - added_rent.saturating_sub(removed_rent) - ); - } - - pub fn verify_regular_rent(&self, added_rent: u64, removed_rent: u64) { - assert_eq!( - self.get_regular_rent().unwrap(), - added_rent.saturating_sub(removed_rent) - ); - } - } - - #[tokio::test] - async fn test_read_balance_missing_account() { - let fixture = Fixture::new().await; - let storage = fixture.build_account_storage().await; - - assert_eq!( - storage.balance(MISSING_ADDRESS, LEGACY_CHAIN_ID).await, - U256::ZERO - ); - assert_eq!(storage.nonce(MISSING_ADDRESS, LEGACY_CHAIN_ID).await, 0); - - storage.verify_used_accounts(&[ - ( - fixture.balance_pubkey(MISSING_ADDRESS, LEGACY_CHAIN_ID), - false, - false, - ), - (fixture.legacy_pubkey(MISSING_ADDRESS), false, false), - ]); - storage.verify_upgrade_rent(0, 0); - storage.verify_regular_rent(0, 0); - } - - #[tokio::test] - async fn test_read_balance_missing_account_extra_chain() { - let fixture = Fixture::new().await; - let storage = fixture.build_account_storage().await; - - assert_eq!( - storage.balance(MISSING_ADDRESS, EXTRA_CHAIN_ID).await, - U256::ZERO - ); - assert_eq!(storage.nonce(MISSING_ADDRESS, EXTRA_CHAIN_ID).await, 0); - - storage.verify_used_accounts(&[( - fixture.balance_pubkey(MISSING_ADDRESS, EXTRA_CHAIN_ID), - false, - false, - )]); - storage.verify_upgrade_rent(0, 0); - storage.verify_regular_rent(0, 0); - } - - #[tokio::test] - async fn test_read_balance_actual_account() { - let fixture = Fixture::new().await; - let storage = fixture.build_account_storage().await; - - let acc = &ACTUAL_BALANCE; - assert_eq!( - storage.balance(acc.address, acc.chain_id).await, - acc.balance - ); - assert_eq!(storage.nonce(acc.address, acc.chain_id).await, acc.nonce); - - storage.verify_used_accounts(&[( - fixture.balance_pubkey(acc.address, acc.chain_id), - false, - false, - )]); - storage.verify_upgrade_rent(0, 0); - storage.verify_regular_rent(0, 0); - } - - #[tokio::test] - async fn test_read_balance_actual_account_extra_chain() { - let fixture = Fixture::new().await; - let storage = fixture.build_account_storage().await; - - let acc = &ACTUAL_BALANCE2; - assert_eq!(acc.chain_id, EXTRA_CHAIN_ID); - assert_eq!( - storage.balance(acc.address, acc.chain_id).await, - acc.balance - ); - assert_eq!(storage.nonce(acc.address, acc.chain_id).await, acc.nonce); - - storage.verify_used_accounts(&[( - fixture.balance_pubkey(acc.address, acc.chain_id), - false, - false, - )]); - storage.verify_upgrade_rent(0, 0); - storage.verify_regular_rent(0, 0); - } - - #[tokio::test] - async fn test_read_balance_legacy_account() { - let fixture = Fixture::new().await; - let storage = fixture.build_account_storage().await; - - let acc = &LEGACY_ACCOUNT; - assert_eq!( - storage.balance(acc.address, LEGACY_CHAIN_ID).await, - acc.balance - ); - assert_eq!(storage.nonce(acc.address, LEGACY_CHAIN_ID).await, acc.nonce); - - storage.verify_used_accounts(&[ - ( - fixture.balance_pubkey(acc.address, LEGACY_CHAIN_ID), - true, - true, - ), - (fixture.legacy_pubkey(acc.address), true, true), - ]); - storage.verify_upgrade_rent(fixture.balance_rent(), fixture.legacy_rent(None)); - storage.verify_regular_rent(0, 0); - } - - #[tokio::test] - async fn test_modify_actual_and_missing_account() { - let fixture = Fixture::new().await; - let mut storage = fixture.build_account_storage().await; - - let from = &ACTUAL_BALANCE; - let amount = U256::new(10); - assert_eq!(from.chain_id, LEGACY_CHAIN_ID); - assert_eq!( - storage - .transfer(from.address, MISSING_ADDRESS, from.chain_id, amount) - .await - .is_ok(), - true - ); - - storage.verify_used_accounts(&[ - ( - fixture.balance_pubkey(from.address, from.chain_id), - true, - false, - ), - ( - fixture.balance_pubkey(MISSING_ADDRESS, LEGACY_CHAIN_ID), - true, - false, - ), - (fixture.legacy_pubkey(MISSING_ADDRESS), false, false), - ]); - storage.verify_upgrade_rent(0, 0); - storage.verify_regular_rent(fixture.balance_rent(), 0); - - assert_eq!( - storage.balance(from.address, from.chain_id).await, - from.balance - amount - ); - assert_eq!( - storage.balance(MISSING_ADDRESS, LEGACY_CHAIN_ID).await, - amount - ); - } - - #[tokio::test] - async fn test_modify_actual_and_missing_account_extra_chain() { - let fixture = Fixture::new().await; - let mut storage = fixture.build_account_storage().await; - - let from = &ACTUAL_BALANCE2; - let amount = U256::new(11); - assert_eq!(from.chain_id, EXTRA_CHAIN_ID); - assert_eq!( - storage - .transfer(from.address, MISSING_ADDRESS, from.chain_id, amount) - .await - .is_ok(), - true - ); - - storage.verify_used_accounts(&[ - ( - fixture.balance_pubkey(from.address, from.chain_id), - true, - false, - ), - ( - fixture.balance_pubkey(MISSING_ADDRESS, from.chain_id), - true, - false, - ), - ]); - storage.verify_upgrade_rent(0, 0); - storage.verify_regular_rent(fixture.balance_rent(), 0); - - assert_eq!( - storage.balance(from.address, from.chain_id).await, - from.balance - amount - ); - assert_eq!( - storage.balance(MISSING_ADDRESS, from.chain_id).await, - amount - ); - } - - #[tokio::test] - async fn test_modify_actual_and_legacy_account() { - let fixture = Fixture::new().await; - let mut storage = fixture.build_account_storage().await; - - let from = &ACTUAL_BALANCE; - let to = &LEGACY_ACCOUNT; - let amount = U256::new(10); - assert_eq!(from.chain_id, LEGACY_CHAIN_ID); - assert_eq!( - storage - .transfer(from.address, to.address, from.chain_id, amount) - .await - .is_ok(), - true - ); - - storage.verify_used_accounts(&[ - ( - fixture.balance_pubkey(from.address, from.chain_id), - true, - false, - ), - ( - fixture.balance_pubkey(to.address, LEGACY_CHAIN_ID), - true, - true, - ), - (fixture.legacy_pubkey(to.address), true, true), - ]); - storage.verify_upgrade_rent(fixture.balance_rent(), fixture.legacy_rent(None)); - storage.verify_regular_rent(0, 0); - - assert_eq!( - storage.balance(from.address, from.chain_id).await, - from.balance - amount - ); - assert_eq!( - storage.balance(to.address, LEGACY_CHAIN_ID).await, - to.balance + amount - ); - } - - #[tokio::test] - async fn test_read_missing_contract() { - let fixture = Fixture::new().await; - let storage = fixture.build_account_storage().await; - - assert_eq!(*storage.code(MISSING_ADDRESS).await, [0u8; 0]); - assert_eq!( - storage.storage(MISSING_ADDRESS, U256::ZERO).await, - [0u8; 32] - ); - storage.verify_used_accounts(&[(fixture.contract_pubkey(MISSING_ADDRESS), false, false)]); - storage.verify_upgrade_rent(0, 0); - storage.verify_regular_rent(0, 0); - - assert_eq!( - storage - .storage( - MISSING_ADDRESS, - U256::new(STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT as u128) - ) - .await, - [0u8; 32] - ); - } - - #[tokio::test] - async fn test_read_legacy_contract() { - let fixture = Fixture::new().await; - let storage = fixture.build_account_storage().await; - - assert_eq!( - *storage.code(LEGACY_CONTRACT.address).await, - *LEGACY_CONTRACT.code - ); - assert_eq!( - storage.storage(LEGACY_CONTRACT.address, U256::ZERO).await, - [0u8; 32] - ); - storage.verify_used_accounts(&[ - ( - fixture.balance_pubkey(LEGACY_CONTRACT.address, LEGACY_CHAIN_ID), - true, - true, - ), - (fixture.contract_pubkey(LEGACY_CONTRACT.address), true, true), - ]); - storage.verify_upgrade_rent( - fixture.balance_rent() + fixture.contract_rent(LEGACY_CONTRACT.code), - fixture.legacy_rent(Some(LEGACY_CONTRACT.code.len())), - ); - storage.verify_regular_rent(0, 0); - } - - #[tokio::test] - async fn test_read_legacy_contract_no_balance() { - let fixture = Fixture::new().await; - let storage = fixture.build_account_storage().await; - - let contract = &LEGACY_CONTRACT_NO_BALANCE; - assert_eq!(*storage.code(contract.address).await, *contract.code); - assert_eq!( - storage.storage(contract.address, U256::ZERO).await, - [53u8; 32] - ); - storage.verify_used_accounts(&[ - ( - fixture.balance_pubkey(contract.address, LEGACY_CHAIN_ID), - false, - true, - ), - (fixture.contract_pubkey(contract.address), true, true), - ]); - storage.verify_upgrade_rent( - fixture.contract_rent(contract.code), - fixture.legacy_rent(Some(contract.code.len())), - ); - storage.verify_regular_rent(0, 0); - } - - #[tokio::test] - async fn test_read_actual_suicide_contract() { - let fixture = Fixture::new().await; - let storage = fixture.build_account_storage().await; - - let contract = &ACTUAL_SUICIDE; - assert_eq!(*storage.code(contract.address).await, [0u8; 0]); - assert_eq!( - storage.storage(contract.address, U256::ZERO).await, - [0u8; 32] - ); - storage.verify_used_accounts(&[(fixture.contract_pubkey(contract.address), false, false)]); - storage.verify_upgrade_rent(0, 0); - storage.verify_regular_rent(0, 0); - } - - #[tokio::test] - async fn test_read_legacy_suicide_contract() { - let fixture = Fixture::new().await; - let storage = fixture.build_account_storage().await; - - let contract = &LEGACY_SUICIDE; - assert_eq!(*storage.code(contract.address).await, [0u8; 0]); - assert_eq!( - storage.storage(contract.address, U256::ZERO).await, - [0u8; 32] - ); - storage.verify_used_accounts(&[ - ( - fixture.balance_pubkey(contract.address, LEGACY_CHAIN_ID), - true, - true, - ), - (fixture.contract_pubkey(contract.address), true, true), - ]); - storage.verify_upgrade_rent( - fixture.balance_rent() + fixture.contract_rent(contract.code), - fixture.legacy_rent(Some(contract.code.len())), - ); - storage.verify_regular_rent(0, 0); - } - - #[tokio::test] - async fn test_deploy_at_missing_contract() { - let fixture = Fixture::new().await; - let mut storage = fixture.build_account_storage().await; - - let code = hex!("14643165").to_vec(); - assert_eq!( - storage - .set_code(MISSING_ADDRESS, LEGACY_CHAIN_ID, code.clone()) - .await - .is_ok(), - true - ); - storage.verify_used_accounts(&[(fixture.contract_pubkey(MISSING_ADDRESS), true, false)]); - storage.verify_upgrade_rent(0, 0); - storage.verify_regular_rent(fixture.contract_rent(&code), 0); - } - - #[tokio::test] - async fn test_deploy_at_actual_balance() { - let fixture = Fixture::new().await; - let mut storage = fixture.build_account_storage().await; - - let code = hex!("14643165").to_vec(); - let acc = &ACTUAL_BALANCE; - assert_eq!( - storage - .set_code(acc.address, LEGACY_CHAIN_ID, code.clone()) - .await - .is_ok(), - true - ); - storage.verify_used_accounts(&[(fixture.contract_pubkey(acc.address), true, false)]); - storage.verify_upgrade_rent(0, 0); - storage.verify_regular_rent(fixture.contract_rent(&code), 0); - } - - #[tokio::test] - async fn test_deploy_at_actual_contract() { - let fixture = Fixture::new().await; - let mut storage = fixture.build_account_storage().await; - - let code = hex!("62345987").to_vec(); - let contract = &ACTUAL_CONTRACT; - assert_eq!( - storage - .set_code(contract.address, LEGACY_CHAIN_ID, code) - .await - .unwrap_err() - .to_string(), - EvmLoaderError::AccountAlreadyInitialized(fixture.contract_pubkey(contract.address)) - .to_string() - ); - storage.verify_used_accounts(&[(fixture.contract_pubkey(contract.address), false, false)]); - storage.verify_upgrade_rent(0, 0); - storage.verify_regular_rent(0, 0); - } - - #[tokio::test] - async fn test_deploy_at_legacy_account() { - let fixture = Fixture::new().await; - let mut storage = fixture.build_account_storage().await; - - let code = hex!("37455846").to_vec(); - let contract = &LEGACY_ACCOUNT; - assert_eq!( - storage - .set_code(contract.address, LEGACY_CHAIN_ID, code.clone()) - .await - .is_ok(), - true - ); - storage.verify_used_accounts(&[ - ( - fixture.balance_pubkey(contract.address, LEGACY_CHAIN_ID), - true, - true, - ), - (fixture.contract_pubkey(contract.address), true, true), - ]); - storage.verify_upgrade_rent(fixture.balance_rent(), fixture.legacy_rent(None)); - storage.verify_regular_rent(fixture.contract_rent(&code), 0); - } - - #[tokio::test] - async fn test_deploy_at_legacy_contract() { - let fixture = Fixture::new().await; - let mut storage = fixture.build_account_storage().await; - - let code = hex!("13412971").to_vec(); - let contract = &LEGACY_CONTRACT; - assert_eq!( - storage - .set_code(contract.address, LEGACY_CHAIN_ID, code) - .await - .unwrap_err() - .to_string(), - EvmLoaderError::AccountAlreadyInitialized(fixture.contract_pubkey(contract.address)) - .to_string() - ); - storage.verify_used_accounts(&[ - ( - fixture.balance_pubkey(contract.address, LEGACY_CHAIN_ID), - true, - true, - ), - (fixture.contract_pubkey(contract.address), true, true), - ]); - storage.verify_upgrade_rent( - fixture.balance_rent() + fixture.contract_rent(contract.code), - fixture.legacy_rent(Some(contract.code.len())), - ); - storage.verify_regular_rent(0, 0); - } - - #[tokio::test] - async fn test_deploy_at_actual_suicide() { - let fixture = Fixture::new().await; - let mut storage = fixture.build_account_storage().await; - - let code = hex!("13412971").to_vec(); - let contract = &ACTUAL_SUICIDE; - // TODO: Should we deploy new contract by the previous address? - assert_eq!( - storage - .set_code(contract.address, LEGACY_CHAIN_ID, code.clone()) - .await - .is_ok(), - true, - ); - storage.verify_used_accounts(&[(fixture.contract_pubkey(contract.address), true, false)]); - storage.verify_upgrade_rent(0, 0); - storage.verify_regular_rent( - fixture.contract_rent(&code), - fixture.contract_rent(contract.code), - ); - } - - #[tokio::test] - async fn test_deploy_at_legacy_suicide() { - let fixture = Fixture::new().await; - let mut storage = fixture.build_account_storage().await; - - let code = hex!("13412971").to_vec(); - let contract = &LEGACY_SUICIDE; - // TODO: Should we deploy new contract by the previous address? - assert_eq!( - storage - .set_code(contract.address, LEGACY_CHAIN_ID, code.clone()) - .await - .is_ok(), - true, - ); - storage.verify_used_accounts(&[ - ( - fixture.balance_pubkey(contract.address, LEGACY_CHAIN_ID), - true, - true, - ), - (fixture.contract_pubkey(contract.address), true, true), - ]); - storage.verify_upgrade_rent( - fixture.balance_rent() + fixture.contract_rent(&contract.code), - fixture.legacy_rent(Some(contract.code.len())), - ); - storage.verify_regular_rent( - fixture.contract_rent(&code), - fixture.contract_rent(&contract.code), - ); - } - - #[tokio::test] - async fn test_read_missing_storage_for_missing_contract() { - let fixture = Fixture::new().await; - let storage = fixture.build_account_storage().await; - - assert_eq!( - storage - .storage(MISSING_ADDRESS, MISSING_STORAGE_INDEX) - .await, - [0u8; 32] - ); - storage.verify_used_accounts(&[( - fixture.storage_pubkey(MISSING_ADDRESS, MISSING_STORAGE_INDEX), - false, - false, - )]); - storage.verify_upgrade_rent(0, 0); - storage.verify_regular_rent(0, 0); - } - - #[tokio::test] - async fn test_read_missing_storage_for_actual_contract() { - let fixture = Fixture::new().await; - let storage = fixture.build_account_storage().await; - - let contract = &ACTUAL_CONTRACT; - assert_eq!( - storage - .storage(contract.address, MISSING_STORAGE_INDEX) - .await, - [0u8; 32] - ); - storage.verify_used_accounts(&[( - fixture.storage_pubkey(contract.address, MISSING_STORAGE_INDEX), - false, - false, - )]); - storage.verify_upgrade_rent(0, 0); - storage.verify_regular_rent(0, 0); - } - - #[tokio::test] - async fn test_read_actual_storage_for_actual_contract() { - let fixture = Fixture::new().await; - let storage = fixture.build_account_storage().await; - - let contract = &ACTUAL_CONTRACT; - assert_eq!( - storage - .storage(contract.address, ACTUAL_STORAGE_INDEX) - .await, - contract.actual_storage.values[0].1 - ); - storage.verify_used_accounts(&[( - fixture.storage_pubkey(contract.address, ACTUAL_STORAGE_INDEX), - false, - false, - )]); - storage.verify_upgrade_rent(0, 0); - storage.verify_regular_rent(0, 0); - } - - #[tokio::test] - async fn test_modify_new_storage_for_actual_contract() { - let fixture = Fixture::new().await; - let mut storage = fixture.build_account_storage().await; - - let contract = &ACTUAL_CONTRACT; - assert_eq!( - storage - .storage(contract.address, ACTUAL_STORAGE_INDEX + 1) - .await, - [0u8; 32] - ); - storage.verify_upgrade_rent(0, 0); - storage.verify_regular_rent(0, 0); - - let new_value = [0x01u8; 32]; - assert_eq!( - storage - .set_storage( - contract.address, - ACTUAL_STORAGE_INDEX + 1, - new_value.clone() - ) - .await - .is_ok(), - true - ); - assert_eq!( - storage - .storage(contract.address, ACTUAL_STORAGE_INDEX + 1) - .await, - new_value - ); - storage.verify_used_accounts(&[( - fixture.storage_pubkey(contract.address, ACTUAL_STORAGE_INDEX), - true, - false, - )]); - storage.verify_upgrade_rent(0, 0); - storage.verify_regular_rent(fixture.storage_rent(2), fixture.storage_rent(1)); - } - - #[tokio::test] - async fn test_modify_missing_storage_for_actual_contract() { - let fixture = Fixture::new().await; - let mut storage = fixture.build_account_storage().await; - - let contract = &ACTUAL_CONTRACT; - let new_value = [0x02u8; 32]; - assert_eq!( - storage - .set_storage(contract.address, MISSING_STORAGE_INDEX, new_value.clone()) - .await - .is_ok(), - true - ); - assert_eq!( - storage - .storage(contract.address, MISSING_STORAGE_INDEX) - .await, - new_value - ); - storage.verify_used_accounts(&[( - fixture.storage_pubkey(contract.address, MISSING_STORAGE_INDEX), - true, - false, - )]); - storage.verify_upgrade_rent(0, 0); - storage.verify_regular_rent(fixture.storage_rent(1), 0); - } - - #[tokio::test] - async fn test_modify_internal_storage_for_actual_contract() { - let fixture = Fixture::new().await; - let mut storage = fixture.build_account_storage().await; - - let contract = &ACTUAL_CONTRACT; - let new_value = [0x03u8; 32]; - let index = U256::new(0); - assert_eq!( - storage - .set_storage(contract.address, index, new_value.clone()) - .await - .is_ok(), - true - ); - assert_eq!(storage.storage(contract.address, index).await, new_value); - storage.verify_used_accounts(&[(fixture.contract_pubkey(contract.address), true, false)]); - storage.verify_upgrade_rent(0, 0); - storage.verify_regular_rent(0, 0); - } - - #[tokio::test] - async fn test_read_legacy_storage_for_actual_contract() { - let fixture = Fixture::new().await; - let storage = fixture.build_account_storage().await; - - let contract = &ACTUAL_CONTRACT; - assert_eq!( - storage - .storage(contract.address, LEGACY_STORAGE_INDEX) - .await, - contract.legacy_storage.values[0].1 - ); - storage.verify_used_accounts(&[ - (fixture.contract_pubkey(contract.address), false, true), - ( - fixture.storage_pubkey(contract.address, LEGACY_STORAGE_INDEX), - true, - true, - ), - ]); - storage.verify_upgrade_rent(fixture.storage_rent(1), fixture.legacy_storage_rent(1)); - storage.verify_regular_rent(0, 0); - } - - #[tokio::test] - async fn test_read_outdate_storage_for_actual_contract() { - let fixture = Fixture::new().await; - let storage = fixture.build_account_storage().await; - - let contract = &ACTUAL_CONTRACT; - assert_eq!( - storage - .storage(contract.address, OUTDATE_STORAGE_INDEX) - .await, - [0u8; 32] - ); - storage.verify_used_accounts(&[ - (fixture.contract_pubkey(contract.address), false, true), - ( - fixture.storage_pubkey(contract.address, OUTDATE_STORAGE_INDEX), - true, - true, - ), - ]); - storage.verify_upgrade_rent(0, fixture.legacy_storage_rent(1)); - storage.verify_regular_rent(0, 0); - } - - #[tokio::test] - async fn test_read_missing_storage_for_legacy_contract() { - let fixture = Fixture::new().await; - let storage = fixture.build_account_storage().await; - - let contract = &LEGACY_CONTRACT; - assert_eq!( - storage - .storage(contract.address, MISSING_STORAGE_INDEX) - .await, - [0u8; 32] - ); - storage.verify_used_accounts(&[( - fixture.storage_pubkey(contract.address, MISSING_STORAGE_INDEX), - false, - false, - )]); - storage.verify_upgrade_rent(0, 0); - storage.verify_regular_rent(0, 0); - } - - #[tokio::test] - async fn test_read_legacy_storage_for_legacy_contract() { - let fixture = Fixture::new().await; - let storage = fixture.build_account_storage().await; - - let contract = &LEGACY_CONTRACT; - assert_eq!( - storage - .storage(contract.address, LEGACY_STORAGE_INDEX) - .await, - contract.legacy_storage.values[0].1 - ); - storage.verify_used_accounts(&[ - (fixture.contract_pubkey(contract.address), true, true), - ( - fixture.balance_pubkey(contract.address, LEGACY_CHAIN_ID), - true, - true, - ), - ( - fixture.storage_pubkey(contract.address, LEGACY_STORAGE_INDEX), - true, - true, - ), - ]); - storage.verify_upgrade_rent( - fixture.balance_rent() + fixture.contract_rent(contract.code) + fixture.storage_rent(1), - fixture.legacy_storage_rent(1) + fixture.legacy_rent(Some(contract.code.len())), - ); - storage.verify_regular_rent(0, 0); - } - - #[tokio::test] - async fn test_read_outdate_storage_for_legacy_contract() { - let fixture = Fixture::new().await; - let storage = fixture.build_account_storage().await; - - let contract = &LEGACY_CONTRACT; - assert_eq!( - storage - .storage(contract.address, OUTDATE_STORAGE_INDEX) - .await, - [0u8; 32] - ); - storage.verify_used_accounts(&[ - (fixture.contract_pubkey(contract.address), true, true), - ( - fixture.balance_pubkey(contract.address, LEGACY_CHAIN_ID), - true, - true, - ), - ( - fixture.storage_pubkey(contract.address, OUTDATE_STORAGE_INDEX), - true, - true, - ), - ]); - storage.verify_upgrade_rent( - fixture.balance_rent() + fixture.contract_rent(contract.code), - fixture.legacy_storage_rent(1) + fixture.legacy_rent(Some(contract.code.len())), - ); - storage.verify_regular_rent(0, 0); - } - - #[tokio::test] - async fn test_read_missing_storage_for_legacy_suicide() { - let fixture = Fixture::new().await; - let storage = fixture.build_account_storage().await; - - let contract = &LEGACY_SUICIDE; - assert_eq!( - storage - .storage(contract.address, MISSING_STORAGE_INDEX) - .await, - [0u8; 32] - ); - storage.verify_used_accounts(&[( - fixture.storage_pubkey(contract.address, MISSING_STORAGE_INDEX), - false, - false, - )]); - storage.verify_upgrade_rent(0, 0); - storage.verify_regular_rent(0, 0); - } - - #[tokio::test] - async fn test_read_outdate_storage_for_legacy_suicide() { - let fixture = Fixture::new().await; - let storage = fixture.build_account_storage().await; - - let contract = &LEGACY_SUICIDE; - assert_eq!( - storage - .storage(contract.address, OUTDATE_STORAGE_INDEX) - .await, - [0u8; 32] - ); - storage.verify_used_accounts(&[ - (fixture.contract_pubkey(contract.address), true, true), - ( - fixture.balance_pubkey(contract.address, LEGACY_CHAIN_ID), - true, - true, - ), - ( - fixture.storage_pubkey(contract.address, OUTDATE_STORAGE_INDEX), - true, - true, - ), - ]); - storage.verify_upgrade_rent( - fixture.balance_rent() + fixture.contract_rent(contract.code), - fixture.legacy_storage_rent(1) + fixture.legacy_rent(Some(contract.code.len())), - ); - storage.verify_regular_rent(0, 0); - } -} +#[path = "./account_storage_tests.rs"] +mod account_storage_tests; diff --git a/evm_loader/lib/src/account_storage_tests.rs b/evm_loader/lib/src/account_storage_tests.rs new file mode 100644 index 000000000..fe9770df4 --- /dev/null +++ b/evm_loader/lib/src/account_storage_tests.rs @@ -0,0 +1,1581 @@ +use super::*; +use crate::tracing::AccountOverride; +use hex_literal::hex; +use std::collections::HashMap; +use std::str::FromStr; + +mod mock_rpc_client { + use crate::commands::get_config::BuildConfigSimulator; + use crate::NeonResult; + use crate::{commands::get_config::ConfigSimulator, rpc::Rpc}; + use async_trait::async_trait; + use solana_client::client_error::Result as ClientResult; + use solana_client::rpc_response::{Response, RpcResponseContext, RpcResult}; + use solana_sdk::account::Account; + use solana_sdk::clock::{Slot, UnixTimestamp}; + use solana_sdk::commitment_config::CommitmentConfig; + use solana_sdk::pubkey::Pubkey; + use std::collections::HashMap; + + pub struct MockRpcClient { + accounts: HashMap, + } + + impl MockRpcClient { + pub fn new(accounts: &[(Pubkey, Account)]) -> Self { + Self { + accounts: accounts.iter().cloned().collect(), + } + } + } + + #[async_trait(?Send)] + impl Rpc for MockRpcClient { + async fn get_account(&self, key: &Pubkey) -> RpcResult> { + let result = self.accounts.get(key).cloned(); + Ok(Response { + context: RpcResponseContext { + slot: 0, + api_version: None, + }, + value: result, + }) + } + + async fn get_account_with_commitment( + &self, + key: &Pubkey, + _commitment: CommitmentConfig, + ) -> RpcResult> { + self.get_account(key).await + } + + async fn get_multiple_accounts( + &self, + pubkeys: &[Pubkey], + ) -> ClientResult>> { + let result = pubkeys + .iter() + .map(|key| self.accounts.get(key).cloned()) + .collect::>(); + Ok(result) + } + + async fn get_block_time(&self, _slot: Slot) -> ClientResult { + Ok(UnixTimestamp::default()) + } + + async fn get_slot(&self) -> ClientResult { + Ok(Slot::default()) + } + } + + #[async_trait(?Send)] + impl BuildConfigSimulator for MockRpcClient { + async fn build_config_simulator(&self, _program_id: Pubkey) -> NeonResult { + unimplemented!(); + } + } +} + +fn create_legacy_ether_contract( + program_id: &Pubkey, + rent: &Rent, + address: Address, + balance: U256, + trx_count: u64, + generation: u32, + code: &[u8], + storage: &[[u8; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT], +) -> Account { + let data_length = if (code.len() > 0) || (generation > 0) { + 1 + LegacyEtherData::SIZE + 32 * STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT + code.len() + } else { + 1 + LegacyEtherData::SIZE + }; + let mut data = vec![0u8; data_length]; + + let data_ref = arrayref::array_mut_ref![data, 0, 1 + LegacyEtherData::SIZE]; + let ( + tag_ptr, + address_ptr, + bump_seed_ptr, + trx_count_ptr, + balance_ptr, + generation_ptr, + code_size_ptr, + rw_blocked_ptr, + ) = arrayref::mut_array_refs![data_ref, 1, 20, 1, 8, 32, 4, 4, 1]; + + *tag_ptr = LegacyEtherData::TAG.to_le_bytes(); + *address_ptr = *address.as_bytes(); + *bump_seed_ptr = 0u8.to_le_bytes(); + *trx_count_ptr = trx_count.to_le_bytes(); + *balance_ptr = balance.to_le_bytes(); + *generation_ptr = generation.to_le_bytes(); + *code_size_ptr = (code.len() as u32).to_le_bytes(); + *rw_blocked_ptr = 0u8.to_le_bytes(); + + if (generation > 0) || (code.len() > 0) { + let storage_offset = 1 + LegacyEtherData::SIZE; + const STORAGE_LENGTH: usize = 32 * STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT; + let storage_ptr = &mut data[storage_offset..][..STORAGE_LENGTH]; + let storage_source = unsafe { + let ptr: *const u8 = storage.as_ptr().cast(); + std::slice::from_raw_parts(ptr, 32 * STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT) + }; + storage_ptr.copy_from_slice(storage_source); + + let code_offset = storage_offset + STORAGE_LENGTH; + let code_ptr = &mut data[code_offset..][..code.len()]; + code_ptr.copy_from_slice(code); + } + + Account { + lamports: rent.minimum_balance(data.len()), + data: data, + owner: *program_id, + executable: false, + rent_epoch: 0, + } +} + +fn create_legacy_ether_account( + program_id: &Pubkey, + rent: &Rent, + address: Address, + balance: U256, + trx_count: u64, +) -> Account { + let storage = [[0u8; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT]; + create_legacy_ether_contract( + program_id, + rent, + address, + balance, + trx_count, + 0u32, + &[], + &storage, + ) +} + +struct ActualStorage { + index: U256, + values: &'static [(u8, [u8; 32])], +} + +struct LegacyStorage { + generation: u32, + index: U256, + values: &'static [(u8, [u8; 32])], +} + +impl ActualStorage { + pub fn account_with_pubkey( + &self, + program_id: &Pubkey, + rent: &Rent, + address: Address, + ) -> (Pubkey, Account) { + let (contract, _) = address.find_solana_address(program_id); + let cell_address = StorageCellAddress::new(program_id, &contract, &self.index); + let cell_pubkey = *cell_address.pubkey(); + let mut account_data = AccountData::new(cell_pubkey); + account_data.assign(*program_id).unwrap(); + account_data.expand(StorageCell::required_account_size(self.values.len())); + account_data.lamports = rent.minimum_balance(account_data.get_length()); + let mut storage = + StorageCell::initialize(account_data.into_account_info(), program_id).unwrap(); + for (cell, (index, value)) in storage.cells_mut().iter_mut().zip(self.values.iter()) { + cell.subindex = *index; + cell.value.copy_from_slice(value); + } + ( + cell_pubkey, + Account { + lamports: rent.minimum_balance(account_data.get_length()), + data: account_data.data().to_vec(), + owner: *program_id, + executable: false, + rent_epoch: 0, + }, + ) + } +} + +impl LegacyStorage { + pub fn required_account_size(count: usize) -> usize { + 1 + LegacyStorageData::SIZE + std::mem::size_of::<(u8, [u8; 32])>() * count + } + pub fn account_with_pubkey( + &self, + program_id: &Pubkey, + rent: &Rent, + address: Address, + ) -> (Pubkey, Account) { + let (contract, _) = address.find_solana_address(program_id); + let cell_address = StorageCellAddress::new(program_id, &contract, &self.index); + let cell_pubkey = *cell_address.pubkey(); + let mut data = vec![0u8; Self::required_account_size(self.values.len())]; + + let data_ref = arrayref::array_mut_ref![data, 0, 1 + LegacyStorageData::SIZE]; + let (tag_ptr, address_ptr, generation_ptr, index_ptr) = + arrayref::mut_array_refs![data_ref, 1, 20, 4, 32]; + + *tag_ptr = LegacyStorageData::TAG.to_le_bytes(); + *address_ptr = *address.as_bytes(); + *generation_ptr = self.generation.to_le_bytes(); + *index_ptr = self.index.to_le_bytes(); + + let storage = unsafe { + let data = &mut data[1 + LegacyStorageData::SIZE..]; + let ptr = data.as_mut_ptr().cast::<(u8, [u8; 32])>(); + std::slice::from_raw_parts_mut(ptr, self.values.len()) + }; + storage.copy_from_slice(self.values); + + let account = Account { + lamports: rent.minimum_balance(data.len()), + data: data, + owner: *program_id, + executable: false, + rent_epoch: 0, + }; + + (cell_pubkey, account) + } +} + +struct LegacyAccount { + pub address: Address, + pub balance: U256, + pub nonce: u64, +} + +impl LegacyAccount { + pub fn account_with_pubkey(&self, program_id: &Pubkey, rent: &Rent) -> (Pubkey, Account) { + ( + self.address.find_solana_address(&program_id).0, + create_legacy_ether_account(&program_id, &rent, self.address, self.balance, self.nonce), + ) + } +} +struct LegacyContract { + pub address: Address, + pub balance: U256, + pub nonce: u64, + pub generation: u32, + pub code: &'static [u8], + pub storage: [[u8; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT], + + pub legacy_storage: LegacyStorage, + pub outdate_storage: LegacyStorage, +} + +impl LegacyContract { + fn account_with_pubkey(&self, program_id: &Pubkey, rent: &Rent) -> (Pubkey, Account) { + ( + self.address.find_solana_address(&program_id).0, + create_legacy_ether_contract( + &program_id, + &rent, + self.address, + self.balance, + self.nonce, + self.generation, + &self.code, + &self.storage, + ), + ) + } + + pub fn legacy_storage_with_pubkey( + &self, + program_id: &Pubkey, + rent: &Rent, + ) -> (Pubkey, Account) { + self.legacy_storage + .account_with_pubkey(program_id, rent, self.address) + } + + pub fn outdate_storage_with_pubkey( + &self, + program_id: &Pubkey, + rent: &Rent, + ) -> (Pubkey, Account) { + self.outdate_storage + .account_with_pubkey(program_id, rent, self.address) + } +} + +struct ActualBalance { + pub address: Address, + pub chain_id: u64, + pub balance: U256, + pub nonce: u64, +} + +impl ActualBalance { + pub fn account_with_pubkey(&self, program_id: &Pubkey, rent: &Rent) -> (Pubkey, Account) { + let (pubkey, _) = self + .address + .find_balance_address(&program_id, self.chain_id); + let mut account_data = AccountData::new(pubkey); + account_data.assign(*program_id).unwrap(); + account_data.expand(BalanceAccount::required_account_size()); + account_data.lamports = rent.minimum_balance(account_data.get_length()); + + let mut balance = BalanceAccount::initialize( + account_data.into_account_info(), + program_id, + self.address, + self.chain_id, + ) + .unwrap(); + balance.mint(self.balance).unwrap(); + balance.increment_nonce_by(self.nonce).unwrap(); + + ( + pubkey, + Account { + lamports: rent.minimum_balance(account_data.get_length()), + data: account_data.data().to_vec(), + owner: *program_id, + executable: false, + rent_epoch: 0, + }, + ) + } +} + +struct ActualContract { + pub address: Address, + pub chain_id: u64, + pub generation: u32, + pub code: &'static [u8], + pub storage: [[u8; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT], + + pub actual_storage: ActualStorage, + pub legacy_storage: LegacyStorage, + pub outdate_storage: LegacyStorage, +} + +impl ActualContract { + pub fn account_with_pubkey(&self, program_id: &Pubkey, rent: &Rent) -> (Pubkey, Account) { + let (pubkey, _) = self.address.find_solana_address(&program_id); + let mut account_data = AccountData::new(pubkey); + account_data.assign(*program_id).unwrap(); + account_data.expand(ContractAccount::required_account_size(self.code)); + account_data.lamports = rent.minimum_balance(account_data.get_length()); + + let mut contract = ContractAccount::initialize( + account_data.into_account_info(), + program_id, + self.address, + self.chain_id, + self.generation, + self.code, + ) + .unwrap(); + contract.set_storage_multiple_values(0, &self.storage); + + ( + pubkey, + Account { + lamports: rent.minimum_balance(account_data.get_length()), + data: account_data.data().to_vec(), + owner: *program_id, + executable: false, + rent_epoch: 0, + }, + ) + } + + pub fn actual_storage_with_pubkey( + &self, + program_id: &Pubkey, + rent: &Rent, + ) -> (Pubkey, Account) { + self.actual_storage + .account_with_pubkey(program_id, rent, self.address) + } + + pub fn legacy_storage_with_pubkey( + &self, + program_id: &Pubkey, + rent: &Rent, + ) -> (Pubkey, Account) { + self.legacy_storage + .account_with_pubkey(program_id, rent, self.address) + } + + pub fn outdate_storage_with_pubkey( + &self, + program_id: &Pubkey, + rent: &Rent, + ) -> (Pubkey, Account) { + self.outdate_storage + .account_with_pubkey(program_id, rent, self.address) + } +} + +const LEGACY_CHAIN_ID: u64 = 1; +const EXTRA_CHAIN_ID: u64 = 2; +const MISSING_ADDRESS: Address = Address(hex!("7a250d5630b4cf539739df2c5dacb4c659f24800")); + +const MISSING_STORAGE_INDEX: U256 = U256::new(1 * 256u128); +const ACTUAL_STORAGE_INDEX: U256 = U256::new(2 * 256u128); +const LEGACY_STORAGE_INDEX: U256 = U256::new(3 * 256u128); +const OUTDATE_STORAGE_INDEX: U256 = U256::new(4 * 256u128); + +const ACTUAL_BALANCE: ActualBalance = ActualBalance { + address: Address(hex!("7a250d5630b4cf539739df2c5dacb4c659f24810")), + chain_id: LEGACY_CHAIN_ID, + balance: U256::new(1513), + nonce: 41, +}; + +const ACTUAL_BALANCE2: ActualBalance = ActualBalance { + address: Address(hex!("7a250d5630b4cf539739df2c5dacb4c659f24811")), + chain_id: EXTRA_CHAIN_ID, + balance: U256::new(5134), + nonce: 14, +}; + +const ACTUAL_CONTRACT: ActualContract = ActualContract { + address: Address(hex!("7a250d5630b4cf539739df2c5dacb4c659f24c11")), + chain_id: LEGACY_CHAIN_ID, + generation: 4, + code: &[0x03, 0x04, 0x05], + storage: [[14u8; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT], + actual_storage: ActualStorage { + index: ACTUAL_STORAGE_INDEX, + values: &[(0u8, [64u8; 32])], + }, + legacy_storage: LegacyStorage { + generation: 4, + index: LEGACY_STORAGE_INDEX, + values: &[(0u8, [54u8; 32])], + }, + outdate_storage: LegacyStorage { + generation: 3, + index: OUTDATE_STORAGE_INDEX, + values: &[(0u8, [34u8; 32])], + }, +}; + +const ACTUAL_SUICIDE: ActualContract = ActualContract { + address: Address(hex!("7a250d5630b4cf539739df2c5dacb4c659f24d10")), + chain_id: LEGACY_CHAIN_ID, + generation: 12, + code: &[], + storage: [[0u8; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT], // It's matter that suicide contract doesn't contains any values in storage! + actual_storage: ActualStorage { + index: U256::ZERO, + values: &[], + }, + legacy_storage: LegacyStorage { + generation: 0, + index: U256::ZERO, + values: &[], + }, + outdate_storage: LegacyStorage { + generation: 11, + index: LEGACY_STORAGE_INDEX, + values: &[(0u8, [13u8; 32])], + }, +}; + +const LEGACY_ACCOUNT: LegacyAccount = LegacyAccount { + address: Address(hex!("7a250d5630b4cf539739df2c5dacb4c659f24820")), + balance: U256::new(10234), + nonce: 123, +}; + +const LEGACY_CONTRACT: LegacyContract = LegacyContract { + address: Address(hex!("7a250d5630b4cf539739df2c5dacb4c659f24c21")), + balance: U256::new(6153), + nonce: 1, + generation: 3, + code: &[0x01, 0x02, 0x03], + storage: [[0u8; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT], + + legacy_storage: LegacyStorage { + generation: 3, + index: LEGACY_STORAGE_INDEX, + values: &[(0u8, [23u8; 32])], + }, + outdate_storage: LegacyStorage { + generation: 2, + index: OUTDATE_STORAGE_INDEX, + values: &[(0u8, [43u8; 32])], + }, +}; + +const LEGACY_CONTRACT_NO_BALANCE: LegacyContract = LegacyContract { + address: Address(hex!("7a250d5630b4cf539739df2c5dacb4c659f24c20")), + balance: U256::ZERO, + nonce: 0, + generation: 2, + code: &[0x01, 0x02, 0x03, 0x04], + storage: [[53u8; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT], + legacy_storage: LegacyStorage { + generation: 0, + index: U256::ZERO, + values: &[], + }, + outdate_storage: LegacyStorage { + generation: 1, + index: U256::ZERO, + values: &[], + }, +}; + +const LEGACY_SUICIDE: LegacyContract = LegacyContract { + address: Address(hex!("7a250d5630b4cf539739df2c5dacb4c659f24d21")), + balance: U256::new(41234), + nonce: 413, + generation: 5, + code: &[], + storage: [[42u8; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT], + + legacy_storage: LegacyStorage { + generation: 413, + index: LEGACY_STORAGE_INDEX, + values: &[(0u8, [65u8; 32])], + }, + outdate_storage: LegacyStorage { + generation: 412, + index: OUTDATE_STORAGE_INDEX, + values: &[(0u8, [76u8; 32])], + }, +}; + +struct Fixture { + program_id: Pubkey, + chains: Vec, + rent: Rent, + mock_rpc: mock_rpc_client::MockRpcClient, + block_overrides: Option, + state_overrides: Option>, + solana_overrides: Option, +} + +impl Fixture { + pub async fn new() -> Self { + let rent = Rent::default(); + let program_id = Pubkey::from_str("53DfF883gyixYNXnM7s5xhdeyV8mVk9T4i2hGV9vG9io").unwrap(); + let accounts = vec![ + ( + Pubkey::from_str("SysvarRent111111111111111111111111111111111").unwrap(), + Account { + lamports: 1009200, + data: bincode::serialize(&rent).unwrap(), + owner: Pubkey::from_str("Sysvar1111111111111111111111111111111111111").unwrap(), + executable: false, + rent_epoch: 0, + }, + ), + ACTUAL_BALANCE.account_with_pubkey(&program_id, &rent), + ACTUAL_BALANCE2.account_with_pubkey(&program_id, &rent), + LEGACY_ACCOUNT.account_with_pubkey(&program_id, &rent), + ACTUAL_CONTRACT.account_with_pubkey(&program_id, &rent), + ACTUAL_CONTRACT.actual_storage_with_pubkey(&program_id, &rent), + ACTUAL_CONTRACT.legacy_storage_with_pubkey(&program_id, &rent), + ACTUAL_CONTRACT.outdate_storage_with_pubkey(&program_id, &rent), + ACTUAL_SUICIDE.account_with_pubkey(&program_id, &rent), + ACTUAL_SUICIDE.outdate_storage_with_pubkey(&program_id, &rent), + LEGACY_CONTRACT.account_with_pubkey(&program_id, &rent), + LEGACY_CONTRACT.legacy_storage_with_pubkey(&program_id, &rent), + LEGACY_CONTRACT.outdate_storage_with_pubkey(&program_id, &rent), + LEGACY_CONTRACT_NO_BALANCE.account_with_pubkey(&program_id, &rent), + LEGACY_SUICIDE.account_with_pubkey(&program_id, &rent), + LEGACY_SUICIDE.outdate_storage_with_pubkey(&program_id, &rent), + ]; + + let rpc_client = mock_rpc_client::MockRpcClient::new(&accounts); + + Self { + program_id, + chains: vec![ + ChainInfo { + id: LEGACY_CHAIN_ID, + name: "neon".to_string(), + token: Pubkey::new_unique(), + }, + ChainInfo { + id: EXTRA_CHAIN_ID, + name: "usdt".to_string(), + token: Pubkey::new_unique(), + }, + ], + rent, + mock_rpc: rpc_client, + block_overrides: None, + state_overrides: None, + solana_overrides: None, + } + } + + pub async fn build_account_storage( + &self, + ) -> EmulatorAccountStorage<'_, mock_rpc_client::MockRpcClient> { + EmulatorAccountStorage::new( + &self.mock_rpc, + self.program_id, + Some(self.chains.clone()), + self.block_overrides.clone(), + self.state_overrides.clone(), + self.solana_overrides.clone(), + ) + .await + .unwrap() + } + + pub fn balance_pubkey(&self, address: Address, chain_id: u64) -> Pubkey { + address.find_balance_address(&self.program_id, chain_id).0 + } + + pub fn legacy_pubkey(&self, address: Address) -> Pubkey { + address.find_solana_address(&self.program_id).0 + } + + pub fn contract_pubkey(&self, address: Address) -> Pubkey { + address.find_solana_address(&self.program_id).0 + } + + pub fn storage_pubkey(&self, address: Address, index: U256) -> Pubkey { + if index < U256::new(STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT as u128) { + self.contract_pubkey(address) + } else { + let index = index & !U256::new(0xFF); + let base = self.contract_pubkey(address); + let cell_address = StorageCellAddress::new(&self.program_id, &base, &index); + *cell_address.pubkey() + } + } + + pub fn storage_rent(&self, count: usize) -> u64 { + self.rent + .minimum_balance(StorageCell::required_account_size(count)) + } + + pub fn legacy_storage_rent(&self, count: usize) -> u64 { + self.rent + .minimum_balance(LegacyStorage::required_account_size(count)) + } + + pub fn balance_rent(&self) -> u64 { + self.rent + .minimum_balance(BalanceAccount::required_account_size()) + } + + pub fn legacy_rent(&self, code_len: Option) -> u64 { + let data_length = code_len + .map(|len| 1 + LegacyEtherData::SIZE + 32 * STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT + len) + .unwrap_or(1 + LegacyEtherData::SIZE); + self.rent.minimum_balance(data_length) + } + + pub fn contract_rent(&self, code: &[u8]) -> u64 { + self.rent + .minimum_balance(ContractAccount::required_account_size(code)) + } +} + +impl<'rpc, T: Rpc> EmulatorAccountStorage<'rpc, T> { + pub fn verify_used_accounts(&self, expected: &[(Pubkey, bool, bool)]) { + let mut expected = expected.to_vec(); + expected.sort_by_key(|(k, _, _)| *k); + let mut actual = self + .used_accounts() + .iter() + .map(|v| (v.pubkey, v.is_writable, v.is_legacy)) + .collect::>(); + actual.sort_by_key(|(k, _, _)| *k); + assert_eq!(actual, expected); + } + + pub fn verify_upgrade_rent(&self, added_rent: u64, removed_rent: u64) { + assert_eq!( + self.get_upgrade_rent().unwrap(), + added_rent.saturating_sub(removed_rent) + ); + } + + pub fn verify_regular_rent(&self, added_rent: u64, removed_rent: u64) { + assert_eq!( + self.get_regular_rent().unwrap(), + added_rent.saturating_sub(removed_rent) + ); + } +} + +#[tokio::test] +async fn test_read_balance_missing_account() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + assert_eq!( + storage.balance(MISSING_ADDRESS, LEGACY_CHAIN_ID).await, + U256::ZERO + ); + assert_eq!(storage.nonce(MISSING_ADDRESS, LEGACY_CHAIN_ID).await, 0); + + storage.verify_used_accounts(&[ + ( + fixture.balance_pubkey(MISSING_ADDRESS, LEGACY_CHAIN_ID), + false, + false, + ), + (fixture.legacy_pubkey(MISSING_ADDRESS), false, false), + ]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(0, 0); +} + +#[tokio::test] +async fn test_read_balance_missing_account_extra_chain() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + assert_eq!( + storage.balance(MISSING_ADDRESS, EXTRA_CHAIN_ID).await, + U256::ZERO + ); + assert_eq!(storage.nonce(MISSING_ADDRESS, EXTRA_CHAIN_ID).await, 0); + + storage.verify_used_accounts(&[( + fixture.balance_pubkey(MISSING_ADDRESS, EXTRA_CHAIN_ID), + false, + false, + )]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(0, 0); +} + +#[tokio::test] +async fn test_read_balance_actual_account() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + let acc = &ACTUAL_BALANCE; + assert_eq!( + storage.balance(acc.address, acc.chain_id).await, + acc.balance + ); + assert_eq!(storage.nonce(acc.address, acc.chain_id).await, acc.nonce); + + storage.verify_used_accounts(&[( + fixture.balance_pubkey(acc.address, acc.chain_id), + false, + false, + )]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(0, 0); +} + +#[tokio::test] +async fn test_read_balance_actual_account_extra_chain() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + let acc = &ACTUAL_BALANCE2; + assert_eq!(acc.chain_id, EXTRA_CHAIN_ID); + assert_eq!( + storage.balance(acc.address, acc.chain_id).await, + acc.balance + ); + assert_eq!(storage.nonce(acc.address, acc.chain_id).await, acc.nonce); + + storage.verify_used_accounts(&[( + fixture.balance_pubkey(acc.address, acc.chain_id), + false, + false, + )]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(0, 0); +} + +#[tokio::test] +async fn test_read_balance_legacy_account() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + let acc = &LEGACY_ACCOUNT; + assert_eq!( + storage.balance(acc.address, LEGACY_CHAIN_ID).await, + acc.balance + ); + assert_eq!(storage.nonce(acc.address, LEGACY_CHAIN_ID).await, acc.nonce); + + storage.verify_used_accounts(&[ + ( + fixture.balance_pubkey(acc.address, LEGACY_CHAIN_ID), + true, + true, + ), + (fixture.legacy_pubkey(acc.address), true, true), + ]); + storage.verify_upgrade_rent(fixture.balance_rent(), fixture.legacy_rent(None)); + storage.verify_regular_rent(0, 0); +} + +#[tokio::test] +async fn test_modify_actual_and_missing_account() { + let fixture = Fixture::new().await; + let mut storage = fixture.build_account_storage().await; + + let from = &ACTUAL_BALANCE; + let amount = U256::new(10); + assert_eq!(from.chain_id, LEGACY_CHAIN_ID); + assert_eq!( + storage + .transfer(from.address, MISSING_ADDRESS, from.chain_id, amount) + .await + .is_ok(), + true + ); + + storage.verify_used_accounts(&[ + ( + fixture.balance_pubkey(from.address, from.chain_id), + true, + false, + ), + ( + fixture.balance_pubkey(MISSING_ADDRESS, LEGACY_CHAIN_ID), + true, + false, + ), + (fixture.legacy_pubkey(MISSING_ADDRESS), false, false), + ]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(fixture.balance_rent(), 0); + + assert_eq!( + storage.balance(from.address, from.chain_id).await, + from.balance - amount + ); + assert_eq!( + storage.balance(MISSING_ADDRESS, LEGACY_CHAIN_ID).await, + amount + ); +} + +#[tokio::test] +async fn test_modify_actual_and_missing_account_extra_chain() { + let fixture = Fixture::new().await; + let mut storage = fixture.build_account_storage().await; + + let from = &ACTUAL_BALANCE2; + let amount = U256::new(11); + assert_eq!(from.chain_id, EXTRA_CHAIN_ID); + assert_eq!( + storage + .transfer(from.address, MISSING_ADDRESS, from.chain_id, amount) + .await + .is_ok(), + true + ); + + storage.verify_used_accounts(&[ + ( + fixture.balance_pubkey(from.address, from.chain_id), + true, + false, + ), + ( + fixture.balance_pubkey(MISSING_ADDRESS, from.chain_id), + true, + false, + ), + ]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(fixture.balance_rent(), 0); + + assert_eq!( + storage.balance(from.address, from.chain_id).await, + from.balance - amount + ); + assert_eq!( + storage.balance(MISSING_ADDRESS, from.chain_id).await, + amount + ); +} + +#[tokio::test] +async fn test_modify_actual_and_legacy_account() { + let fixture = Fixture::new().await; + let mut storage = fixture.build_account_storage().await; + + let from = &ACTUAL_BALANCE; + let to = &LEGACY_ACCOUNT; + let amount = U256::new(10); + assert_eq!(from.chain_id, LEGACY_CHAIN_ID); + assert_eq!( + storage + .transfer(from.address, to.address, from.chain_id, amount) + .await + .is_ok(), + true + ); + + storage.verify_used_accounts(&[ + ( + fixture.balance_pubkey(from.address, from.chain_id), + true, + false, + ), + ( + fixture.balance_pubkey(to.address, LEGACY_CHAIN_ID), + true, + true, + ), + (fixture.legacy_pubkey(to.address), true, true), + ]); + storage.verify_upgrade_rent(fixture.balance_rent(), fixture.legacy_rent(None)); + storage.verify_regular_rent(0, 0); + + assert_eq!( + storage.balance(from.address, from.chain_id).await, + from.balance - amount + ); + assert_eq!( + storage.balance(to.address, LEGACY_CHAIN_ID).await, + to.balance + amount + ); +} + +#[tokio::test] +async fn test_read_missing_contract() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + assert_eq!(*storage.code(MISSING_ADDRESS).await, [0u8; 0]); + assert_eq!( + storage.storage(MISSING_ADDRESS, U256::ZERO).await, + [0u8; 32] + ); + storage.verify_used_accounts(&[(fixture.contract_pubkey(MISSING_ADDRESS), false, false)]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(0, 0); + + assert_eq!( + storage + .storage( + MISSING_ADDRESS, + U256::new(STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT as u128) + ) + .await, + [0u8; 32] + ); +} + +#[tokio::test] +async fn test_read_legacy_contract() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + assert_eq!( + *storage.code(LEGACY_CONTRACT.address).await, + *LEGACY_CONTRACT.code + ); + assert_eq!( + storage.storage(LEGACY_CONTRACT.address, U256::ZERO).await, + [0u8; 32] + ); + storage.verify_used_accounts(&[ + ( + fixture.balance_pubkey(LEGACY_CONTRACT.address, LEGACY_CHAIN_ID), + true, + true, + ), + (fixture.contract_pubkey(LEGACY_CONTRACT.address), true, true), + ]); + storage.verify_upgrade_rent( + fixture.balance_rent() + fixture.contract_rent(LEGACY_CONTRACT.code), + fixture.legacy_rent(Some(LEGACY_CONTRACT.code.len())), + ); + storage.verify_regular_rent(0, 0); +} + +#[tokio::test] +async fn test_read_legacy_contract_no_balance() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + let contract = &LEGACY_CONTRACT_NO_BALANCE; + assert_eq!(*storage.code(contract.address).await, *contract.code); + assert_eq!( + storage.storage(contract.address, U256::ZERO).await, + [53u8; 32] + ); + storage.verify_used_accounts(&[ + ( + fixture.balance_pubkey(contract.address, LEGACY_CHAIN_ID), + false, + true, + ), + (fixture.contract_pubkey(contract.address), true, true), + ]); + storage.verify_upgrade_rent( + fixture.contract_rent(contract.code), + fixture.legacy_rent(Some(contract.code.len())), + ); + storage.verify_regular_rent(0, 0); +} + +#[tokio::test] +async fn test_read_actual_suicide_contract() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + let contract = &ACTUAL_SUICIDE; + assert_eq!(*storage.code(contract.address).await, [0u8; 0]); + assert_eq!( + storage.storage(contract.address, U256::ZERO).await, + [0u8; 32] + ); + storage.verify_used_accounts(&[(fixture.contract_pubkey(contract.address), false, false)]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(0, 0); +} + +#[tokio::test] +async fn test_read_legacy_suicide_contract() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + let contract = &LEGACY_SUICIDE; + assert_eq!(*storage.code(contract.address).await, [0u8; 0]); + assert_eq!( + storage.storage(contract.address, U256::ZERO).await, + [0u8; 32] + ); + storage.verify_used_accounts(&[ + ( + fixture.balance_pubkey(contract.address, LEGACY_CHAIN_ID), + true, + true, + ), + (fixture.contract_pubkey(contract.address), true, true), + ]); + storage.verify_upgrade_rent( + fixture.balance_rent() + fixture.contract_rent(contract.code), + fixture.legacy_rent(Some(contract.code.len())), + ); + storage.verify_regular_rent(0, 0); +} + +#[tokio::test] +async fn test_deploy_at_missing_contract() { + let fixture = Fixture::new().await; + let mut storage = fixture.build_account_storage().await; + + let code = hex!("14643165").to_vec(); + assert_eq!( + storage + .set_code(MISSING_ADDRESS, LEGACY_CHAIN_ID, code.clone()) + .await + .is_ok(), + true + ); + storage.verify_used_accounts(&[(fixture.contract_pubkey(MISSING_ADDRESS), true, false)]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(fixture.contract_rent(&code), 0); +} + +#[tokio::test] +async fn test_deploy_at_actual_balance() { + let fixture = Fixture::new().await; + let mut storage = fixture.build_account_storage().await; + + let code = hex!("14643165").to_vec(); + let acc = &ACTUAL_BALANCE; + assert_eq!( + storage + .set_code(acc.address, LEGACY_CHAIN_ID, code.clone()) + .await + .is_ok(), + true + ); + storage.verify_used_accounts(&[(fixture.contract_pubkey(acc.address), true, false)]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(fixture.contract_rent(&code), 0); +} + +#[tokio::test] +async fn test_deploy_at_actual_contract() { + let fixture = Fixture::new().await; + let mut storage = fixture.build_account_storage().await; + + let code = hex!("62345987").to_vec(); + let contract = &ACTUAL_CONTRACT; + assert_eq!( + storage + .set_code(contract.address, LEGACY_CHAIN_ID, code) + .await + .unwrap_err() + .to_string(), + EvmLoaderError::AccountAlreadyInitialized(fixture.contract_pubkey(contract.address)) + .to_string() + ); + storage.verify_used_accounts(&[(fixture.contract_pubkey(contract.address), false, false)]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(0, 0); +} + +#[tokio::test] +async fn test_deploy_at_legacy_account() { + let fixture = Fixture::new().await; + let mut storage = fixture.build_account_storage().await; + + let code = hex!("37455846").to_vec(); + let contract = &LEGACY_ACCOUNT; + assert_eq!( + storage + .set_code(contract.address, LEGACY_CHAIN_ID, code.clone()) + .await + .is_ok(), + true + ); + storage.verify_used_accounts(&[ + ( + fixture.balance_pubkey(contract.address, LEGACY_CHAIN_ID), + true, + true, + ), + (fixture.contract_pubkey(contract.address), true, true), + ]); + storage.verify_upgrade_rent(fixture.balance_rent(), fixture.legacy_rent(None)); + storage.verify_regular_rent(fixture.contract_rent(&code), 0); +} + +#[tokio::test] +async fn test_deploy_at_legacy_contract() { + let fixture = Fixture::new().await; + let mut storage = fixture.build_account_storage().await; + + let code = hex!("13412971").to_vec(); + let contract = &LEGACY_CONTRACT; + assert_eq!( + storage + .set_code(contract.address, LEGACY_CHAIN_ID, code) + .await + .unwrap_err() + .to_string(), + EvmLoaderError::AccountAlreadyInitialized(fixture.contract_pubkey(contract.address)) + .to_string() + ); + storage.verify_used_accounts(&[ + ( + fixture.balance_pubkey(contract.address, LEGACY_CHAIN_ID), + true, + true, + ), + (fixture.contract_pubkey(contract.address), true, true), + ]); + storage.verify_upgrade_rent( + fixture.balance_rent() + fixture.contract_rent(contract.code), + fixture.legacy_rent(Some(contract.code.len())), + ); + storage.verify_regular_rent(0, 0); +} + +#[tokio::test] +async fn test_deploy_at_actual_suicide() { + let fixture = Fixture::new().await; + let mut storage = fixture.build_account_storage().await; + + let code = hex!("13412971").to_vec(); + let contract = &ACTUAL_SUICIDE; + // TODO: Should we deploy new contract by the previous address? + assert_eq!( + storage + .set_code(contract.address, LEGACY_CHAIN_ID, code.clone()) + .await + .is_ok(), + true, + ); + storage.verify_used_accounts(&[(fixture.contract_pubkey(contract.address), true, false)]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent( + fixture.contract_rent(&code), + fixture.contract_rent(contract.code), + ); +} + +#[tokio::test] +async fn test_deploy_at_legacy_suicide() { + let fixture = Fixture::new().await; + let mut storage = fixture.build_account_storage().await; + + let code = hex!("13412971").to_vec(); + let contract = &LEGACY_SUICIDE; + // TODO: Should we deploy new contract by the previous address? + assert_eq!( + storage + .set_code(contract.address, LEGACY_CHAIN_ID, code.clone()) + .await + .is_ok(), + true, + ); + storage.verify_used_accounts(&[ + ( + fixture.balance_pubkey(contract.address, LEGACY_CHAIN_ID), + true, + true, + ), + (fixture.contract_pubkey(contract.address), true, true), + ]); + storage.verify_upgrade_rent( + fixture.balance_rent() + fixture.contract_rent(&contract.code), + fixture.legacy_rent(Some(contract.code.len())), + ); + storage.verify_regular_rent( + fixture.contract_rent(&code), + fixture.contract_rent(&contract.code), + ); +} + +#[tokio::test] +async fn test_read_missing_storage_for_missing_contract() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + assert_eq!( + storage + .storage(MISSING_ADDRESS, MISSING_STORAGE_INDEX) + .await, + [0u8; 32] + ); + storage.verify_used_accounts(&[( + fixture.storage_pubkey(MISSING_ADDRESS, MISSING_STORAGE_INDEX), + false, + false, + )]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(0, 0); +} + +#[tokio::test] +async fn test_read_missing_storage_for_actual_contract() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + let contract = &ACTUAL_CONTRACT; + assert_eq!( + storage + .storage(contract.address, MISSING_STORAGE_INDEX) + .await, + [0u8; 32] + ); + storage.verify_used_accounts(&[( + fixture.storage_pubkey(contract.address, MISSING_STORAGE_INDEX), + false, + false, + )]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(0, 0); +} + +#[tokio::test] +async fn test_read_actual_storage_for_actual_contract() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + let contract = &ACTUAL_CONTRACT; + assert_eq!( + storage + .storage(contract.address, ACTUAL_STORAGE_INDEX) + .await, + contract.actual_storage.values[0].1 + ); + storage.verify_used_accounts(&[( + fixture.storage_pubkey(contract.address, ACTUAL_STORAGE_INDEX), + false, + false, + )]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(0, 0); +} + +#[tokio::test] +async fn test_modify_new_storage_for_actual_contract() { + let fixture = Fixture::new().await; + let mut storage = fixture.build_account_storage().await; + + let contract = &ACTUAL_CONTRACT; + assert_eq!( + storage + .storage(contract.address, ACTUAL_STORAGE_INDEX + 1) + .await, + [0u8; 32] + ); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(0, 0); + + let new_value = [0x01u8; 32]; + assert_eq!( + storage + .set_storage( + contract.address, + ACTUAL_STORAGE_INDEX + 1, + new_value.clone() + ) + .await + .is_ok(), + true + ); + assert_eq!( + storage + .storage(contract.address, ACTUAL_STORAGE_INDEX + 1) + .await, + new_value + ); + storage.verify_used_accounts(&[( + fixture.storage_pubkey(contract.address, ACTUAL_STORAGE_INDEX), + true, + false, + )]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(fixture.storage_rent(2), fixture.storage_rent(1)); +} + +#[tokio::test] +async fn test_modify_missing_storage_for_actual_contract() { + let fixture = Fixture::new().await; + let mut storage = fixture.build_account_storage().await; + + let contract = &ACTUAL_CONTRACT; + let new_value = [0x02u8; 32]; + assert_eq!( + storage + .set_storage(contract.address, MISSING_STORAGE_INDEX, new_value.clone()) + .await + .is_ok(), + true + ); + assert_eq!( + storage + .storage(contract.address, MISSING_STORAGE_INDEX) + .await, + new_value + ); + storage.verify_used_accounts(&[( + fixture.storage_pubkey(contract.address, MISSING_STORAGE_INDEX), + true, + false, + )]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(fixture.storage_rent(1), 0); +} + +#[tokio::test] +async fn test_modify_internal_storage_for_actual_contract() { + let fixture = Fixture::new().await; + let mut storage = fixture.build_account_storage().await; + + let contract = &ACTUAL_CONTRACT; + let new_value = [0x03u8; 32]; + let index = U256::new(0); + assert_eq!( + storage + .set_storage(contract.address, index, new_value.clone()) + .await + .is_ok(), + true + ); + assert_eq!(storage.storage(contract.address, index).await, new_value); + storage.verify_used_accounts(&[(fixture.contract_pubkey(contract.address), true, false)]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(0, 0); +} + +#[tokio::test] +async fn test_read_legacy_storage_for_actual_contract() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + let contract = &ACTUAL_CONTRACT; + assert_eq!( + storage + .storage(contract.address, LEGACY_STORAGE_INDEX) + .await, + contract.legacy_storage.values[0].1 + ); + storage.verify_used_accounts(&[ + (fixture.contract_pubkey(contract.address), false, true), + ( + fixture.storage_pubkey(contract.address, LEGACY_STORAGE_INDEX), + true, + true, + ), + ]); + storage.verify_upgrade_rent(fixture.storage_rent(1), fixture.legacy_storage_rent(1)); + storage.verify_regular_rent(0, 0); +} + +#[tokio::test] +async fn test_read_outdate_storage_for_actual_contract() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + let contract = &ACTUAL_CONTRACT; + assert_eq!( + storage + .storage(contract.address, OUTDATE_STORAGE_INDEX) + .await, + [0u8; 32] + ); + storage.verify_used_accounts(&[ + (fixture.contract_pubkey(contract.address), false, true), + ( + fixture.storage_pubkey(contract.address, OUTDATE_STORAGE_INDEX), + true, + true, + ), + ]); + storage.verify_upgrade_rent(0, fixture.legacy_storage_rent(1)); + storage.verify_regular_rent(0, 0); +} + +#[tokio::test] +async fn test_read_missing_storage_for_legacy_contract() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + let contract = &LEGACY_CONTRACT; + assert_eq!( + storage + .storage(contract.address, MISSING_STORAGE_INDEX) + .await, + [0u8; 32] + ); + storage.verify_used_accounts(&[( + fixture.storage_pubkey(contract.address, MISSING_STORAGE_INDEX), + false, + false, + )]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(0, 0); +} + +#[tokio::test] +async fn test_read_legacy_storage_for_legacy_contract() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + let contract = &LEGACY_CONTRACT; + assert_eq!( + storage + .storage(contract.address, LEGACY_STORAGE_INDEX) + .await, + contract.legacy_storage.values[0].1 + ); + storage.verify_used_accounts(&[ + (fixture.contract_pubkey(contract.address), true, true), + ( + fixture.balance_pubkey(contract.address, LEGACY_CHAIN_ID), + true, + true, + ), + ( + fixture.storage_pubkey(contract.address, LEGACY_STORAGE_INDEX), + true, + true, + ), + ]); + storage.verify_upgrade_rent( + fixture.balance_rent() + fixture.contract_rent(contract.code) + fixture.storage_rent(1), + fixture.legacy_storage_rent(1) + fixture.legacy_rent(Some(contract.code.len())), + ); + storage.verify_regular_rent(0, 0); +} + +#[tokio::test] +async fn test_read_outdate_storage_for_legacy_contract() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + let contract = &LEGACY_CONTRACT; + assert_eq!( + storage + .storage(contract.address, OUTDATE_STORAGE_INDEX) + .await, + [0u8; 32] + ); + storage.verify_used_accounts(&[ + (fixture.contract_pubkey(contract.address), true, true), + ( + fixture.balance_pubkey(contract.address, LEGACY_CHAIN_ID), + true, + true, + ), + ( + fixture.storage_pubkey(contract.address, OUTDATE_STORAGE_INDEX), + true, + true, + ), + ]); + storage.verify_upgrade_rent( + fixture.balance_rent() + fixture.contract_rent(contract.code), + fixture.legacy_storage_rent(1) + fixture.legacy_rent(Some(contract.code.len())), + ); + storage.verify_regular_rent(0, 0); +} + +#[tokio::test] +async fn test_read_missing_storage_for_legacy_suicide() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + let contract = &LEGACY_SUICIDE; + assert_eq!( + storage + .storage(contract.address, MISSING_STORAGE_INDEX) + .await, + [0u8; 32] + ); + storage.verify_used_accounts(&[( + fixture.storage_pubkey(contract.address, MISSING_STORAGE_INDEX), + false, + false, + )]); + storage.verify_upgrade_rent(0, 0); + storage.verify_regular_rent(0, 0); +} + +#[tokio::test] +async fn test_read_outdate_storage_for_legacy_suicide() { + let fixture = Fixture::new().await; + let storage = fixture.build_account_storage().await; + + let contract = &LEGACY_SUICIDE; + assert_eq!( + storage + .storage(contract.address, OUTDATE_STORAGE_INDEX) + .await, + [0u8; 32] + ); + storage.verify_used_accounts(&[ + (fixture.contract_pubkey(contract.address), true, true), + ( + fixture.balance_pubkey(contract.address, LEGACY_CHAIN_ID), + true, + true, + ), + ( + fixture.storage_pubkey(contract.address, OUTDATE_STORAGE_INDEX), + true, + true, + ), + ]); + storage.verify_upgrade_rent( + fixture.balance_rent() + fixture.contract_rent(contract.code), + fixture.legacy_storage_rent(1) + fixture.legacy_rent(Some(contract.code.len())), + ); + storage.verify_regular_rent(0, 0); +} From 8672e357cabdc0b80726a8bfbca5a99d4e09a4f1 Mon Sep 17 00:00:00 2001 From: sergei poletaev Date: Thu, 9 May 2024 13:48:05 +0300 Subject: [PATCH 190/318] Added tests for balance and nonce overridings --- evm_loader/lib/src/account_storage.rs | 12 +- evm_loader/lib/src/account_storage_tests.rs | 166 +++++++++++++++++++- evm_loader/lib/src/tracing/mod.rs | 2 +- 3 files changed, 169 insertions(+), 11 deletions(-) diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index 062ac2f07..afa93b773 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -114,7 +114,7 @@ pub struct EmulatorAccountStorage<'rpc, T: Rpc> { block_timestamp: i64, timestamp_used: RefCell, rent: Rent, - _state_overrides: Option, + state_overrides: Option, accounts_cache: FrozenMap>>, used_accounts: FrozenMap>>, return_data: RefCell>, @@ -233,7 +233,7 @@ impl<'rpc, T: Rpc + BuildConfigSimulator> EmulatorAccountStorage<'rpc, T> { block_number, block_timestamp, timestamp_used: RefCell::new(false), - _state_overrides: state_overrides, + state_overrides: state_overrides, rent, accounts_cache, used_accounts: FrozenMap::new(), @@ -256,7 +256,7 @@ impl<'rpc, T: Rpc + BuildConfigSimulator> EmulatorAccountStorage<'rpc, T> { block_timestamp: other.block_timestamp.saturating_add(timestamp_shift), timestamp_used: RefCell::new(false), rent: other.rent, - _state_overrides: other._state_overrides.clone(), + state_overrides: other.state_overrides.clone(), accounts_cache: other.accounts_cache.clone(), used_accounts: other.used_accounts.clone(), return_data: RefCell::new(None), @@ -969,12 +969,6 @@ impl AccountStorage for EmulatorAccountStorage<'_, T> { async fn balance(&self, address: Address, chain_id: u64) -> U256 { info!("balance {address} {chain_id}"); - // TODO: move to reading data from Solana node - // let balance_override = self.account_override(address, |a| a.balance); - // if let Some(balance_override) = balance_override { - // return balance_override; - // } - self.ethereum_balance_map_or(address, chain_id, U256::default(), |account| { account.balance() }) diff --git a/evm_loader/lib/src/account_storage_tests.rs b/evm_loader/lib/src/account_storage_tests.rs index fe9770df4..d703b2350 100644 --- a/evm_loader/lib/src/account_storage_tests.rs +++ b/evm_loader/lib/src/account_storage_tests.rs @@ -1,9 +1,9 @@ use super::*; +use crate::rpc; use crate::tracing::AccountOverride; use hex_literal::hex; use std::collections::HashMap; use std::str::FromStr; - mod mock_rpc_client { use crate::commands::get_config::BuildConfigSimulator; use crate::NeonResult; @@ -78,6 +78,40 @@ mod mock_rpc_client { } } +async fn get_overriden_nonce_and_balance( + address: Address, + tx_chain_id: u64, + nonce_chain_id: u64, + overrides: Option, +) -> (u64, U256) { + let mut fixture = Fixture::new().await; + fixture.state_overrides = overrides; + let storage = fixture.build_account_storage().await; + + assert!(storage.apply_balance_overrides(tx_chain_id).await.is_ok()); + + ( + storage.nonce(address, nonce_chain_id).await, + storage.balance(address, nonce_chain_id).await, + ) +} + +async fn get_balance_account_info( + storage: &EmulatorAccountStorage<'_, T>, + action: F, +) -> NeonResult +where + F: FnOnce(&BalanceAccount) -> R, +{ + let mut balance_data = storage + .get_balance_account(ACTUAL_BALANCE.address, LEGACY_CHAIN_ID) + .await? + .borrow_mut(); + let balance_account = + BalanceAccount::from_account(&storage.program_id, balance_data.into_account_info()); + + Ok(action(&balance_account?)) +} fn create_legacy_ether_contract( program_id: &Pubkey, rent: &Rent, @@ -1579,3 +1613,133 @@ async fn test_read_outdate_storage_for_legacy_suicide() { ); storage.verify_regular_rent(0, 0); } + +#[tokio::test] +async fn test_state_overrides_nonce_and_balance() { + let expected_nonce = 17; + let expected_balance = U256::MAX; + + let overriden_state = AccountOverrides::from([ + ( + ACTUAL_BALANCE.address, + AccountOverride { + nonce: Some(expected_nonce), + balance: Some(expected_balance), + ..Default::default() + }, + ), + ( + ACTUAL_BALANCE2.address, + AccountOverride { + nonce: Some(expected_nonce), + ..Default::default() + }, + ), + ]); + + // Checking override for another acount and chain where we expect only + // nonce overriden. + assert_eq!( + get_overriden_nonce_and_balance( + ACTUAL_BALANCE2.address, + EXTRA_CHAIN_ID, + EXTRA_CHAIN_ID, + Some(overriden_state.clone()) + ) + .await, + (expected_nonce, ACTUAL_BALANCE2.balance) + ); + + // Checking override for another for first account for both + // balance and nonce. + assert_eq!( + get_overriden_nonce_and_balance( + ACTUAL_BALANCE.address, + LEGACY_CHAIN_ID, + LEGACY_CHAIN_ID, + Some(overriden_state.clone()) + ) + .await, + (expected_nonce, expected_balance) + ); + + // Override for different chain id. + assert_ne!(expected_nonce, ACTUAL_BALANCE.nonce); + assert_eq!( + get_overriden_nonce_and_balance( + ACTUAL_BALANCE.address, + EXTRA_CHAIN_ID, + LEGACY_CHAIN_ID, + Some(overriden_state.clone()) + ) + .await, + (ACTUAL_BALANCE.nonce, ACTUAL_BALANCE.balance) + ); + + // Do not override if all items are None. + assert_eq!( + get_overriden_nonce_and_balance( + ACTUAL_BALANCE.address, + LEGACY_CHAIN_ID, + LEGACY_CHAIN_ID, + Some(AccountOverrides::from([ + (ACTUAL_BALANCE.address, AccountOverride::default()), + (ACTUAL_BALANCE2.address, AccountOverride::default()) + ])) + ) + .await, + (ACTUAL_BALANCE.nonce, ACTUAL_BALANCE.balance) + ); +} + +#[tokio::test] +async fn test_storage_init_and_override() { + let expected_nonce = 17; + let expected_balance = U256::MAX; + + let rent = Rent::default(); + let program_id = Pubkey::from_str("53DfF883gyixYNXnM7s5xhdeyV8mVk9T4i2hGV9vG9io").unwrap(); + let account_tuple = ACTUAL_BALANCE.account_with_pubkey(&program_id, &rent); + let accounts_for_rpc = vec![ + (solana_sdk::sysvar::rent::id(), account_tuple.1.clone()), + account_tuple.clone(), + ]; + let rpc_client = mock_rpc_client::MockRpcClient::new(&accounts_for_rpc); + let accounts_for_storage: Vec = vec![account_tuple.0.clone()]; + let storage = EmulatorAccountStorage::with_accounts( + &rpc_client, + program_id, + &accounts_for_storage, + vec![ChainInfo { + id: LEGACY_CHAIN_ID, + name: "neon".to_string(), + token: Pubkey::new_unique(), + }] + .into(), + None, + Some(AccountOverrides::from([( + ACTUAL_BALANCE.address, + AccountOverride { + nonce: Some(expected_nonce), + balance: Some(expected_balance), + ..Default::default() + }, + )])), + None, + Some(LEGACY_CHAIN_ID), + ) + .await + .expect("Failed to create storage"); + assert_eq!( + get_balance_account_info(&storage, |account| account.nonce()) + .await + .expect("Failed to read nonce"), + expected_nonce + ); + assert_eq!( + get_balance_account_info(&storage, |account| account.balance()) + .await + .expect("Failed to read balance"), + expected_balance + ); +} diff --git a/evm_loader/lib/src/tracing/mod.rs b/evm_loader/lib/src/tracing/mod.rs index adbb83878..a702b4262 100644 --- a/evm_loader/lib/src/tracing/mod.rs +++ b/evm_loader/lib/src/tracing/mod.rs @@ -27,7 +27,7 @@ pub struct BlockOverrides { } /// See -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)] #[serde(rename_all = "camelCase")] pub struct AccountOverride { pub nonce: Option, From 105fd2155d18fa34d5d15110cdf086dc7f4b3376 Mon Sep 17 00:00:00 2001 From: sergei poletaev Date: Tue, 14 May 2024 14:53:34 +0300 Subject: [PATCH 191/318] Apply overrides from all constructors --- evm_loader/lib/src/account_storage.rs | 28 +++++-- evm_loader/lib/src/account_storage_tests.rs | 83 ++++++++++++++++++- evm_loader/lib/src/commands/emulate.rs | 8 +- evm_loader/lib/src/commands/get_storage_at.rs | 2 +- 4 files changed, 107 insertions(+), 14 deletions(-) diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index afa93b773..f3d08b9a8 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -187,6 +187,7 @@ impl<'rpc, T: Rpc + BuildConfigSimulator> EmulatorAccountStorage<'rpc, T> { block_overrides: Option, state_overrides: Option, solana_overrides: Option, + tx_chain_id: Option, ) -> Result, NeonError> { trace!("backend::new"); @@ -219,8 +220,7 @@ impl<'rpc, T: Rpc + BuildConfigSimulator> EmulatorAccountStorage<'rpc, T> { accounts_cache.insert(pubkey, Box::new(account)); } } - - Ok(Self { + let storage = Self { accounts: FrozenMap::new(), call_stack: vec![], program_id, @@ -238,11 +238,21 @@ impl<'rpc, T: Rpc + BuildConfigSimulator> EmulatorAccountStorage<'rpc, T> { accounts_cache, used_accounts: FrozenMap::new(), return_data: RefCell::new(None), - }) + }; + + let target_chain_id = tx_chain_id.unwrap_or(storage.default_chain_id()); + storage.apply_balance_overrides(target_chain_id).await?; + + Ok(storage) } - pub fn new_from_other(other: &Self, block_shift: u64, timestamp_shift: i64) -> Self { - Self { + pub async fn new_from_other( + other: &Self, + block_shift: u64, + timestamp_shift: i64, + tx_chain_id: Option, + ) -> Result, NeonError> { + let storage = Self { accounts: FrozenMap::new(), call_stack: vec![], program_id: other.program_id, @@ -260,7 +270,10 @@ impl<'rpc, T: Rpc + BuildConfigSimulator> EmulatorAccountStorage<'rpc, T> { accounts_cache: other.accounts_cache.clone(), used_accounts: other.used_accounts.clone(), return_data: RefCell::new(None), - } + }; + let target_chain_id = tx_chain_id.unwrap_or(storage.default_chain_id()); + storage.apply_balance_overrides(target_chain_id).await?; + Ok(storage) } pub async fn with_accounts( @@ -280,12 +293,11 @@ impl<'rpc, T: Rpc + BuildConfigSimulator> EmulatorAccountStorage<'rpc, T> { block_overrides, state_overrides, solana_overrides, + tx_chain_id, ) .await?; storage.download_accounts(accounts).await?; - let target_chain_id = tx_chain_id.unwrap_or(storage.default_chain_id()); - storage.apply_balance_overrides(target_chain_id).await?; Ok(storage) } diff --git a/evm_loader/lib/src/account_storage_tests.rs b/evm_loader/lib/src/account_storage_tests.rs index d703b2350..143cdf1a5 100644 --- a/evm_loader/lib/src/account_storage_tests.rs +++ b/evm_loader/lib/src/account_storage_tests.rs @@ -86,9 +86,9 @@ async fn get_overriden_nonce_and_balance( ) -> (u64, U256) { let mut fixture = Fixture::new().await; fixture.state_overrides = overrides; - let storage = fixture.build_account_storage().await; - - assert!(storage.apply_balance_overrides(tx_chain_id).await.is_ok()); + let storage = fixture + .build_account_storage_with_chain_id(Some(tx_chain_id)) + .await; ( storage.nonce(address, nonce_chain_id).await, @@ -652,6 +652,23 @@ impl Fixture { } } + pub async fn build_account_storage_with_chain_id( + &self, + tx_chain_id: Option, + ) -> EmulatorAccountStorage<'_, mock_rpc_client::MockRpcClient> { + EmulatorAccountStorage::new( + &self.mock_rpc, + self.program_id, + Some(self.chains.clone()), + self.block_overrides.clone(), + self.state_overrides.clone(), + self.solana_overrides.clone(), + tx_chain_id, + ) + .await + .unwrap() + } + pub async fn build_account_storage( &self, ) -> EmulatorAccountStorage<'_, mock_rpc_client::MockRpcClient> { @@ -662,6 +679,7 @@ impl Fixture { self.block_overrides.clone(), self.state_overrides.clone(), self.solana_overrides.clone(), + None, ) .await .unwrap() @@ -1693,7 +1711,7 @@ async fn test_state_overrides_nonce_and_balance() { } #[tokio::test] -async fn test_storage_init_and_override() { +async fn test_storage_with_accounts_and_override() { let expected_nonce = 17; let expected_balance = U256::MAX; @@ -1743,3 +1761,60 @@ async fn test_storage_init_and_override() { expected_balance ); } + +#[tokio::test] +async fn test_storage_new_from_other_and_override() { + let expected_nonce = 17; + let expected_balance = U256::MAX; + + let rent = Rent::default(); + let program_id = Pubkey::from_str("53DfF883gyixYNXnM7s5xhdeyV8mVk9T4i2hGV9vG9io").unwrap(); + let account_tuple = ACTUAL_BALANCE.account_with_pubkey(&program_id, &rent); + let accounts_for_rpc = vec![ + (solana_sdk::sysvar::rent::id(), account_tuple.1.clone()), + account_tuple.clone(), + ]; + let rpc_client = mock_rpc_client::MockRpcClient::new(&accounts_for_rpc); + let accounts_for_storage: Vec = vec![account_tuple.0.clone()]; + let storage = EmulatorAccountStorage::with_accounts( + &rpc_client, + program_id, + &accounts_for_storage, + vec![ChainInfo { + id: LEGACY_CHAIN_ID, + name: "neon".to_string(), + token: Pubkey::new_unique(), + }] + .into(), + None, + Some(AccountOverrides::from([( + ACTUAL_BALANCE.address, + AccountOverride { + nonce: Some(expected_nonce), + balance: Some(expected_balance), + ..Default::default() + }, + )])), + None, + Some(LEGACY_CHAIN_ID), + ) + .await + .expect("Failed to create storage"); + + let other_storage = + EmulatorAccountStorage::new_from_other(&storage, 0, 0, Some(LEGACY_CHAIN_ID)) + .await + .expect("Failed to create a copy of storage"); + assert_eq!( + get_balance_account_info(&other_storage, |account| account.nonce()) + .await + .expect("Failed to read nonce"), + expected_nonce + ); + assert_eq!( + get_balance_account_info(&other_storage, |account| account.balance()) + .await + .expect("Failed to read balance"), + expected_balance + ); +} diff --git a/evm_loader/lib/src/commands/emulate.rs b/evm_loader/lib/src/commands/emulate.rs index bcbd78aec..a385c5f39 100644 --- a/evm_loader/lib/src/commands/emulate.rs +++ b/evm_loader/lib/src/commands/emulate.rs @@ -101,7 +101,13 @@ pub async fn execute( let result = emulate_trx(emulate_request.tx.clone(), &mut storage, step_limit, tracer).await?; if storage.is_timestamp_used() { - let mut storage2 = EmulatorAccountStorage::new_from_other(&storage, 5, 3); + let mut storage2 = EmulatorAccountStorage::new_from_other( + &storage, + 5, + 3, + emulate_request.tx.chain_id.clone(), + ) + .await?; if let Ok(result2) = emulate_trx( emulate_request.tx, &mut storage2, diff --git a/evm_loader/lib/src/commands/get_storage_at.rs b/evm_loader/lib/src/commands/get_storage_at.rs index 29d7ab310..e46e5ac56 100644 --- a/evm_loader/lib/src/commands/get_storage_at.rs +++ b/evm_loader/lib/src/commands/get_storage_at.rs @@ -17,7 +17,7 @@ pub async fn execute( address: Address, index: U256, ) -> NeonResult { - let value = EmulatorAccountStorage::new(rpc, *program_id, None, None, None, None) + let value = EmulatorAccountStorage::new(rpc, *program_id, None, None, None, None, None) .await? .storage(address, index) .await; From ce0d874573e6658ab35c5645b72585e0d5455eb9 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Wed, 15 May 2024 20:35:19 +0300 Subject: [PATCH 192/318] NDEV-3025: state and stateDiff overrides require 32 byte hex values (#419) --- evm_loader/lib/src/tracing/mod.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/evm_loader/lib/src/tracing/mod.rs b/evm_loader/lib/src/tracing/mod.rs index a702b4262..e510a84a8 100644 --- a/evm_loader/lib/src/tracing/mod.rs +++ b/evm_loader/lib/src/tracing/mod.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use ethnum::U256; use serde_json::Value; -use web3::types::Bytes; +use web3::types::{Bytes, H256}; use evm_loader::types::Address; @@ -33,8 +33,8 @@ pub struct AccountOverride { pub nonce: Option, pub code: Option, pub balance: Option, - pub state: Option>, - pub state_diff: Option>, + pub state: Option>, + pub state_diff: Option>, } impl AccountOverride { @@ -45,8 +45,14 @@ impl AccountOverride { (Some(_), Some(_)) => { panic!("Account has both `state` and `stateDiff` overrides") } - (Some(state), None) => return state.get(&index).map(|value| value.to_be_bytes()), - (None, Some(state_diff)) => state_diff.get(&index).map(|v| v.to_be_bytes()), + (Some(state), None) => { + return state + .get(&H256::from(index.to_be_bytes())) + .map(|value| value.to_fixed_bytes()) + } + (None, Some(state_diff)) => state_diff + .get(&H256::from(index.to_be_bytes())) + .map(|v| v.to_fixed_bytes()), } } } From 14b1617876ee374bf6b6f0465eca632c6f47a121 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 May 2024 20:35:53 +0300 Subject: [PATCH 193/318] Bump base64 from 0.22.0 to 0.22.1 in /evm_loader (#417) Bumps [base64](https://github.com/marshallpierce/rust-base64) from 0.22.0 to 0.22.1. - [Changelog](https://github.com/marshallpierce/rust-base64/blob/master/RELEASE-NOTES.md) - [Commits](https://github.com/marshallpierce/rust-base64/compare/v0.22.0...v0.22.1) --- updated-dependencies: - dependency-name: base64 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 90d59d593..aaf0d60f1 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -683,9 +683,9 @@ checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64" -version = "0.22.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" @@ -3329,7 +3329,7 @@ dependencies = [ "arrayref", "async-ffi", "async-trait", - "base64 0.22.0", + "base64 0.22.1", "bincode", "bs58 0.5.1", "build-info", @@ -4739,7 +4739,7 @@ version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ad483d2ab0149d5a5ebcd9972a3852711e0153d863bf5a5d0391d28883c4a20" dependencies = [ - "base64 0.22.0", + "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", From 0adf434e4e77013827253da2a240d26ae7616e4c Mon Sep 17 00:00:00 2001 From: Kristina Nikolaeva <112946046+kristinaNikolaevaa@users.noreply.github.com> Date: Thu, 16 May 2024 09:48:54 +0200 Subject: [PATCH 194/318] NDEV-3026 add new proxy to ci (#420) * fix PROXY_ENDPOINT * fix RUN_LINK_REPO --- .github/workflows/github_api_client.py | 2 +- .github/workflows/pipeline.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/github_api_client.py b/.github/workflows/github_api_client.py index eb62a9a04..ec91ccd42 100644 --- a/.github/workflows/github_api_client.py +++ b/.github/workflows/github_api_client.py @@ -35,7 +35,7 @@ def run_proxy_dispatches(self, proxy_branch, neon_evm_branch, github_sha, full_t click.echo(f"Sent data: {data}") click.echo(f"Status code: {response.status_code}") if response.status_code != 204: - raise RuntimeError("proxy-model.py action is not triggered, error: {response.text}") + raise RuntimeError("Proxy action is not triggered, error: {response.text}") @staticmethod def is_branch_exist(endpoint, branch): diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index 51f4ef0fe..c2d2f77a8 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -14,10 +14,10 @@ env: DHUBU: ${{secrets.DHUBU}} DHUBP: ${{secrets.DHUBP}} IMAGE_NAME: ${{vars.IMAGE_NAME}} - PROXY_ENDPOINT: ${{vars.PROXY_ENDPOINT}} + PROXY_ENDPOINT: "https://api.github.com/repos/neonlabsorg/neon-proxy.py" NEON_TESTS_ENDPOINT: ${{vars.NEON_TESTS_ENDPOINT}} DOCKERHUB_ORG_NAME: ${{vars.DOCKERHUB_ORG_NAME}} - RUN_LINK_REPO: ${{vars.RUN_LINK_REPO}} + RUN_LINK_REPO: "neonlabsorg/neon-proxy.py" BUILD_URL: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" concurrency: From 46f6fd3cf7cc073783d81a1cdfeed93bcf7fd6d6 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Mon, 8 Apr 2024 09:32:21 +0300 Subject: [PATCH 195/318] Add a new account type for operator balances --- evm_loader/program/src/account/mod.rs | 22 +- .../program/src/account/operator_balance.rs | 236 ++++++++++++++++++ evm_loader/program/src/account/state.rs | 41 ++- .../program/src/account_storage/apply.rs | 9 +- .../program/src/account_storage/base.rs | 4 - evm_loader/program/src/entrypoint.rs | 9 + evm_loader/program/src/error.rs | 12 + evm_loader/program/src/instruction/mod.rs | 12 + .../instruction/operator_create_balance.rs | 36 +++ .../instruction/operator_delete_balance.rs | 22 ++ .../instruction/operator_withdraw_balance.rs | 19 ++ .../src/instruction/transaction_cancel.rs | 10 +- .../transaction_execute_from_account.rs | 15 +- .../transaction_execute_from_instruction.rs | 14 +- .../src/instruction/transaction_step.rs | 2 +- .../transaction_step_from_account.rs | 25 +- .../transaction_step_from_instruction.rs | 20 +- evm_loader/program/src/types/address.rs | 20 +- 18 files changed, 465 insertions(+), 63 deletions(-) create mode 100644 evm_loader/program/src/account/operator_balance.rs create mode 100644 evm_loader/program/src/instruction/operator_create_balance.rs create mode 100644 evm_loader/program/src/instruction/operator_delete_balance.rs create mode 100644 evm_loader/program/src/instruction/operator_withdraw_balance.rs diff --git a/evm_loader/program/src/account/mod.rs b/evm_loader/program/src/account/mod.rs index 06211ee2c..d0bef519f 100644 --- a/evm_loader/program/src/account/mod.rs +++ b/evm_loader/program/src/account/mod.rs @@ -1,5 +1,4 @@ use crate::error::{Error, Result}; -use crate::types::Address; use solana_program::account_info::AccountInfo; use solana_program::pubkey::Pubkey; use solana_program::rent::Rent; @@ -13,6 +12,7 @@ pub use ether_storage::{Header as StorageCellHeader, StorageCell, StorageCellAdd pub use holder::{Header as HolderHeader, Holder}; pub use incinerator::Incinerator; pub use operator::Operator; +pub use operator_balance::{OperatorBalanceAccount, OperatorBalanceValidator}; pub use state::{AccountsStatus, StateAccount}; pub use state_finalized::{Header as StateFinalizedHeader, StateFinalizedAccount}; pub use treasury::{MainTreasury, Treasury}; @@ -26,6 +26,7 @@ mod holder; mod incinerator; pub mod legacy; mod operator; +mod operator_balance; pub mod program; mod state; mod state_finalized; @@ -39,6 +40,7 @@ pub const TAG_HOLDER: u8 = 52; pub const TAG_ACCOUNT_BALANCE: u8 = 60; pub const TAG_ACCOUNT_CONTRACT: u8 = 70; +pub const TAG_OPERATOR_BALANCE: u8 = 80; pub const TAG_STORAGE_CELL: u8 = 43; const TAG_OFFSET: usize = 0; @@ -203,7 +205,7 @@ pub unsafe fn delete(account: &AccountInfo, operator: &Operator) { pub struct AccountsDB<'a> { sorted_accounts: Vec>, operator: Operator<'a>, - operator_balance: Option>, + operator_balance: Option>, system: Option>, treasury: Option>, } @@ -213,7 +215,7 @@ impl<'a> AccountsDB<'a> { pub fn new( accounts: &[AccountInfo<'a>], operator: Operator<'a>, - operator_balance: Option>, + operator_balance: Option>, system: Option>, treasury: Option>, ) -> Self { @@ -259,21 +261,17 @@ impl<'a> AccountsDB<'a> { } #[must_use] - pub fn operator_balance(&mut self) -> &mut BalanceAccount<'a> { - if let Some(operator_balance) = &mut self.operator_balance { - return operator_balance; + pub fn operator_balance(&self) -> OperatorBalanceAccount<'a> { + if let Some(operator_balance) = &self.operator_balance { + return operator_balance.clone(); } panic!("Operator Balance Account must be present in the transaction"); } #[must_use] - pub fn operator_balance_address(&self) -> Address { - if let Some(operator_balance) = &self.operator_balance { - return operator_balance.address(); - } - - panic!("Operator Balance Account must be present in the transaction"); + pub fn try_operator_balance(&self) -> Option> { + self.operator_balance.clone() } #[must_use] diff --git a/evm_loader/program/src/account/operator_balance.rs b/evm_loader/program/src/account/operator_balance.rs new file mode 100644 index 000000000..753bd22ae --- /dev/null +++ b/evm_loader/program/src/account/operator_balance.rs @@ -0,0 +1,236 @@ +use std::mem::size_of; + +use crate::{ + error::{Error, Result}, + types::{Address, Transaction}, +}; +use ethnum::U256; +use solana_program::{account_info::AccountInfo, pubkey::Pubkey, rent::Rent, system_program}; + +use super::{ + program, AccountHeader, BalanceAccount, Operator, ACCOUNT_PREFIX_LEN, ACCOUNT_SEED_VERSION, + TAG_OPERATOR_BALANCE, +}; + +#[repr(C, packed)] +pub struct Header { + pub owner: Pubkey, + pub address: Address, + pub chain_id: u64, + pub balance: U256, +} +impl AccountHeader for Header { + const VERSION: u8 = 2; +} + +#[derive(Clone)] +pub struct OperatorBalanceAccount<'a> { + account: &'a AccountInfo<'a>, +} + +impl<'a> OperatorBalanceAccount<'a> { + #[must_use] + pub fn required_account_size() -> usize { + ACCOUNT_PREFIX_LEN + size_of::
() + } + + pub fn from_account(program_id: &Pubkey, account: &'a AccountInfo<'a>) -> Result { + super::validate_tag(program_id, account, TAG_OPERATOR_BALANCE)?; + + Ok(Self { account }) + } + + pub fn try_from_account( + program_id: &Pubkey, + account: &'a AccountInfo<'a>, + ) -> Result> { + if system_program::check_id(account.owner) { + Ok(None) + } else { + let balance = Self::from_account(program_id, account)?; + Ok(Some(balance)) + } + } + + pub fn create( + address: Address, + chain_id: u64, + account: &'a AccountInfo<'a>, + operator: &Operator<'a>, + system: &program::System<'a>, + rent: &Rent, + ) -> Result { + let (pubkey, bump_seed) = address.find_operator_address(&crate::ID, chain_id, operator); + + if account.key != &pubkey { + return Err(Error::AccountInvalidKey(*account.key, pubkey)); + } + + // Already created. Return immidiately + if !system_program::check_id(account.owner) { + let balance_account = Self::from_account(&crate::ID, account)?; + assert_eq!(balance_account.address(), address); + assert_eq!(balance_account.chain_id(), chain_id); + assert_eq!(balance_account.owner(), *operator.key); + + return Ok(balance_account); + } + + // Create a new account + let program_seeds: &[&[u8]] = &[ + &[ACCOUNT_SEED_VERSION], + operator.key.as_ref(), + address.as_bytes(), + &U256::from(chain_id).to_be_bytes(), + &[bump_seed], + ]; + + system.create_pda_account( + &crate::ID, + operator, + account, + program_seeds, + Self::required_account_size(), + rent, + )?; + + super::set_tag(&crate::ID, account, TAG_OPERATOR_BALANCE, Header::VERSION)?; + { + let mut header = super::header_mut::
(account); + header.owner = *operator.key; + header.address = address; + header.chain_id = chain_id; + header.balance = U256::ZERO; + } + + Ok(Self { account }) + } + + #[must_use] + pub fn pubkey(&self) -> &'a Pubkey { + self.account.key + } + + #[must_use] + pub fn address(&self) -> Address { + let header = super::header::
(self.account); + header.address + } + + #[must_use] + pub fn chain_id(&self) -> u64 { + let header = super::header::
(self.account); + header.chain_id + } + + #[must_use] + pub fn balance(&self) -> U256 { + let header = super::header::
(self.account); + header.balance + } + + #[must_use] + pub fn owner(&self) -> Pubkey { + let header = super::header::
(self.account); + header.owner + } + + pub fn validate_owner(&self, operator: &Operator) -> Result<()> { + let owner = self.owner(); + if &owner != operator.key { + return Err(Error::OperatorBalanceInvalidOwner(owner, *operator.key)); + } + + Ok(()) + } + + pub fn consume_gas(&mut self, source: &mut BalanceAccount, value: U256) -> Result<()> { + if self.chain_id() != source.chain_id() { + return Err(Error::OperatorBalanceInvalidChainId); + } + + source.burn(value)?; + self.mint(value) + } + + pub fn withdraw(&mut self, target: &mut BalanceAccount) -> Result<()> { + if self.chain_id() != target.chain_id() { + return Err(Error::OperatorBalanceInvalidChainId); + } + + if self.address() != target.address() { + return Err(Error::OperatorBalanceInvalidAddress); + } + + let value = self.balance(); + + self.burn(value)?; + target.mint(value) + } + + pub fn burn(&mut self, value: U256) -> Result<()> { + let mut header = super::header_mut::
(self.account); + + header.balance = header + .balance + .checked_sub(value) + .ok_or(Error::InsufficientBalance( + header.address, + header.chain_id, + value, + ))?; + + Ok(()) + } + + pub fn mint(&mut self, value: U256) -> Result<()> { + let mut header = super::header_mut::
(self.account); + + header.balance = header + .balance + .checked_add(value) + .ok_or(Error::IntegerOverflow)?; + + Ok(()) + } + + /// # Safety + /// Permanently deletes Operator Balance account and all data in it + pub unsafe fn suicide(self, operator: &Operator) { + assert_eq!(self.balance(), U256::ZERO); + + crate::account::delete(self.account, operator); + } +} + +pub trait OperatorBalanceValidator { + fn validate(&self, operator: &Operator, trx: &Transaction) -> Result<()> { + self.validate_owner(operator)?; + self.validate_transaction(trx) + } + + fn validate_owner(&self, operator: &Operator) -> Result<()>; + fn validate_transaction(&self, trx: &Transaction) -> Result<()>; + + fn miner(&self, origin: Address) -> Address; +} + +impl OperatorBalanceValidator for Option> { + fn validate_owner(&self, operator: &Operator) -> Result<()> { + let Some(balance) = self else { return Ok(()) }; + balance.validate_owner(operator) + } + + fn validate_transaction(&self, trx: &Transaction) -> Result<()> { + if self.is_none() && (trx.gas_price() != U256::ZERO) { + return Err(Error::OperatorBalanceMissing); + } + + Ok(()) + } + + fn miner(&self, origin: Address) -> Address { + self.as_ref() + .map_or(origin, OperatorBalanceAccount::address) + } +} diff --git a/evm_loader/program/src/account/state.rs b/evm_loader/program/src/account/state.rs index b27a904ff..ec4a52122 100644 --- a/evm_loader/program/src/account/state.rs +++ b/evm_loader/program/src/account/state.rs @@ -11,8 +11,8 @@ use serde::{Deserialize, Serialize}; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; use super::{ - revision, AccountHeader, AccountsDB, BalanceAccount, Holder, StateFinalizedAccount, - ACCOUNT_PREFIX_LEN, TAG_HOLDER, TAG_STATE, TAG_STATE_FINALIZED, + revision, AccountHeader, AccountsDB, BalanceAccount, Holder, OperatorBalanceAccount, + StateFinalizedAccount, ACCOUNT_PREFIX_LEN, TAG_HOLDER, TAG_STATE, TAG_STATE_FINALIZED, }; #[derive(PartialEq, Eq)] @@ -258,14 +258,9 @@ impl<'a> StateAccount<'a> { self.trx().gas_limit().saturating_sub(self.gas_used()) } - pub fn consume_gas(&mut self, amount: U256, receiver: &mut BalanceAccount) -> Result<()> { + fn use_gas(&mut self, amount: U256) -> Result { if amount == U256::ZERO { - return Ok(()); - } - - let trx_chain_id = self.trx().chain_id().unwrap_or(DEFAULT_CHAIN_ID); - if receiver.chain_id() != trx_chain_id { - return Err(Error::GasReceiverInvalidChainId); + return Ok(U256::ZERO); } let total_gas_used = self.data.gas_used.saturating_add(amount); @@ -277,10 +272,29 @@ impl<'a> StateAccount<'a> { self.data.gas_used = total_gas_used; - let tokens = amount + amount .checked_mul(self.trx().gas_price()) - .ok_or(Error::IntegerOverflow)?; - receiver.mint(tokens) + .ok_or(Error::IntegerOverflow) + } + + pub fn consume_gas( + &mut self, + amount: U256, + receiver: Option, + ) -> Result<()> { + let tokens = self.use_gas(amount)?; + if tokens == U256::ZERO { + return Ok(()); + } + + let mut operator_balance = receiver.ok_or(Error::OperatorBalanceMissing)?; + + let trx_chain_id = self.trx().chain_id().unwrap_or(DEFAULT_CHAIN_ID); + if operator_balance.chain_id() != trx_chain_id { + return Err(Error::OperatorBalanceInvalidChainId); + } + + operator_balance.mint(tokens) } pub fn refund_unused_gas(&mut self, origin: &mut BalanceAccount) -> Result<()> { @@ -290,7 +304,8 @@ impl<'a> StateAccount<'a> { assert!(origin.address() == self.trx_origin()); let unused_gas = self.gas_available(); - self.consume_gas(unused_gas, origin) + let tokens = self.use_gas(unused_gas)?; + origin.mint(tokens) } #[must_use] diff --git a/evm_loader/program/src/account_storage/apply.rs b/evm_loader/program/src/account_storage/apply.rs index 7265c1784..2ae41b9c9 100644 --- a/evm_loader/program/src/account_storage/apply.rs +++ b/evm_loader/program/src/account_storage/apply.rs @@ -32,14 +32,17 @@ impl<'a> ProgramAccountStorage<'a> { chain_id: u64, value: U256, ) -> Result<()> { + if value == U256::ZERO { + return Ok(()); + } + let (pubkey, _) = origin.find_balance_address(&crate::ID, chain_id); let source = self.accounts.get(&pubkey).clone(); let mut source = BalanceAccount::from_account(&crate::ID, source)?; - let target = self.accounts.operator_balance(); - - source.transfer(target, value) + let mut target = self.accounts.operator_balance(); + target.consume_gas(&mut source, value) } pub fn allocate(&mut self, actions: &[Action]) -> Result { diff --git a/evm_loader/program/src/account_storage/base.rs b/evm_loader/program/src/account_storage/base.rs index b5f79dee7..e898c5b72 100644 --- a/evm_loader/program/src/account_storage/base.rs +++ b/evm_loader/program/src/account_storage/base.rs @@ -28,10 +28,6 @@ impl<'a> ProgramAccountStorage<'a> { self.accounts.operator() } - pub fn operator_balance(&mut self) -> &mut BalanceAccount<'a> { - self.accounts.operator_balance() - } - pub fn treasury(&self) -> &Treasury<'a> { self.accounts.treasury() } diff --git a/evm_loader/program/src/entrypoint.rs b/evm_loader/program/src/entrypoint.rs index 5d84c72fa..eb075a85a 100644 --- a/evm_loader/program/src/entrypoint.rs +++ b/evm_loader/program/src/entrypoint.rs @@ -166,6 +166,15 @@ fn process_instruction<'a>( EvmInstruction::ConfigGetVersion => { instruction::config_get_version::process(program_id, accounts, instruction) } + EvmInstruction::OperatorBalanceCreate => { + instruction::operator_create_balance::process(program_id, accounts, instruction) + } + EvmInstruction::OperatorBalanceDelete => { + instruction::operator_delete_balance::process(program_id, accounts, instruction) + } + EvmInstruction::OperatorBalanceWithdraw => { + instruction::operator_withdraw_balance::process(program_id, accounts, instruction) + } } .map_err(ProgramError::from) } diff --git a/evm_loader/program/src/error.rs b/evm_loader/program/src/error.rs index 825db02dd..bf88f7e92 100644 --- a/evm_loader/program/src/error.rs +++ b/evm_loader/program/src/error.rs @@ -190,6 +190,18 @@ pub enum Error { #[error("External call fails {0}: {1}")] ExternalCallFailed(Pubkey, String), + + #[error("Operator Balance - invalid owner {0}, expected = {1}")] + OperatorBalanceInvalidOwner(Pubkey, Pubkey), + + #[error("Operator Balance - not found")] + OperatorBalanceMissing, + + #[error("Operator Balance - invalid chainId")] + OperatorBalanceInvalidChainId, + + #[error("Operator Balance - invalid address")] + OperatorBalanceInvalidAddress, } pub type Result = std::result::Result; diff --git a/evm_loader/program/src/instruction/mod.rs b/evm_loader/program/src/instruction/mod.rs index a46695e0d..0875fa568 100644 --- a/evm_loader/program/src/instruction/mod.rs +++ b/evm_loader/program/src/instruction/mod.rs @@ -203,6 +203,10 @@ pub enum EvmInstruction { ConfigGetPropertyByName, ConfigGetStatus, ConfigGetVersion, + + OperatorBalanceCreate, + OperatorBalanceDelete, + OperatorBalanceWithdraw, } impl EvmInstruction { @@ -229,6 +233,10 @@ impl EvmInstruction { 0x38 => Self::TransactionExecuteFromInstructionWithSolanaCall, // 56 0x39 => Self::TransactionExecuteFromAccountWithSolanaCall, // 57 + 0x38 => Self::OperatorBalanceCreate, // 56 + 0x39 => Self::OperatorBalanceDelete, // 57 + 0x3A => Self::OperatorBalanceWithdraw, // 58 + 0xA0 => Self::ConfigGetChainCount, // 160 0xA1 => Self::ConfigGetChainInfo, 0xA2 => Self::ConfigGetEnvironment, @@ -237,6 +245,7 @@ impl EvmInstruction { 0xA5 => Self::ConfigGetPropertyByName, 0xA6 => Self::ConfigGetStatus, 0xA7 => Self::ConfigGetVersion, + _ => return Err(ProgramError::InvalidInstructionData), }) } @@ -257,6 +266,9 @@ pub mod config_get_status; pub mod config_get_version; pub mod create_main_treasury; pub mod neon_tokens_deposit; +pub mod operator_create_balance; +pub mod operator_delete_balance; +pub mod operator_withdraw_balance; pub mod transaction_cancel; pub mod transaction_execute; pub mod transaction_execute_from_account; diff --git a/evm_loader/program/src/instruction/operator_create_balance.rs b/evm_loader/program/src/instruction/operator_create_balance.rs new file mode 100644 index 000000000..fa3a8d10e --- /dev/null +++ b/evm_loader/program/src/instruction/operator_create_balance.rs @@ -0,0 +1,36 @@ +use arrayref::array_ref; +use solana_program::{account_info::AccountInfo, pubkey::Pubkey, rent::Rent, sysvar::Sysvar}; + +use crate::account::{program, Operator, OperatorBalanceAccount}; +use crate::config::CHAIN_ID_LIST; +use crate::error::{Error, Result}; +use crate::types::Address; + +pub fn process<'a>( + _program_id: &'a Pubkey, + accounts: &'a [AccountInfo<'a>], + instruction: &[u8], +) -> Result<()> { + log_msg!("Instruction: Create Operator Balance Account"); + + let operator = unsafe { Operator::from_account_not_whitelisted(&accounts[0]) }?; + let system = program::System::from_account(&accounts[1])?; + let account = &accounts[2]; + + let address = array_ref![instruction, 0, 20]; + let address = Address::from(*address); + + let chain_id = array_ref![instruction, 20, 8]; + let chain_id = u64::from_le_bytes(*chain_id); + + CHAIN_ID_LIST + .binary_search_by_key(&chain_id, |c| c.0) + .map_err(|_| Error::InvalidChainId(chain_id))?; + + log_msg!("Address: {}, ChainID: {}", address, chain_id); + + let rent = Rent::get()?; + OperatorBalanceAccount::create(address, chain_id, account, &operator, &system, &rent)?; + + Ok(()) +} diff --git a/evm_loader/program/src/instruction/operator_delete_balance.rs b/evm_loader/program/src/instruction/operator_delete_balance.rs new file mode 100644 index 000000000..2b0ee3669 --- /dev/null +++ b/evm_loader/program/src/instruction/operator_delete_balance.rs @@ -0,0 +1,22 @@ +use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; + +use crate::account::{Operator, OperatorBalanceAccount}; +use crate::error::Result; + +pub fn process<'a>( + program_id: &'a Pubkey, + accounts: &'a [AccountInfo<'a>], + _instruction: &[u8], +) -> Result<()> { + log_msg!("Instruction: Delete Operator Balance Account"); + + let operator = unsafe { Operator::from_account_not_whitelisted(&accounts[0]) }?; + let operator_balance = OperatorBalanceAccount::from_account(program_id, &accounts[1])?; + + operator_balance.validate_owner(&operator)?; + unsafe { + operator_balance.suicide(&operator); + } + + Ok(()) +} diff --git a/evm_loader/program/src/instruction/operator_withdraw_balance.rs b/evm_loader/program/src/instruction/operator_withdraw_balance.rs new file mode 100644 index 000000000..935efa439 --- /dev/null +++ b/evm_loader/program/src/instruction/operator_withdraw_balance.rs @@ -0,0 +1,19 @@ +use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; + +use crate::account::{BalanceAccount, Operator, OperatorBalanceAccount}; +use crate::error::Result; + +pub fn process<'a>( + program_id: &'a Pubkey, + accounts: &'a [AccountInfo<'a>], + _instruction: &[u8], +) -> Result<()> { + log_msg!("Instruction: Withdraw Operator Balance Account"); + + let operator = unsafe { Operator::from_account_not_whitelisted(&accounts[0]) }?; + let mut operator_balance = OperatorBalanceAccount::from_account(program_id, &accounts[1])?; + let mut target_balance = BalanceAccount::from_account(program_id, accounts[2].clone())?; + + operator_balance.validate_owner(&operator)?; + operator_balance.withdraw(&mut target_balance) +} diff --git a/evm_loader/program/src/instruction/transaction_cancel.rs b/evm_loader/program/src/instruction/transaction_cancel.rs index 489685363..74944f799 100644 --- a/evm_loader/program/src/instruction/transaction_cancel.rs +++ b/evm_loader/program/src/instruction/transaction_cancel.rs @@ -1,4 +1,4 @@ -use crate::account::{AccountsDB, BalanceAccount, Operator, StateAccount}; +use crate::account::{AccountsDB, BalanceAccount, Operator, OperatorBalanceAccount, StateAccount}; use crate::config::DEFAULT_CHAIN_ID; use crate::debug::log_data; use crate::error::{Error, Result}; @@ -18,7 +18,9 @@ pub fn process<'a>( let storage_info = accounts[0].clone(); let operator = Operator::from_account(&accounts[1])?; - let operator_balance = BalanceAccount::from_account(program_id, accounts[2].clone())?; + let operator_balance = OperatorBalanceAccount::from_account(program_id, &accounts[2])?; + + operator_balance.validate_owner(&operator)?; log_data(&[b"HASH", transaction_hash]); log_data(&[b"MINER", operator_balance.address().as_bytes()]); @@ -43,7 +45,7 @@ fn validate(storage: &StateAccount, transaction_hash: &[u8; 32]) -> Result<()> { fn execute<'a>( program_id: &Pubkey, - mut accounts: AccountsDB<'a>, + accounts: AccountsDB<'a>, mut storage: StateAccount<'a>, ) -> Result<()> { let trx_chain_id = storage.trx().chain_id().unwrap_or(DEFAULT_CHAIN_ID); @@ -57,7 +59,7 @@ fn execute<'a>( ]); let gas = U256::from(CANCEL_TRX_COST + LAST_ITERATION_COST); - let _ = storage.consume_gas(gas, accounts.operator_balance()); // ignore error + let _ = storage.consume_gas(gas, accounts.try_operator_balance()); // ignore error let origin = storage.trx_origin(); let (origin_pubkey, _) = origin.find_balance_address(program_id, trx_chain_id); diff --git a/evm_loader/program/src/instruction/transaction_execute_from_account.rs b/evm_loader/program/src/instruction/transaction_execute_from_account.rs index 7d7ad6c2d..18cf02532 100644 --- a/evm_loader/program/src/instruction/transaction_execute_from_account.rs +++ b/evm_loader/program/src/instruction/transaction_execute_from_account.rs @@ -1,4 +1,7 @@ -use crate::account::{program, AccountsDB, BalanceAccount, Holder, Operator, Treasury}; +use crate::account::{ + program, AccountsDB, Holder, Operator, OperatorBalanceAccount, OperatorBalanceValidator, + Treasury, +}; use crate::debug::log_data; use crate::error::Result; use crate::gasometer::Gasometer; @@ -21,7 +24,7 @@ pub fn process<'a>( let operator = unsafe { Operator::from_account_not_whitelisted(&accounts[1])? }; let treasury = Treasury::from_account(program_id, treasury_index, &accounts[2])?; - let operator_balance = BalanceAccount::from_account(program_id, accounts[3].clone())?; + let operator_balance = OperatorBalanceAccount::try_from_account(program_id, &accounts[3])?; let system = program::System::from_account(&accounts[4])?; holder.validate_owner(&operator)?; @@ -30,13 +33,17 @@ pub fn process<'a>( let origin = trx.recover_caller_address()?; + operator_balance.validate_owner(&operator)?; + operator_balance.validate_transaction(&trx)?; + let miner_address = operator_balance.miner(origin); + log_data(&[b"HASH", &trx.hash()]); - log_data(&[b"MINER", operator_balance.address().as_bytes()]); + log_data(&[b"MINER", miner_address.as_bytes()]); let accounts_db = AccountsDB::new( &accounts[5..], operator, - Some(operator_balance), + operator_balance, Some(system), Some(treasury), ); diff --git a/evm_loader/program/src/instruction/transaction_execute_from_instruction.rs b/evm_loader/program/src/instruction/transaction_execute_from_instruction.rs index b51d593d8..355179f8a 100644 --- a/evm_loader/program/src/instruction/transaction_execute_from_instruction.rs +++ b/evm_loader/program/src/instruction/transaction_execute_from_instruction.rs @@ -1,4 +1,6 @@ -use crate::account::{program, AccountsDB, BalanceAccount, Operator, Treasury}; +use crate::account::{ + program, AccountsDB, Operator, OperatorBalanceAccount, OperatorBalanceValidator, Treasury, +}; use crate::debug::log_data; use crate::error::Result; use crate::gasometer::Gasometer; @@ -20,19 +22,23 @@ pub fn process<'a>( let operator = unsafe { Operator::from_account_not_whitelisted(&accounts[0])? }; let treasury = Treasury::from_account(program_id, treasury_index, &accounts[1])?; - let operator_balance = BalanceAccount::from_account(program_id, accounts[2].clone())?; + let operator_balance = OperatorBalanceAccount::try_from_account(program_id, &accounts[2])?; let system = program::System::from_account(&accounts[3])?; let trx = Transaction::from_rlp(messsage)?; let origin = trx.recover_caller_address()?; + operator_balance.validate_owner(&operator)?; + operator_balance.validate_transaction(&trx)?; + let miner_address = operator_balance.miner(origin); + log_data(&[b"HASH", &trx.hash()]); - log_data(&[b"MINER", operator_balance.address().as_bytes()]); + log_data(&[b"MINER", miner_address.as_bytes()]); let accounts_db = AccountsDB::new( &accounts[4..], operator, - Some(operator_balance), + operator_balance, Some(system), Some(treasury), ); diff --git a/evm_loader/program/src/instruction/transaction_step.rs b/evm_loader/program/src/instruction/transaction_step.rs index ca56888bb..7f9dd0b65 100644 --- a/evm_loader/program/src/instruction/transaction_step.rs +++ b/evm_loader/program/src/instruction/transaction_step.rs @@ -132,7 +132,7 @@ fn finalize<'a>( &total_used_gas.to_le_bytes(), ]); - storage.consume_gas(used_gas, accounts.operator_balance())?; + storage.consume_gas(used_gas, accounts.db().try_operator_balance())?; if let Some(status) = status { log_return_value(&status); diff --git a/evm_loader/program/src/instruction/transaction_step_from_account.rs b/evm_loader/program/src/instruction/transaction_step_from_account.rs index 4cc712ba7..fac16e504 100644 --- a/evm_loader/program/src/instruction/transaction_step_from_account.rs +++ b/evm_loader/program/src/instruction/transaction_step_from_account.rs @@ -1,7 +1,7 @@ use crate::account::legacy::{TAG_HOLDER_DEPRECATED, TAG_STATE_FINALIZED_DEPRECATED}; use crate::account::{ - program, AccountsDB, AccountsStatus, BalanceAccount, Holder, Operator, StateAccount, Treasury, - TAG_HOLDER, TAG_STATE, TAG_STATE_FINALIZED, + program, AccountsDB, AccountsStatus, Holder, Operator, OperatorBalanceAccount, + OperatorBalanceValidator, StateAccount, Treasury, TAG_HOLDER, TAG_STATE, TAG_STATE_FINALIZED, }; use crate::debug::log_data; use crate::error::{Error, Result}; @@ -35,15 +35,15 @@ pub fn process_inner<'a>( let operator = Operator::from_account(&accounts[1])?; let treasury = Treasury::from_account(program_id, treasury_index, &accounts[2])?; - let operator_balance = BalanceAccount::from_account(program_id, accounts[3].clone())?; + let operator_balance = OperatorBalanceAccount::try_from_account(program_id, &accounts[3])?; let system = program::System::from_account(&accounts[4])?; - let miner_address = operator_balance.address(); + operator_balance.validate_owner(&operator)?; let accounts_db = AccountsDB::new( &accounts[5..], operator.clone(), - Some(operator_balance), + operator_balance.clone(), Some(system), Some(treasury), ); @@ -59,7 +59,7 @@ pub fn process_inner<'a>( TAG_HOLDER | TAG_HOLDER_DEPRECATED => { let mut trx = { let holder = Holder::from_account(program_id, holder_or_storage.clone())?; - holder.validate_owner(accounts_db.operator())?; + holder.validate_owner(&operator)?; let message = holder.transaction(); let trx = Transaction::from_rlp(&message)?; @@ -68,6 +68,10 @@ pub fn process_inner<'a>( trx }; + let origin = trx.recover_caller_address()?; + + operator_balance.validate_transaction(&trx)?; + let miner_address = operator_balance.miner(origin); log_data(&[b"HASH", &trx.hash]); log_data(&[b"MINER", miner_address.as_bytes()]); @@ -77,9 +81,7 @@ pub fn process_inner<'a>( trx.use_gas_limit_multiplier(); } - let origin = trx.recover_caller_address()?; - - let mut gasometer = Gasometer::new(U256::ZERO, accounts_db.operator())?; + let mut gasometer = Gasometer::new(U256::ZERO, &operator)?; gasometer.record_solana_transaction_cost(); gasometer.record_address_lookup_table(accounts); gasometer.record_write_to_holder(&trx); @@ -101,10 +103,13 @@ pub fn process_inner<'a>( let (storage, accounts_status) = StateAccount::restore(program_id, holder_or_storage.clone(), &accounts_db)?; + operator_balance.validate_transaction(storage.trx())?; + let miner_address = operator_balance.miner(storage.trx_origin()); + log_data(&[b"HASH", &storage.trx().hash()]); log_data(&[b"MINER", miner_address.as_bytes()]); - let mut gasometer = Gasometer::new(storage.gas_used(), accounts_db.operator())?; + let mut gasometer = Gasometer::new(storage.gas_used(), &operator)?; gasometer.record_solana_transaction_cost(); let reset = accounts_status != AccountsStatus::Ok; diff --git a/evm_loader/program/src/instruction/transaction_step_from_instruction.rs b/evm_loader/program/src/instruction/transaction_step_from_instruction.rs index adc2b7ae6..798a0942f 100644 --- a/evm_loader/program/src/instruction/transaction_step_from_instruction.rs +++ b/evm_loader/program/src/instruction/transaction_step_from_instruction.rs @@ -1,7 +1,7 @@ use crate::account::legacy::{TAG_HOLDER_DEPRECATED, TAG_STATE_FINALIZED_DEPRECATED}; use crate::account::{ - program, AccountsDB, AccountsStatus, BalanceAccount, Operator, StateAccount, Treasury, - TAG_HOLDER, TAG_STATE, TAG_STATE_FINALIZED, + program, AccountsDB, AccountsStatus, Operator, OperatorBalanceAccount, + OperatorBalanceValidator, StateAccount, Treasury, TAG_HOLDER, TAG_STATE, TAG_STATE_FINALIZED, }; use crate::debug::log_data; use crate::error::{Error, Result}; @@ -28,15 +28,15 @@ pub fn process<'a>( let operator = Operator::from_account(&accounts[1])?; let treasury = Treasury::from_account(program_id, treasury_index, &accounts[2])?; - let operator_balance = BalanceAccount::from_account(program_id, accounts[3].clone())?; + let operator_balance = OperatorBalanceAccount::try_from_account(program_id, &accounts[3])?; let system = program::System::from_account(&accounts[4])?; - let miner_address = operator_balance.address(); + operator_balance.validate_owner(&operator)?; let accounts_db = AccountsDB::new( &accounts[5..], operator.clone(), - Some(operator_balance), + operator_balance.clone(), Some(system), Some(treasury), ); @@ -53,10 +53,13 @@ pub fn process<'a>( let trx = Transaction::from_rlp(message)?; let origin = trx.recover_caller_address()?; + operator_balance.validate_transaction(&trx)?; + let miner_address = operator_balance.miner(origin); + log_data(&[b"HASH", &trx.hash()]); log_data(&[b"MINER", miner_address.as_bytes()]); - let mut gasometer = Gasometer::new(U256::ZERO, accounts_db.operator())?; + let mut gasometer = Gasometer::new(U256::ZERO, &operator)?; gasometer.record_solana_transaction_cost(); gasometer.record_address_lookup_table(accounts); @@ -71,10 +74,13 @@ pub fn process<'a>( let (storage, accounts_status) = StateAccount::restore(program_id, storage_info, &accounts_db)?; + operator_balance.validate_transaction(storage.trx())?; + let miner_address = operator_balance.miner(storage.trx_origin()); + log_data(&[b"HASH", &storage.trx().hash()]); log_data(&[b"MINER", miner_address.as_bytes()]); - let mut gasometer = Gasometer::new(storage.gas_used(), accounts_db.operator())?; + let mut gasometer = Gasometer::new(storage.gas_used(), &operator)?; gasometer.record_solana_transaction_cost(); let reset = accounts_status != AccountsStatus::Ok; diff --git a/evm_loader/program/src/types/address.rs b/evm_loader/program/src/types/address.rs index 8d16b5c0c..48ea697a1 100644 --- a/evm_loader/program/src/types/address.rs +++ b/evm_loader/program/src/types/address.rs @@ -6,7 +6,7 @@ use std::convert::{From, TryInto}; use std::fmt::{Debug, Display}; use std::str::FromStr; -use crate::account::ACCOUNT_SEED_VERSION; +use crate::account::{Operator, ACCOUNT_SEED_VERSION}; use crate::error::Error; #[repr(transparent)] @@ -66,6 +66,24 @@ impl Address { let seeds: &[&[u8]] = &[&[ACCOUNT_SEED_VERSION], &self.0, &chain_id.to_be_bytes()]; Pubkey::find_program_address(seeds, program_id) } + + #[must_use] + pub fn find_operator_address( + &self, + program_id: &Pubkey, + chain_id: u64, + operator: &Operator, + ) -> (Pubkey, u8) { + let chain_id = U256::from(chain_id); + + let seeds: &[&[u8]] = &[ + &[ACCOUNT_SEED_VERSION], + operator.key.as_ref(), + &self.0, + &chain_id.to_be_bytes(), + ]; + Pubkey::find_program_address(seeds, program_id) + } } impl FromStr for Address { From 3b24f4eb0ea85a306c6c80da3dcb1cdf48afa12d Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Mon, 8 Apr 2024 09:32:52 +0300 Subject: [PATCH 196/318] Remove cancel_trx from neon-cli --- evm_loader/cli/src/main.rs | 14 +---- evm_loader/cli/src/program_options.rs | 13 ----- evm_loader/lib/src/commands/cancel_trx.rs | 63 ----------------------- evm_loader/lib/src/commands/mod.rs | 1 - 4 files changed, 2 insertions(+), 89 deletions(-) delete mode 100644 evm_loader/lib/src/commands/cancel_trx.rs diff --git a/evm_loader/cli/src/main.rs b/evm_loader/cli/src/main.rs index c134bfd53..17695ec1b 100644 --- a/evm_loader/cli/src/main.rs +++ b/evm_loader/cli/src/main.rs @@ -9,8 +9,8 @@ mod program_options; use neon_lib::{ commands::{ - cancel_trx, collect_treasury, emulate, get_balance, get_config, get_contract, get_holder, - get_neon_elf, get_storage_at, init_environment, trace, + collect_treasury, emulate, get_balance, get_config, get_contract, get_holder, get_neon_elf, + get_storage_at, init_environment, trace, }, rpc::CloneRpcClient, types::{BalanceAddress, EmulateRequest}, @@ -90,16 +90,6 @@ async fn run(options: &ArgMatches<'_>) -> NeonCliResult { .await .map(|result| json!(result)) } - ("cancel-trx", Some(params)) => { - let rpc_client = CloneRpcClient::new_from_config(config); - let signer = build_signer(config)?; - - let storage_account = - pubkey_of(params, "storage_account").expect("storage_account parse error"); - cancel_trx::execute(rpc_client, &*signer, config.evm_loader, &storage_account) - .await - .map(|result| json!(result)) - } ("neon-elf-params", Some(params)) => { let rpc = build_rpc(options, config).await?; diff --git a/evm_loader/cli/src/program_options.rs b/evm_loader/cli/src/program_options.rs index b6ad7810b..05c223de2 100644 --- a/evm_loader/cli/src/program_options.rs +++ b/evm_loader/cli/src/program_options.rs @@ -214,19 +214,6 @@ pub fn parse<'a>() -> ArgMatches<'a> { .help("Public Key"), ) ) - .subcommand( - SubCommand::with_name("cancel-trx") - .about("Cancel NEON transaction") - .arg( - Arg::with_name("storage_account") - .index(1) - .value_name("STORAGE_ACCOUNT") - .takes_value(true) - .required(true) - .validator(is_valid_pubkey) - .help("storage account for transaction"), - ) - ) .subcommand( SubCommand::with_name("neon-elf-params") .about("Get NEON values stored in elf") diff --git a/evm_loader/lib/src/commands/cancel_trx.rs b/evm_loader/lib/src/commands/cancel_trx.rs deleted file mode 100644 index f68ee6441..000000000 --- a/evm_loader/lib/src/commands/cancel_trx.rs +++ /dev/null @@ -1,63 +0,0 @@ -use evm_loader::account::StateAccount; -use log::info; - -use serde::{Deserialize, Serialize}; -use solana_sdk::{ - instruction::{AccountMeta, Instruction}, - pubkey::Pubkey, - signature::Signature, - signer::Signer, -}; - -use crate::{ - account_storage::account_info, commands::send_transaction, rpc::CloneRpcClient, NeonResult, -}; - -#[derive(Debug, Serialize, Deserialize)] -pub struct CancelTrxReturn { - pub transaction: Signature, -} - -pub async fn execute( - rpc_client: CloneRpcClient, - signer: &dyn Signer, - program_id: Pubkey, - storage_account: &Pubkey, -) -> NeonResult { - let mut acc = rpc_client.get_account(storage_account).await?; - let storage_info = account_info(storage_account, &mut acc); - let storage = StateAccount::from_account(&program_id, storage_info)?; - - let operator = &signer.pubkey(); - - let default_chain_id = - crate::commands::get_config::read_default_chain_id(&rpc_client, program_id).await?; - let chain_id = storage.trx().chain_id().unwrap_or(default_chain_id); - - let origin = storage.trx_origin(); - let (origin_pubkey, _) = origin.find_balance_address(&program_id, chain_id); - - let mut accounts_meta: Vec = vec![ - AccountMeta::new(*storage_account, false), // State account - AccountMeta::new(*operator, true), // Operator - AccountMeta::new(origin_pubkey, false), - ]; - - for key in storage.accounts() { - let meta = AccountMeta::new(*key, true); - info!("\t{:?}", meta); - - accounts_meta.push(meta); - } - - let cancel_with_nonce_instruction = - Instruction::new_with_bincode(program_id, &(0x37_u8, storage.trx().hash()), accounts_meta); - - let instructions = vec![cancel_with_nonce_instruction]; - - let signature = send_transaction(&rpc_client, signer, &instructions).await?; - - Ok(CancelTrxReturn { - transaction: signature, - }) -} diff --git a/evm_loader/lib/src/commands/mod.rs b/evm_loader/lib/src/commands/mod.rs index 1749e5ddc..7cf084b97 100644 --- a/evm_loader/lib/src/commands/mod.rs +++ b/evm_loader/lib/src/commands/mod.rs @@ -11,7 +11,6 @@ use solana_sdk::{ transaction::Transaction, }; -pub mod cancel_trx; pub mod collect_treasury; pub mod emulate; pub mod get_balance; From abab063b410eb1c633e4ac7f34eec2c912c9c73c Mon Sep 17 00:00:00 2001 From: Andrey Falaleev Date: Fri, 17 May 2024 00:48:41 +0100 Subject: [PATCH 197/318] Add suport of operator balances to instructions with Solana calls --- evm_loader/program/src/instruction/mod.rs | 6 +++--- ...transaction_execute_from_account_solana_call.rs | 14 ++++++++++---- ...saction_execute_from_instruction_solana_call.rs | 14 ++++++++++---- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/evm_loader/program/src/instruction/mod.rs b/evm_loader/program/src/instruction/mod.rs index 0875fa568..0159d1928 100644 --- a/evm_loader/program/src/instruction/mod.rs +++ b/evm_loader/program/src/instruction/mod.rs @@ -233,9 +233,9 @@ impl EvmInstruction { 0x38 => Self::TransactionExecuteFromInstructionWithSolanaCall, // 56 0x39 => Self::TransactionExecuteFromAccountWithSolanaCall, // 57 - 0x38 => Self::OperatorBalanceCreate, // 56 - 0x39 => Self::OperatorBalanceDelete, // 57 - 0x3A => Self::OperatorBalanceWithdraw, // 58 + 0x3A => Self::OperatorBalanceCreate, // 58 + 0x3B => Self::OperatorBalanceDelete, // 59 + 0x3C => Self::OperatorBalanceWithdraw, // 60 0xA0 => Self::ConfigGetChainCount, // 160 0xA1 => Self::ConfigGetChainInfo, diff --git a/evm_loader/program/src/instruction/transaction_execute_from_account_solana_call.rs b/evm_loader/program/src/instruction/transaction_execute_from_account_solana_call.rs index 95fa8019a..3cd60c6b1 100644 --- a/evm_loader/program/src/instruction/transaction_execute_from_account_solana_call.rs +++ b/evm_loader/program/src/instruction/transaction_execute_from_account_solana_call.rs @@ -1,4 +1,7 @@ -use crate::account::{program, AccountsDB, BalanceAccount, Holder, Operator, Treasury}; +use crate::account::{ + program, AccountsDB, Holder, Operator, OperatorBalanceAccount, OperatorBalanceValidator, + Treasury, +}; use crate::debug::log_data; use crate::error::Result; use crate::gasometer::Gasometer; @@ -21,7 +24,7 @@ pub fn process<'a>( let operator = unsafe { Operator::from_account_not_whitelisted(&accounts[1])? }; let treasury = Treasury::from_account(program_id, treasury_index, &accounts[2])?; - let operator_balance = BalanceAccount::from_account(program_id, accounts[3].clone())?; + let operator_balance = OperatorBalanceAccount::try_from_account(program_id, &accounts[3])?; let system = program::System::from_account(&accounts[4])?; holder.validate_owner(&operator)?; @@ -29,14 +32,17 @@ pub fn process<'a>( holder.validate_transaction(&trx)?; let origin = trx.recover_caller_address()?; + operator_balance.validate_owner(&operator)?; + operator_balance.validate_transaction(&trx)?; + let miner_address = operator_balance.miner(origin); log_data(&[b"HASH", &trx.hash()]); - log_data(&[b"MINER", operator_balance.address().as_bytes()]); + log_data(&[b"MINER", miner_address.as_bytes()]); let accounts_db = AccountsDB::new( &accounts[5..], operator, - Some(operator_balance), + operator_balance, Some(system), Some(treasury), ); diff --git a/evm_loader/program/src/instruction/transaction_execute_from_instruction_solana_call.rs b/evm_loader/program/src/instruction/transaction_execute_from_instruction_solana_call.rs index 3bae7620f..46c3b8a3d 100644 --- a/evm_loader/program/src/instruction/transaction_execute_from_instruction_solana_call.rs +++ b/evm_loader/program/src/instruction/transaction_execute_from_instruction_solana_call.rs @@ -1,4 +1,6 @@ -use crate::account::{program, AccountsDB, BalanceAccount, Operator, Treasury}; +use crate::account::{ + program, AccountsDB, Operator, OperatorBalanceAccount, OperatorBalanceValidator, Treasury, +}; use crate::debug::log_data; use crate::error::Result; use crate::gasometer::Gasometer; @@ -20,19 +22,23 @@ pub fn process<'a>( let operator = unsafe { Operator::from_account_not_whitelisted(&accounts[0])? }; let treasury = Treasury::from_account(program_id, treasury_index, &accounts[1])?; - let operator_balance = BalanceAccount::from_account(program_id, accounts[2].clone())?; + let operator_balance = OperatorBalanceAccount::try_from_account(program_id, &accounts[2])?; let system = program::System::from_account(&accounts[3])?; let trx = Transaction::from_rlp(messsage)?; let origin = trx.recover_caller_address()?; + operator_balance.validate_owner(&operator)?; + operator_balance.validate_transaction(&trx)?; + let miner_address = operator_balance.miner(origin); + log_data(&[b"HASH", &trx.hash()]); - log_data(&[b"MINER", operator_balance.address().as_bytes()]); + log_data(&[b"MINER", miner_address.as_bytes()]); let accounts_db = AccountsDB::new( &accounts[4..], operator, - Some(operator_balance), + operator_balance, Some(system), Some(treasury), ); From 0bc93bd9dbc36f49581cf10c51b7498b173ca479 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 May 2024 17:44:42 +0300 Subject: [PATCH 198/318] Bump anyhow from 1.0.82 to 1.0.83 in /evm_loader (#421) Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.82 to 1.0.83. - [Release notes](https://github.com/dtolnay/anyhow/releases) - [Commits](https://github.com/dtolnay/anyhow/compare/1.0.82...1.0.83) --- updated-dependencies: - dependency-name: anyhow dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index aaf0d60f1..f1ea5a87d 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -381,9 +381,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.82" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519" +checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" [[package]] name = "ark-bn254" From 287d8969405d10215d2ea484f96eb179c8dc919d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 May 2024 17:55:49 +0300 Subject: [PATCH 199/318] Bump serde from 1.0.201 to 1.0.202 in /evm_loader (#424) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.201 to 1.0.202. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.201...v1.0.202) --- updated-dependencies: - dependency-name: serde dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 8 ++++---- evm_loader/api/Cargo.toml | 2 +- evm_loader/cli/Cargo.toml | 2 +- evm_loader/lib-interface/Cargo.toml | 2 +- evm_loader/program/Cargo.toml | 2 +- evm_loader/rpc-client/Cargo.toml | 2 +- evm_loader/rpc/Cargo.toml | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index f1ea5a87d..fe7e4ac70 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -4652,9 +4652,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.201" +version = "1.0.202" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" +checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" dependencies = [ "serde_derive", ] @@ -4670,9 +4670,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.201" +version = "1.0.202" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" +checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" dependencies = [ "proc-macro2", "quote", diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index d7e7bf3c8..459b8fef6 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -10,7 +10,7 @@ clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } solana-sdk.workspace = true solana-client.workspace = true -serde = "1.0.201" +serde = "1.0.202" serde_json = { version = "1.0.115", features = ["preserve_order"] } ethnum = { version = "1.5", default-features = false, features = ["serde"] } tokio = { version = "1", features = ["full"] } diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index abb2cf256..fa9b0dd4f 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -13,7 +13,7 @@ solana-client.workspace = true solana-clap-utils.workspace = true solana-cli-config.workspace = true hex = "0.4.2" -serde = "1.0.201" +serde = "1.0.202" serde_json = { version = "1.0.115", features = ["preserve_order"] } log = "0.4.21" fern = "0.6" diff --git a/evm_loader/lib-interface/Cargo.toml b/evm_loader/lib-interface/Cargo.toml index 25b2f2866..efd4af896 100644 --- a/evm_loader/lib-interface/Cargo.toml +++ b/evm_loader/lib-interface/Cargo.toml @@ -9,5 +9,5 @@ edition = "2021" abi_stable = "0.11.1" thiserror = "1" async-ffi = { version = "0.5.0", features = ["abi_stable"] } -serde = "1.0.201" +serde = "1.0.202" serde_json = "1.0.115" diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 3faab3a24..d25dbf3e9 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -50,7 +50,7 @@ static_assertions = "1" borsh = "0.10" bincode = "1" serde_bytes = "0.11.14" -serde = { version = "1.0.201", default-features = false, features = ["derive", "rc"] } +serde = { version = "1.0.202", default-features = false, features = ["derive", "rc"] } ethnum = { version = "1.5", default-features = false, features = ["serde"] } cfg-if = { version = "1.0" } log = { version = "0.4", default-features = false, optional = true } diff --git a/evm_loader/rpc-client/Cargo.toml b/evm_loader/rpc-client/Cargo.toml index eef1e13e9..4171eb9f6 100644 --- a/evm_loader/rpc-client/Cargo.toml +++ b/evm_loader/rpc-client/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -serde = "1.0.201" +serde = "1.0.202" serde_json = "1.0.115" neon-lib = { path = "../lib" } thiserror = "1.0.58" diff --git a/evm_loader/rpc/Cargo.toml b/evm_loader/rpc/Cargo.toml index 35f39dd6c..29b248823 100644 --- a/evm_loader/rpc/Cargo.toml +++ b/evm_loader/rpc/Cargo.toml @@ -12,7 +12,7 @@ jsonrpc-v2 = "0.13.0" neon-lib-interface = { path = "../lib-interface" } neon-lib = { path = "../lib" } semver = "1.0.23" -serde = "1.0.201" +serde = "1.0.202" serde_json = "1.0.115" tokio = { version = "1", features = ["full"] } build-info = { version = "0.0.31", features = ["serde"] } From 12f3a23ec7531bc3e850b0ef025d716a9790ebb6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 May 2024 15:51:31 +0300 Subject: [PATCH 200/318] Bump anyhow from 1.0.83 to 1.0.86 in /evm_loader (#428) Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.83 to 1.0.86. - [Release notes](https://github.com/dtolnay/anyhow/releases) - [Commits](https://github.com/dtolnay/anyhow/compare/1.0.83...1.0.86) --- updated-dependencies: - dependency-name: anyhow dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index fe7e4ac70..f2556ddb2 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -381,9 +381,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.83" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "ark-bn254" From 05cd085a3e0bd0d2b6b223fc4c38880edf6eda9c Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Wed, 22 May 2024 10:53:25 +0300 Subject: [PATCH 201/318] NDEV-3047: Update Solana to v1.17.34 (#431) --- .github/workflows/deploy.py | 4 +- evm_loader/Cargo.lock | 188 ++++++++++++++++++------------------ evm_loader/Cargo.toml | 18 ++-- 3 files changed, 105 insertions(+), 105 deletions(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index c4909e0a7..b825d1534 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -32,8 +32,8 @@ IMAGE_NAME = os.environ.get("IMAGE_NAME") RUN_LINK_REPO = os.environ.get("RUN_LINK_REPO") DOCKERHUB_ORG_NAME = os.environ.get("DOCKERHUB_ORG_NAME") -SOLANA_NODE_VERSION = 'v1.17.33' -SOLANA_BPF_VERSION = 'v1.17.33' +SOLANA_NODE_VERSION = 'v1.17.34' +SOLANA_BPF_VERSION = 'v1.17.34' VERSION_BRANCH_TEMPLATE = r"[vt]{1}\d{1,2}\.\d{1,2}\.x.*" docker_client = docker.APIClient() diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index f2556ddb2..806900951 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -4956,9 +4956,9 @@ dependencies = [ [[package]] name = "solana-account-decoder" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed136199e67867bea960ab65895e150b0f767b1f6d9e7093a62a875f7f33d207" +checksum = "1a9721ff8b83683cb7dd856079cde8a8010bfd282d482699a867ad50ea9e727e" dependencies = [ "Inflector", "base64 0.21.7", @@ -4981,9 +4981,9 @@ dependencies = [ [[package]] name = "solana-accounts-db" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb104530ea601d2dad1232449589c6198e26e70c1c9d0be1fb0ba1a40a546df" +checksum = "7cdae5f9d2562360bd07fde58976f6ff8f7d90c8311bc5a4959edd7ba61ccec4" dependencies = [ "arrayref", "bincode", @@ -5040,9 +5040,9 @@ dependencies = [ [[package]] name = "solana-address-lookup-table-program" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5152bcbdcd1dd698cd3182ce4e810f6f4ff18ce3260e934005dba4c5d53293db" +checksum = "c471a3f150762652b5d77f83432b8574738e621fae4885c47132cfe33676d27c" dependencies = [ "bincode", "bytemuck", @@ -5061,9 +5061,9 @@ dependencies = [ [[package]] name = "solana-bpf-loader-program" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60bdb8a5c42a514b00605ec184870aee7230a0610b46d56aa19e8a77928a0d80" +checksum = "0a99a75cdd7d4e40b51d8de8125f3d44db3f7735d96f4e3f31ee79d3110a8f4d" dependencies = [ "bincode", "byteorder", @@ -5080,9 +5080,9 @@ dependencies = [ [[package]] name = "solana-bucket-map" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bee6b54dc14d1cdf80334934745ae5011dda936cdcd5316b9d393a912dc2132" +checksum = "9830a7dbea75c0cbd62a4ca31bcd9b8832fbdb915c949740a44a496630fb5eb6" dependencies = [ "bv", "bytemuck", @@ -5098,9 +5098,9 @@ dependencies = [ [[package]] name = "solana-clap-utils" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae9cafd23f6641f118dd11148f950309139849b74b28ec9dfafbfa00457761b9" +checksum = "4af0fe4584d7692f24e573b17a5245cfc0d99a4e351b0185dfe02baf52f99864" dependencies = [ "chrono", "clap 2.34.0", @@ -5115,9 +5115,9 @@ dependencies = [ [[package]] name = "solana-cli" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "598d94119670b731a168e72f343260e37e38d221a116db974a6553d4da1be74a" +checksum = "50775240fd486edb16add2664efeda82e4fdb78850ae70b1b2219dcbbf04ef30" dependencies = [ "bincode", "bs58 0.4.0", @@ -5166,9 +5166,9 @@ dependencies = [ [[package]] name = "solana-cli-config" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632f34d4a96028066250b48f4255fa53ab561dab145cc0c2db8f1e403c48e33b" +checksum = "914499b160f7562cbec40d5a688a81028760870e35d22b3061596ebe677409a8" dependencies = [ "dirs-next", "lazy_static", @@ -5182,9 +5182,9 @@ dependencies = [ [[package]] name = "solana-cli-output" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c20066a01daa20b7b31d44318558517ed9e7da1c7e4e017210d2b659fce255f" +checksum = "a32a72324bc9a47a0c72af93bba2fb7530cffab019a67eb24b2b22d81c8de1ce" dependencies = [ "Inflector", "base64 0.21.7", @@ -5209,9 +5209,9 @@ dependencies = [ [[package]] name = "solana-client" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d221979e0ee0f8133e9a02a6a9d54a004c59a6857e9b245e4cb4a7541826a662" +checksum = "250ffcda91bc30c2adcc290c9b7c796f59884f1043ae3bcf3245f05158c7986c" dependencies = [ "async-trait", "bincode", @@ -5242,9 +5242,9 @@ dependencies = [ [[package]] name = "solana-compute-budget-program" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7056e3d37696525e1257090ec9af4ee8667aac3fbda313f801b712b3b5bce11" +checksum = "8703a92306dfdc4760e18db14b2f8b36c9769e5c47f0656bc77355875674e079" dependencies = [ "solana-program-runtime", "solana-sdk", @@ -5252,9 +5252,9 @@ dependencies = [ [[package]] name = "solana-config-program" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e66d677aafa8822aae006cebe3b55587b610541e4f8f4e34987463d0640d05ad" +checksum = "16fd2daba039bad58277ec88143b1fe624f2352d8ccb2a80bba3693de61df440" dependencies = [ "bincode", "chrono", @@ -5266,9 +5266,9 @@ dependencies = [ [[package]] name = "solana-connection-cache" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "716f64f1c9ed455729a8de412b7b3ad200b47997b4f68408a1bb65c2a61ccf80" +checksum = "868e7fb550af97ad6fc283a5628f8ffb6dafd590dc30254163e7c9003f13ceb0" dependencies = [ "async-trait", "bincode", @@ -5288,9 +5288,9 @@ dependencies = [ [[package]] name = "solana-cost-model" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47c669f8432952cfe1fa50a6e26827a4b99a3fdfdff229b218f4882668ea89f0" +checksum = "a3b79a349b86d02948720e4416463d50fd4f828b6a63512e47b497613df0d720" dependencies = [ "lazy_static", "log", @@ -5312,9 +5312,9 @@ dependencies = [ [[package]] name = "solana-faucet" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7b988b2989fa6c0c0ff9feafa0f1e4b2571fb1953e88fcb109112219e5edf4b" +checksum = "64540db924b65d0ffeeaac031eb1a6a99892333714f740f01a5ef718cff01ef1" dependencies = [ "bincode", "byteorder", @@ -5336,9 +5336,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef1d4f626d41690e30273990808709fa189f32d2ab55724870e9dbf03107b8a7" +checksum = "219c484f952f006e37a1a2598aebcc4dcfd48478c03fc2ce2d99787a5c78f248" dependencies = [ "ahash 0.8.5", "blake3", @@ -5366,9 +5366,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi-macro" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b82e46dc5348003a010c8b05b494d800a7cfd5793b3dd843a4d664306fce2edc" +checksum = "ffe4e1dc5fd61ac10c304b3eb8ddb49737b13e975281d623a6083cf5cf0a8616" dependencies = [ "proc-macro2", "quote", @@ -5378,9 +5378,9 @@ dependencies = [ [[package]] name = "solana-loader-v4-program" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "331541db807a0a2bfd29fbc39b2c5f17779d3cc9bc29ea70fe0a719689a2c580" +checksum = "ad035401037e6e7d1dc19c0ae4b613b36632b60443d28716355a4e0041892fa2" dependencies = [ "log", "solana-measure", @@ -5391,9 +5391,9 @@ dependencies = [ [[package]] name = "solana-logger" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be76f972b4863c350a408f112979ee607950640d58c164b3c3437c0fbc347867" +checksum = "64b4f281f2263de6d9cc65680b90b6bd2c93ba7de573db83fc86e2d05ca7ea8c" dependencies = [ "env_logger", "lazy_static", @@ -5402,9 +5402,9 @@ dependencies = [ [[package]] name = "solana-measure" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abd540426200a9bb393de5640ae91c2d39909cefca902e529e6fe20709526cf5" +checksum = "18a3ed981230b6a3a8aebf9f03424f5c1ff98be75cc7f0ecb153879e8e439aea" dependencies = [ "log", "solana-sdk", @@ -5412,9 +5412,9 @@ dependencies = [ [[package]] name = "solana-metrics" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa7fe468cdc1113b181f5958414c897593f484e9feaef35c96f8c26c9d39bbdd" +checksum = "efb65329e6716dc0ce5b1d719d6e0052e7ff1179ab361916f256054d6b846ee1" dependencies = [ "crossbeam-channel", "gethostname", @@ -5427,9 +5427,9 @@ dependencies = [ [[package]] name = "solana-net-utils" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8508f0496a42a469c9ffa9b4e9e81a40bc71b93248a8fa759f27b3e9865208bd" +checksum = "8345ffe2bd2a25a02e5dea046bbbf58f81f6b44ee97224474eae1c0ea03b520a" dependencies = [ "bincode", "clap 3.2.23", @@ -5449,9 +5449,9 @@ dependencies = [ [[package]] name = "solana-perf" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b80387cc3b7e2b0c26c67cdd67e08bc461fccb3f62a363e8e1fc32e8270f64d" +checksum = "0326bd89c2453bf2a408ff676cff4ed0080bff2a5c6543db5f62423bc23ad6e8" dependencies = [ "ahash 0.8.5", "bincode", @@ -5478,9 +5478,9 @@ dependencies = [ [[package]] name = "solana-program" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85f79df075d0cf539285c529a683bb0a8cfe819b9ccefad0c9eb6fe567b3528a" +checksum = "93dc0f422549c23c4464eaa9383f4b09cd92b50dea750731dd3c31d3ee2d310f" dependencies = [ "ark-bn254", "ark-ec", @@ -5532,9 +5532,9 @@ dependencies = [ [[package]] name = "solana-program-runtime" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be80e2669f3659165f389d1049c5f4ca7305be44cd743ef7c79a5aed09635058" +checksum = "8b407440b708ffda97e25b8cb977f72d1bb7466c28ea5f58751613df0af8d576" dependencies = [ "base64 0.21.7", "bincode", @@ -5560,9 +5560,9 @@ dependencies = [ [[package]] name = "solana-pubsub-client" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df12f8912a05adb1672de27d4509e35389bc29a46cf2253ecaf6e3ce76fba09c" +checksum = "1f82da20e0c0bb39f9123cf61a6e3c76a8e30b0f09e5215decfb7f6b54734f04" dependencies = [ "crossbeam-channel", "futures-util", @@ -5585,9 +5585,9 @@ dependencies = [ [[package]] name = "solana-quic-client" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0b3cc12f0dce18f7c020363d876aa9258aa403404afcac29d7cf498c2d0d653" +checksum = "8478a6b4f2c2b8fa330d54ff22386a1792498cb6e84ce3893840337a992e47c6" dependencies = [ "async-mutex", "async-trait", @@ -5612,9 +5612,9 @@ dependencies = [ [[package]] name = "solana-rayon-threadlimit" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5d3a9d5f8e6d4c35f1833c61c3afbe138dded89dc91842176f4734f5e56ee66" +checksum = "8df0aac27af8e94f907f6a65305e0a7909800336e7108bd3ce1dc1f3ef011a20" dependencies = [ "lazy_static", "num_cpus", @@ -5622,9 +5622,9 @@ dependencies = [ [[package]] name = "solana-remote-wallet" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ecaac75eae288354b765125238ce6ecc46b405de2dd8e851e389e2b0c7fa9d2" +checksum = "6a97d60701d3fe0fde4871c5856da9e52ba733fbcfb030482278c3af4ffa0bf3" dependencies = [ "console", "dialoguer", @@ -5642,9 +5642,9 @@ dependencies = [ [[package]] name = "solana-rpc-client" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde5066e74eff9a714122012683f82ea8bf630b0112b9e83104d5685a9f2bf1b" +checksum = "8b750c49be9dd90981f3c12c8357d0b0c847bf5b8c638c3eff3c09f6ea199393" dependencies = [ "async-trait", "base64 0.21.7", @@ -5668,9 +5668,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-api" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f6ebb85cdcdb7c4f20806b29023c4ee5c7cacc0124478a3d309af52997a4773" +checksum = "314d0f87fc7bab16b1b4674c03d4e92c7008fa181b67210780542c0e6cbfce38" dependencies = [ "base64 0.21.7", "bs58 0.4.0", @@ -5690,9 +5690,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-nonce-utils" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20426894bebb53f7b32dc5cf871e58ba381433c2858cb6338d00d4beb68f6cd6" +checksum = "8acf79164ae52ee1ee85cd7aeb1bb715a9f3b90678ee00501896d173dbc31731" dependencies = [ "clap 2.34.0", "solana-clap-utils", @@ -5703,9 +5703,9 @@ dependencies = [ [[package]] name = "solana-runtime" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3790ebeb675aec5576251a7a71b0ab23e3aaa138d24bef0e83e13e8d64ee3a8" +checksum = "0f3dfd09f3cd529ab56b33a1b389b449ddc31b338f062822c7cc30375a2f234b" dependencies = [ "arrayref", "base64 0.21.7", @@ -5780,9 +5780,9 @@ dependencies = [ [[package]] name = "solana-sdk" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e2722c05330a72ba707715861e365d6b38e8bae0c6dc481032bc53b370469b5" +checksum = "3892ee0e2acdfbeae7315db6c7c56356384631deb943377de5957074bd2dc4d1" dependencies = [ "assert_matches", "base64 0.21.7", @@ -5834,9 +5834,9 @@ dependencies = [ [[package]] name = "solana-sdk-macro" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae8907d340ee8f10d6c9e9530db93ead2a82c8e21da95d8f96e0298071faffea" +checksum = "8019cc997f6c07f09b23dfeb2c45530fa94df2e2fb9d654f3c772c9766a1511f" dependencies = [ "bs58 0.4.0", "proc-macro2", @@ -5853,9 +5853,9 @@ checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" [[package]] name = "solana-stake-program" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c574ada0989783887f963d68a4889774d6b5397551c87030eee555a324c5859c" +checksum = "11c21a028ed8abed4a7a52b8410875d799b31b58489653e05ae885e2ba799463" dependencies = [ "bincode", "log", @@ -5868,9 +5868,9 @@ dependencies = [ [[package]] name = "solana-streamer" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b08adda24e6b06d6848bf0376f0641725b29d8c2710d980506c18190299a5b04" +checksum = "067d167db6be6f25c21e4c615607757ae7161b20e08197ec2d1a63360e522069" dependencies = [ "async-channel", "bytes", @@ -5901,9 +5901,9 @@ dependencies = [ [[package]] name = "solana-system-program" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a98b513f36cbc7a0ee120280b968010a958ef4e04e1e282b711a4d117d217c12" +checksum = "a4fa662731817f995cd114ce44d780be2814982a7674540be8d1c596a2d1ca43" dependencies = [ "bincode", "log", @@ -5915,9 +5915,9 @@ dependencies = [ [[package]] name = "solana-thin-client" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f878baf1685d7bf4ccd9edf53a863bde06ece1bb08c8306a3f623c84ee1be951" +checksum = "0815c6d64a4bd71fd92ce33e82c24f5e8a5b105b26619521c4a8a43ab7573a9a" dependencies = [ "bincode", "log", @@ -5930,9 +5930,9 @@ dependencies = [ [[package]] name = "solana-tpu-client" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66a0f44fcaf0fef6f077b03386242d60dad64a861e3dee3d3312f19f194cfb03" +checksum = "576431a39a612dac9387fecb5e80fe58989b740337a07bca41f0d02695e415f9" dependencies = [ "async-trait", "bincode", @@ -5954,9 +5954,9 @@ dependencies = [ [[package]] name = "solana-transaction-status" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb26713d10ecdd8b2524e227736b3a80d2b8105afc17890b2592eaa83005b253" +checksum = "c0d8e2d97a8569afba70a105b402057b253fd9caee92c7ed2c3e1c3e0173fe91" dependencies = [ "Inflector", "base64 0.21.7", @@ -5979,9 +5979,9 @@ dependencies = [ [[package]] name = "solana-udp-client" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0035cd922f58537b4754867ad3f9b0f5428815f4e1835a90b73e89cf17209fe5" +checksum = "8297b04cb335ffac5b4a2c727dd82a2f72c8a96e3d5e1c159e01866b74a17e50" dependencies = [ "async-trait", "solana-connection-cache", @@ -5994,9 +5994,9 @@ dependencies = [ [[package]] name = "solana-version" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f5f943a8bf30efba1fea89a157eaabd6753d6afa8d595b7b1449526a221f8ea" +checksum = "f84a9f9ff3feebfaa960ac5387b133c6ef2c266779cb4932aed6acac5b83cb7b" dependencies = [ "log", "rustc_version", @@ -6010,9 +6010,9 @@ dependencies = [ [[package]] name = "solana-vote" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14e09c7281abdba4a8cab1f413feaafaa8599a5d4eafa6c37790214f1531c11a" +checksum = "f8a2355a2b40d7b0b3a9ec5a5bd2196494c620a287ce6e4234cc4722fcb0cbb5" dependencies = [ "crossbeam-channel", "itertools 0.10.5", @@ -6029,9 +6029,9 @@ dependencies = [ [[package]] name = "solana-vote-program" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d235dd88b21d78bf5a341c7a80a0730ca078bece366305f53fad9dbd7e72c116" +checksum = "5ab0fe8455b2f06016cddefe7e3a7b9c0a57661d44816a4105c81f1088cfc1ac" dependencies = [ "bincode", "log", @@ -6051,9 +6051,9 @@ dependencies = [ [[package]] name = "solana-zk-token-proof-program" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02967e947d0f17d10cc037fdb5e9ffbac90cd1e390270f765e93dabf82f46b38" +checksum = "ad624adcac620e41d052b29705f30c003b2e396ebca0145c1d296a1ef13f5aa7" dependencies = [ "bytemuck", "num-derive 0.3.3", @@ -6065,9 +6065,9 @@ dependencies = [ [[package]] name = "solana-zk-token-sdk" -version = "1.17.33" +version = "1.17.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229fbe8647285712f672ff6f61b32d04158a216c45d9094acecd07446665e791" +checksum = "70a06e103ed5adf1664f9cca3d1c64edad8b5b603255d8a5dd21a4ac5d86b89c" dependencies = [ "aes-gcm-siv", "base64 0.21.7", diff --git a/evm_loader/Cargo.toml b/evm_loader/Cargo.toml index 371b5a7fa..1d77f1316 100644 --- a/evm_loader/Cargo.toml +++ b/evm_loader/Cargo.toml @@ -12,12 +12,12 @@ members = [ ] [workspace.dependencies] -solana-clap-utils = "=1.17.33" -solana-cli = "=1.17.33" -solana-cli-config = "=1.17.33" -solana-client = "=1.17.33" -solana-program = { version = "=1.17.33", default-features = false } -solana-sdk = "=1.17.33" -solana-program-runtime = "=1.17.33" -solana-runtime = "=1.17.33" -solana-accounts-db = "=1.17.33" +solana-clap-utils = "=1.17.34" +solana-cli = "=1.17.34" +solana-cli-config = "=1.17.34" +solana-client = "=1.17.34" +solana-program = { version = "=1.17.34", default-features = false } +solana-sdk = "=1.17.34" +solana-program-runtime = "=1.17.34" +solana-runtime = "=1.17.34" +solana-accounts-db = "=1.17.34" From 003277f319ec46e63a813ba7d546e62b6d986e9e Mon Sep 17 00:00:00 2001 From: Sergei Poletaev Date: Wed, 22 May 2024 15:53:21 +0300 Subject: [PATCH 202/318] Enable clippy warnings as errors across all crates in neon-evm repository (#426) * Treat clippy warnings as errors * Fix clippy errors * Revert "Fix clippy errors" This reverts commit ca344f95ce51677f6a381c3eb5ecb2bfacd59a08. * Revert "Treat clippy warnings as errors" This reverts commit c014cf0bd7bb3c4616523b8dc7f1e0c52c0082c3. * Add #![deny(warnings)] to all crates * Run "cargo clippy --fix" * cargo fmt * Add #[allow(clippy::too_many_arguments)] * Add #[allow(clippy::too_many_arguments)] * Fix warning: profiles for the non root package will be ignored, specify profiles at the workspace root * Apply clippy rules to api crate * Update api create with allowing future_not_send * Enable nursery for cli * Remove TODO comments * Enable clippy rules for lib * Enable clippy rules for rpc * Enable clippy rules for rpc-client * Remove unnecessary qualifications --------- Co-authored-by: Andrei Silviu Dragnea --- evm_loader/Cargo.toml | 3 + .../api/src/api_server/handlers/emulate.rs | 2 + .../src/api_server/handlers/get_balance.rs | 2 + .../api/src/api_server/handlers/get_config.rs | 2 + .../src/api_server/handlers/get_contract.rs | 2 + .../api/src/api_server/handlers/get_holder.rs | 2 + .../src/api_server/handlers/get_storage_at.rs | 2 + evm_loader/api/src/api_server/handlers/mod.rs | 4 +- .../api_server/handlers/simulate_solana.rs | 2 + .../api/src/api_server/handlers/trace.rs | 2 + evm_loader/api/src/main.rs | 2 +- evm_loader/cli/src/logs.rs | 3 +- evm_loader/cli/src/main.rs | 7 +- evm_loader/lib-interface/src/lib.rs | 3 + evm_loader/lib/src/abi/mod.rs | 15 +- evm_loader/lib/src/abi/state.rs | 1 + evm_loader/lib/src/account_data.rs | 33 ++- evm_loader/lib/src/account_storage.rs | 139 +++++----- evm_loader/lib/src/account_storage_tests.rs | 260 ++++++++---------- evm_loader/lib/src/build_info.rs | 1 + evm_loader/lib/src/build_info_common.rs | 2 +- evm_loader/lib/src/commands/emulate.rs | 18 +- evm_loader/lib/src/commands/get_balance.rs | 3 + evm_loader/lib/src/commands/get_config.rs | 16 +- evm_loader/lib/src/commands/get_contract.rs | 43 +-- evm_loader/lib/src/commands/get_holder.rs | 1 + evm_loader/lib/src/commands/get_neon_elf.rs | 8 +- .../lib/src/commands/init_environment.rs | 10 +- .../lib/src/commands/simulate_solana.rs | 2 +- evm_loader/lib/src/commands/trace.rs | 6 +- evm_loader/lib/src/errors.rs | 2 +- evm_loader/lib/src/lib.rs | 15 +- evm_loader/lib/src/rpc/validator_client.rs | 2 + evm_loader/lib/src/solana_simulator/mod.rs | 8 +- evm_loader/lib/src/solana_simulator/utils.rs | 3 +- .../lib/src/tracing/tracers/call_tracer.rs | 18 +- evm_loader/lib/src/tracing/tracers/mod.rs | 8 +- .../src/tracing/tracers/openeth/state_diff.rs | 5 +- .../lib/src/tracing/tracers/openeth/tracer.rs | 6 +- .../tracers/prestate_tracer/state_diff.rs | 25 +- .../tracing/tracers/prestate_tracer/tracer.rs | 3 +- .../lib/src/tracing/tracers/state_diff.rs | 17 +- .../lib/src/tracing/tracers/struct_logger.rs | 57 ++-- evm_loader/lib/src/types/mod.rs | 54 ++-- evm_loader/lib/src/types/tracer_ch_common.rs | 24 +- evm_loader/lib/src/types/tracer_ch_db.rs | 87 +++--- evm_loader/program/Cargo.toml | 3 - evm_loader/program/src/evm/mod.rs | 1 + evm_loader/rpc-client/src/config.rs | 4 +- evm_loader/rpc-client/src/http.rs | 15 +- evm_loader/rpc-client/src/lib.rs | 4 + evm_loader/rpc/src/error.rs | 2 +- evm_loader/rpc/src/handlers/emulate.rs | 2 + evm_loader/rpc/src/handlers/get_balance.rs | 2 + evm_loader/rpc/src/handlers/get_config.rs | 2 + evm_loader/rpc/src/handlers/get_contract.rs | 2 + evm_loader/rpc/src/handlers/get_holder.rs | 2 + evm_loader/rpc/src/handlers/get_storage_at.rs | 2 + evm_loader/rpc/src/handlers/mod.rs | 25 +- evm_loader/rpc/src/handlers/trace.rs | 2 + evm_loader/rpc/src/main.rs | 8 +- 61 files changed, 532 insertions(+), 474 deletions(-) diff --git a/evm_loader/Cargo.toml b/evm_loader/Cargo.toml index 1d77f1316..075999c6b 100644 --- a/evm_loader/Cargo.toml +++ b/evm_loader/Cargo.toml @@ -21,3 +21,6 @@ solana-sdk = "=1.17.34" solana-program-runtime = "=1.17.34" solana-runtime = "=1.17.34" solana-accounts-db = "=1.17.34" + +[profile.test] +debug = true diff --git a/evm_loader/api/src/api_server/handlers/emulate.rs b/evm_loader/api/src/api_server/handlers/emulate.rs index cbb03472a..c330b66b8 100644 --- a/evm_loader/api/src/api_server/handlers/emulate.rs +++ b/evm_loader/api/src/api_server/handlers/emulate.rs @@ -1,3 +1,5 @@ +#![allow(clippy::future_not_send)] + use actix_request_identifier::RequestId; use actix_web::{http::StatusCode, post, web::Json, Responder}; use neon_lib::tracing::tracers::TracerTypeEnum; diff --git a/evm_loader/api/src/api_server/handlers/get_balance.rs b/evm_loader/api/src/api_server/handlers/get_balance.rs index d09a77430..13b53a607 100644 --- a/evm_loader/api/src/api_server/handlers/get_balance.rs +++ b/evm_loader/api/src/api_server/handlers/get_balance.rs @@ -1,3 +1,5 @@ +#![allow(clippy::future_not_send)] + use crate::api_server::handlers::process_error; use crate::commands::get_balance as GetBalanceCommand; use crate::{types::GetBalanceRequest, NeonApiState}; diff --git a/evm_loader/api/src/api_server/handlers/get_config.rs b/evm_loader/api/src/api_server/handlers/get_config.rs index a0d7f6e90..4de5c1bf5 100644 --- a/evm_loader/api/src/api_server/handlers/get_config.rs +++ b/evm_loader/api/src/api_server/handlers/get_config.rs @@ -1,3 +1,5 @@ +#![allow(clippy::future_not_send)] + use crate::api_server::handlers::process_error; use crate::NeonApiState; use actix_request_identifier::RequestId; diff --git a/evm_loader/api/src/api_server/handlers/get_contract.rs b/evm_loader/api/src/api_server/handlers/get_contract.rs index 217831e12..6e5a47ba7 100644 --- a/evm_loader/api/src/api_server/handlers/get_contract.rs +++ b/evm_loader/api/src/api_server/handlers/get_contract.rs @@ -1,3 +1,5 @@ +#![allow(clippy::future_not_send)] + use crate::api_server::handlers::process_error; use crate::commands::get_contract as GetContractCommand; use crate::{types::GetContractRequest, NeonApiState}; diff --git a/evm_loader/api/src/api_server/handlers/get_holder.rs b/evm_loader/api/src/api_server/handlers/get_holder.rs index 663868b90..4ae6594c7 100644 --- a/evm_loader/api/src/api_server/handlers/get_holder.rs +++ b/evm_loader/api/src/api_server/handlers/get_holder.rs @@ -1,3 +1,5 @@ +#![allow(clippy::future_not_send)] + use crate::api_server::handlers::process_error; use crate::commands::get_holder as GetHolderCommand; use crate::{types::GetHolderRequest, NeonApiState}; diff --git a/evm_loader/api/src/api_server/handlers/get_storage_at.rs b/evm_loader/api/src/api_server/handlers/get_storage_at.rs index ba673e96e..ba4026155 100644 --- a/evm_loader/api/src/api_server/handlers/get_storage_at.rs +++ b/evm_loader/api/src/api_server/handlers/get_storage_at.rs @@ -1,3 +1,5 @@ +#![allow(clippy::future_not_send)] + use crate::api_server::handlers::process_error; use crate::{types::GetStorageAtRequest, NeonApiState}; use actix_request_identifier::RequestId; diff --git a/evm_loader/api/src/api_server/handlers/mod.rs b/evm_loader/api/src/api_server/handlers/mod.rs index b8c3ac724..19a812265 100644 --- a/evm_loader/api/src/api_server/handlers/mod.rs +++ b/evm_loader/api/src/api_server/handlers/mod.rs @@ -30,7 +30,7 @@ impl NeonApiError { impl From for NeonApiError { fn from(value: NeonError) -> Self { - NeonApiError(value) + Self(value) } } @@ -42,7 +42,7 @@ impl From for NeonError { impl From for NeonApiError { fn from(value: AddrParseError) -> Self { - NeonApiError(value.into()) + Self(value.into()) } } diff --git a/evm_loader/api/src/api_server/handlers/simulate_solana.rs b/evm_loader/api/src/api_server/handlers/simulate_solana.rs index 2bdca71e8..986b827cb 100644 --- a/evm_loader/api/src/api_server/handlers/simulate_solana.rs +++ b/evm_loader/api/src/api_server/handlers/simulate_solana.rs @@ -1,3 +1,5 @@ +#![allow(clippy::future_not_send)] + use actix_request_identifier::RequestId; use actix_web::{http::StatusCode, post, web::Json, Responder}; use std::convert::Into; diff --git a/evm_loader/api/src/api_server/handlers/trace.rs b/evm_loader/api/src/api_server/handlers/trace.rs index c2cc84ec5..4723df2f4 100644 --- a/evm_loader/api/src/api_server/handlers/trace.rs +++ b/evm_loader/api/src/api_server/handlers/trace.rs @@ -1,3 +1,5 @@ +#![allow(clippy::future_not_send)] + use actix_request_identifier::RequestId; use actix_web::{http::StatusCode, post, web::Json, Responder}; use std::convert::Into; diff --git a/evm_loader/api/src/main.rs b/evm_loader/api/src/main.rs index 1cba065cd..3d07a3cca 100644 --- a/evm_loader/api/src/main.rs +++ b/evm_loader/api/src/main.rs @@ -1,5 +1,5 @@ #![deny(warnings)] -#![deny(clippy::all, clippy::pedantic)] +#![deny(clippy::all, clippy::pedantic, clippy::nursery)] mod api_options; mod api_server; #[allow(clippy::module_name_repetitions)] diff --git a/evm_loader/cli/src/logs.rs b/evm_loader/cli/src/logs.rs index 500b2ae6b..4d43a03cf 100644 --- a/evm_loader/cli/src/logs.rs +++ b/evm_loader/cli/src/logs.rs @@ -44,8 +44,7 @@ pub fn init(options: &ArgMatches) -> Result<(), log::SetLoggerError> { let file: &str = record.file().unwrap_or("undefined"); let line: u32 = record.line().unwrap_or(0); - let mut context = CONTEXT.lock().unwrap(); - context.push(LogRecord { + CONTEXT.lock().unwrap().push(LogRecord { message: record.args().to_string(), source: format!("{file}:{line}"), level: record.metadata().level().as_str(), diff --git a/evm_loader/cli/src/main.rs b/evm_loader/cli/src/main.rs index 17695ec1b..a1b6bb134 100644 --- a/evm_loader/cli/src/main.rs +++ b/evm_loader/cli/src/main.rs @@ -1,7 +1,8 @@ #![deny(warnings)] -#![deny(clippy::all, clippy::pedantic)] +#![deny(clippy::all, clippy::pedantic, clippy::nursery)] +#![allow(clippy::future_not_send)] +#![allow(clippy::module_name_repetitions)] -#[allow(clippy::module_name_repetitions)] mod build_info; mod config; mod logs; @@ -209,7 +210,7 @@ async fn main() { log::info!("execution time: {} sec", execution_time.as_secs_f64()); print_result(&result); if let Err(e) = result { - std::process::exit(e.error_code()); + std::process::exit(e.error_code().try_into().unwrap()); }; } diff --git a/evm_loader/lib-interface/src/lib.rs b/evm_loader/lib-interface/src/lib.rs index fab07f3f7..0a1781d21 100644 --- a/evm_loader/lib-interface/src/lib.rs +++ b/evm_loader/lib-interface/src/lib.rs @@ -1,3 +1,5 @@ +#![deny(warnings)] +#![deny(clippy::all, clippy::nursery)] #![allow(non_camel_case_types)] pub mod types; @@ -25,6 +27,7 @@ pub struct NeonEVMLib { pub invoke: for<'a> extern "C" fn(RStr<'a>, RStr<'a>) -> RNeonEVMLibResult<'a>, } +#[allow(clippy::use_self)] impl RootModule for NeonEVMLib_Ref { abi_stable::declare_root_module_statics! {NeonEVMLib_Ref} diff --git a/evm_loader/lib/src/abi/mod.rs b/evm_loader/lib/src/abi/mod.rs index 6f181fb3f..c27303e62 100644 --- a/evm_loader/lib/src/abi/mod.rs +++ b/evm_loader/lib/src/abi/mod.rs @@ -29,7 +29,7 @@ use serde_json::json; lazy_static! { static ref RUNTIME: tokio::runtime::Runtime = tokio::runtime::Runtime::new().unwrap(); - static ref STATE: State = State::new(load_config().unwrap()); + static ref STATE: State = State::new(load_config()); } pub const _MODULE_WM_: &WithMetadata = &WithMetadata::new(NeonEVMLib { @@ -72,8 +72,8 @@ fn invoke<'a>(method: RStr<'a>, params: RStr<'a>) -> RNeonEVMLibResult<'a> { .into_local_ffi() } -fn load_config() -> Result { - Ok(config::load_api_config_from_environment()) +fn load_config() -> APIOptions { + config::load_api_config_from_environment() } async fn dispatch(method_str: &str, params_str: &str) -> Result { @@ -127,15 +127,16 @@ fn params_to_neon_error(params: &str) -> NeonError { ) } -fn neon_error_to_neon_lib_error(error: NeonError) -> NeonEVMLibError { - assert!(error.error_code() >= 0); +fn neon_error_to_neon_lib_error(error: &NeonError) -> NeonEVMLibError { + assert!(error.error_code() != 0); NeonEVMLibError { - code: error.error_code() as u32, + code: error.error_code(), message: error.to_string(), data: None, } } +#[allow(clippy::needless_pass_by_value)] fn neon_error_to_rstring(error: NeonError) -> RString { - RString::from(serde_json::to_string(&neon_error_to_neon_lib_error(error)).unwrap()) + RString::from(serde_json::to_string(&neon_error_to_neon_lib_error(&error)).unwrap()) } diff --git a/evm_loader/lib/src/abi/state.rs b/evm_loader/lib/src/abi/state.rs index bad3cb07d..6eaf2fcea 100644 --- a/evm_loader/lib/src/abi/state.rs +++ b/evm_loader/lib/src/abi/state.rs @@ -10,6 +10,7 @@ pub struct State { } impl State { + #[must_use] pub fn new(config: APIOptions) -> Self { Self { tracer_db: TracerDb::new(&config.db_config), diff --git a/evm_loader/lib/src/account_data.rs b/evm_loader/lib/src/account_data.rs index 515c1e70e..376218121 100644 --- a/evm_loader/lib/src/account_data.rs +++ b/evm_loader/lib/src/account_data.rs @@ -24,6 +24,7 @@ use solana_sdk::account_info::IntoAccountInfo; use solana_sdk::entrypoint::MAX_PERMITTED_DATA_INCREASE; impl AccountData { + #[must_use] pub fn new(pubkey: Pubkey) -> Self { Self { original_length: 0, @@ -36,10 +37,12 @@ impl AccountData { } } + #[must_use] pub fn is_empty(&self) -> bool { self.get_length() == 0 && self.owner == system_program::ID } + #[must_use] pub fn is_busy(&self) -> bool { self.get_length() != 0 || self.owner != system_program::ID } @@ -47,12 +50,15 @@ impl AccountData { pub fn new_from_account(pubkey: Pubkey, account: &T) -> Self { let account_data = account.data(); let mut data = vec![0u8; account_data.len() + 8 + MAX_PERMITTED_DATA_INCREASE]; - let ptr_length = data.as_mut_ptr() as *mut _ as *mut u64; + let ptr_length: *mut u64 = data.as_mut_ptr().cast(); unsafe { *ptr_length = account_data.len() as u64 }; data[8..8 + account_data.len()].copy_from_slice(account_data); Self { - original_length: account_data.len() as u32, + original_length: u32::try_from(account_data.len()).unwrap_or_else(|error| { + println!("Error converting account data length: {error}"); + 0 + }), pubkey, lamports: account.lamports(), data, @@ -63,12 +69,19 @@ impl AccountData { } pub fn expand(&mut self, length: usize) { - if self.original_length < length as u32 { + let len = u32::try_from(length).unwrap_or_else(|error| { + println!("Error converting account data length: {error}"); + 0 + }); + if self.original_length < len { self.data .resize(length + 8 + MAX_PERMITTED_DATA_INCREASE, 0); - self.original_length = length as u32; + self.original_length = u32::try_from(length).unwrap_or_else(|error| { + println!("Error converting account data length: {error}"); + 0 + }); } - let ptr_length = self.data.as_mut_ptr() as *mut _ as *mut u64; + let ptr_length: *mut u64 = self.data.as_mut_ptr().cast(); unsafe { if *ptr_length < length as u64 { *ptr_length = length as u64; @@ -77,7 +90,7 @@ impl AccountData { } pub fn reserve(&mut self) { - self.expand(self.get_length()) + self.expand(self.get_length()); } pub fn assign(&mut self, owner: Pubkey) -> evm_loader::error::Result<()> { @@ -90,6 +103,7 @@ impl AccountData { Ok(()) } + #[must_use] pub fn data(&self) -> &[u8] { let length = self.get_length(); &self.data[8..8 + length] @@ -100,9 +114,10 @@ impl AccountData { &mut self.data[8..8 + length] } + #[must_use] pub fn get_length(&self) -> usize { - let ptr_length = self.data.as_ptr() as *const _ as *const u64; - (unsafe { *ptr_length }) as usize + let ptr_length: *const u64 = self.data.as_ptr().cast(); + usize::try_from(unsafe { *ptr_length }).unwrap_or(0) } fn get(&mut self) -> (&Pubkey, &mut u64, &mut [u8], &Pubkey, bool, u64) { @@ -130,7 +145,7 @@ impl<'a> IntoAccountInfo<'a> for &'a mut AccountData { impl<'a> From<&'a AccountData> for Account { fn from(val: &'a AccountData) -> Self { - Account { + Self { lamports: val.lamports, data: val.data().to_vec(), owner: val.owner, diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index f3d08b9a8..adcac0fad 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -1,16 +1,7 @@ +use crate::account_data::AccountData; +use crate::{rpc::Rpc, solana_simulator::SolanaSimulator, NeonError, NeonResult}; use async_trait::async_trait; use elsa::FrozenMap; -use solana_client::rpc_response::{Response, RpcResponseContext, RpcResult}; -use std::collections::{HashMap, HashSet}; -use std::{ - cell::{RefCell, RefMut}, - convert::TryInto, - rc::Rc, -}; - -use crate::{ - account_data::AccountData, rpc::Rpc, solana_simulator::SolanaSimulator, NeonError, NeonResult, -}; use ethnum::U256; pub use evm_loader::account_storage::{AccountStorage, SyncedAccountStorage}; use evm_loader::{ @@ -26,6 +17,7 @@ use evm_loader::{ }; use log::{debug, info, trace}; use solana_client::client_error::{self, Result as ClientResult}; +use solana_client::rpc_response::{Response, RpcResponseContext, RpcResult}; use solana_sdk::{ account::Account, account_info::{AccountInfo, IntoAccountInfo}, @@ -40,6 +32,12 @@ use solana_sdk::{ sysvar::slot_hashes, transaction_context::TransactionReturnData, }; +use std::collections::{HashMap, HashSet}; +use std::{ + cell::{RefCell, RefMut}, + convert::TryInto, + rc::Rc, +}; use crate::commands::get_config::{BuildConfigSimulator, ChainInfo}; use crate::tracing::{AccountOverrides, BlockOverrides}; @@ -67,7 +65,8 @@ trait UpdateLamports<'a> { fn update_lamports(&mut self, rent: &Rent) { let required_lamports = rent.minimum_balance(self.required_lamports()); if self.info().lamports() < required_lamports { - **self.info().lamports.borrow_mut() = required_lamports; + let mut lamports = self.info().lamports.borrow_mut(); + **lamports = required_lamports; } } fn required_lamports(&self) -> usize; @@ -233,14 +232,14 @@ impl<'rpc, T: Rpc + BuildConfigSimulator> EmulatorAccountStorage<'rpc, T> { block_number, block_timestamp, timestamp_used: RefCell::new(false), - state_overrides: state_overrides, + state_overrides, rent, accounts_cache, used_accounts: FrozenMap::new(), return_data: RefCell::new(None), }; - let target_chain_id = tx_chain_id.unwrap_or(storage.default_chain_id()); + let target_chain_id = tx_chain_id.unwrap_or_else(|| storage.default_chain_id()); storage.apply_balance_overrides(target_chain_id).await?; Ok(storage) @@ -271,11 +270,12 @@ impl<'rpc, T: Rpc + BuildConfigSimulator> EmulatorAccountStorage<'rpc, T> { used_accounts: other.used_accounts.clone(), return_data: RefCell::new(None), }; - let target_chain_id = tx_chain_id.unwrap_or(storage.default_chain_id()); + let target_chain_id = tx_chain_id.unwrap_or_else(|| storage.default_chain_id()); storage.apply_balance_overrides(target_chain_id).await?; Ok(storage) } + #[allow(clippy::too_many_arguments)] pub async fn with_accounts( rpc: &'rpc T, program_id: Pubkey, @@ -306,7 +306,7 @@ impl<'rpc, T: Rpc + BuildConfigSimulator> EmulatorAccountStorage<'rpc, T> { impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { async fn apply_balance_overrides(&self, target_chain_id: u64) -> NeonResult<()> { if let Some(state_overrides) = self.state_overrides.as_ref() { - for (address, overrides) in state_overrides.into_iter() { + for (address, overrides) in state_overrides { if overrides.nonce.is_none() && overrides.balance.is_none() { continue; } @@ -392,7 +392,7 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { .borrow_mut() } - async fn _add_legacy_account( + fn _add_legacy_account( &self, info: &AccountInfo<'_>, ) -> NeonResult<(&RefCell, &RefCell)> { @@ -401,7 +401,7 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { let (balance_pubkey, _) = legacy .address .find_balance_address(&self.program_id, self.default_chain_id()); - let balance_data = self.add_empty_account(balance_pubkey)?; + let balance_data = self.add_empty_account(balance_pubkey); if (legacy.balance > 0) || (legacy.trx_count > 0) { let mut balance_data = balance_data.borrow_mut(); let mut balance = self.create_ethereum_balance( @@ -417,7 +417,7 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { } let (contract_pubkey, _) = legacy.address.find_solana_address(&self.program_id); - let contract_data = self.add_empty_account(contract_pubkey)?; + let contract_data = self.add_empty_account(contract_pubkey); if (legacy.code_size > 0) || (legacy.generation > 0) { let code = legacy.read_code(info); let storage = legacy.read_storage(info); @@ -467,11 +467,7 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { let mut account = self._get_account_from_rpc(pubkey).await?.cloned(); if let Some(account) = &mut account { let info = account_info(&pubkey, account); - if *info.owner != self.program_id { - let account_data = AccountData::new_from_account(pubkey, account); - self.accounts - .insert(pubkey, Box::new(RefCell::new(account_data))) - } else { + if *info.owner == self.program_id { match evm_loader::account::tag(&self.program_id, &info)? { evm_loader::account::TAG_ACCOUNT_CONTRACT => { let data = AccountData::new_from_account(pubkey, account); @@ -479,15 +475,18 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { } evm_loader::account::legacy::TAG_ACCOUNT_CONTRACT_DEPRECATED => self ._add_legacy_account(&info) - .await .map(|(contract, _balance)| contract)?, _ => { unimplemented!(); } } + } else { + let account_data = AccountData::new_from_account(pubkey, account); + self.accounts + .insert(pubkey, Box::new(RefCell::new(account_data))) } } else { - self.add_empty_account(pubkey)? + self.add_empty_account(pubkey) } }; self.mark_legacy_account(pubkey, false, None); @@ -503,7 +502,7 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { let generation = self ._get_contract_generation_limited(legacy_storage.address) .await?; - let storage_data = self.add_empty_account(pubkey)?; + let storage_data = self.add_empty_account(pubkey); if Some(legacy_storage.generation) == generation { let cells = legacy_storage.read_cells(info); @@ -530,13 +529,7 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { ) -> NeonResult<&RefCell> { let mut account = account.clone(); let info = account_info(&pubkey, &mut account); - if *info.owner != self.program_id { - let account_data = AccountData::new_from_account(pubkey, &account); - self.mark_account(pubkey, false); - Ok(self - .accounts - .insert(pubkey, Box::new(RefCell::new(account_data)))) - } else { + if *info.owner == self.program_id { let tag = evm_loader::account::tag(&self.program_id, &info)?; match tag { evm_loader::account::TAG_ACCOUNT_BALANCE @@ -551,7 +544,6 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { } evm_loader::account::legacy::TAG_ACCOUNT_CONTRACT_DEPRECATED => self ._add_legacy_account(&info) - .await .map(|(contract, _balance)| contract), evm_loader::account::legacy::TAG_STORAGE_CELL_DEPRECATED => { let legacy_storage = LegacyStorageData::from_account(&self.program_id, &info)?; @@ -562,15 +554,20 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { unimplemented!(); } } + } else { + let account_data = AccountData::new_from_account(pubkey, &account); + self.mark_account(pubkey, false); + Ok(self + .accounts + .insert(pubkey, Box::new(RefCell::new(account_data)))) } } - fn add_empty_account(&self, pubkey: Pubkey) -> NeonResult<&RefCell> { + fn add_empty_account(&self, pubkey: Pubkey) -> &RefCell { let account_data = AccountData::new(pubkey); self.mark_account(pubkey, false); - Ok(self - .accounts - .insert(pubkey, Box::new(RefCell::new(account_data)))) + self.accounts + .insert(pubkey, Box::new(RefCell::new(account_data))) } async fn use_account( @@ -592,7 +589,7 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { if let Some(account) = account { self.add_account(pubkey, account).await } else { - self.add_empty_account(pubkey) + Ok(self.add_empty_account(pubkey)) } } @@ -615,26 +612,24 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { if self.accounts.get(&legacy_pubkey).is_some() { // We already have information about contract account (empty or filled with data). // So the balance should be updated, but it is missed. So return the empty account. - self.add_empty_account(pubkey) + Ok(self.add_empty_account(pubkey)) } else { // We didn't process contract account and we doesn't have any information about it. // So we can try to process account which can be a legacy. - match self._get_account_from_rpc(legacy_pubkey).await? { - Some(legacy_account) => { - self.add_account(legacy_pubkey, legacy_account).await?; - match self.accounts.get(&pubkey) { - Some(account) => Ok(account), - None => self.add_empty_account(pubkey), - } - } - None => { - self.add_empty_account(legacy_pubkey)?; - self.add_empty_account(pubkey) - } + if let Some(legacy_account) = + self._get_account_from_rpc(legacy_pubkey).await? + { + self.add_account(legacy_pubkey, legacy_account).await?; + self.accounts + .get(&pubkey) + .map_or_else(|| Ok(self.add_empty_account(pubkey)), Ok) + } else { + self.add_empty_account(legacy_pubkey); + Ok(self.add_empty_account(pubkey)) } } } else { - self.add_empty_account(pubkey) + Ok(self.add_empty_account(pubkey)) } } } @@ -649,7 +644,7 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { match self._get_account_from_rpc(pubkey).await? { Some(account) => self.add_account(pubkey, account).await, - None => self.add_empty_account(pubkey), + None => Ok(self.add_empty_account(pubkey)), } } @@ -668,7 +663,7 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { match self._get_account_from_rpc(cell_pubkey).await? { Some(account) => self.add_account(cell_pubkey, account).await, - None => self.add_empty_account(cell_pubkey), + None => Ok(self.add_empty_account(cell_pubkey)), } } @@ -855,8 +850,7 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { .get(&used_account.pubkey) .unwrap_or(&None) .as_ref() - .map(|v| v.lamports) - .unwrap_or(0); + .map_or(0, |v| v.lamports); if lamports_after_upgrade > orig_lamports { lamports_spend += lamports_after_upgrade - orig_lamports; } else { @@ -870,7 +864,7 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { pub fn get_regular_rent(&self) -> evm_loader::error::Result { let accounts = self.accounts.clone(); let mut changes_in_rent = 0u64; - for (pubkey, account) in accounts.into_map().iter() { + for (pubkey, account) in &accounts.into_map() { if *pubkey == system_program::ID { continue; } @@ -973,17 +967,25 @@ impl AccountStorage for EmulatorAccountStorage<'_, T> { async fn nonce(&self, address: Address, chain_id: u64) -> u64 { info!("nonce {address} {chain_id}"); - self.ethereum_balance_map_or(address, chain_id, u64::default(), |account| account.nonce()) - .await - .unwrap() + self.ethereum_balance_map_or( + address, + chain_id, + u64::default(), + |account: &BalanceAccount| account.nonce(), + ) + .await + .unwrap() } async fn balance(&self, address: Address, chain_id: u64) -> U256 { info!("balance {address} {chain_id}"); - self.ethereum_balance_map_or(address, chain_id, U256::default(), |account| { - account.balance() - }) + self.ethereum_balance_map_or( + address, + chain_id, + U256::default(), + |account: &BalanceAccount| account.balance(), + ) .await .unwrap() } @@ -1126,6 +1128,7 @@ impl AccountStorage for EmulatorAccountStorage<'_, T> { } } +#[allow(clippy::needless_pass_by_value)] fn map_neon_error(e: NeonError) -> EvmLoaderError { EvmLoaderError::Custom(e.to_string()) } @@ -1309,7 +1312,7 @@ impl SyncedAccountStorage for EmulatorAccountStorage<'_, T> { let signers = seeds .iter() .map(|s| { - let seed = s.iter().map(|s| s.as_slice()).collect::>(); + let seed = s.iter().map(Vec::as_slice).collect::>(); let signer = Pubkey::create_program_address(&seed, &self.program_id)?; Ok(signer) }) @@ -1320,7 +1323,7 @@ impl SyncedAccountStorage for EmulatorAccountStorage<'_, T> { accounts.push(instruction.program_id); self.mark_account(instruction.program_id, false); - for meta in instruction.accounts.iter() { + for meta in &instruction.accounts { if meta.pubkey != self.operator { self.use_account(meta.pubkey, meta.is_writable) .await @@ -1358,7 +1361,7 @@ impl SyncedAccountStorage for EmulatorAccountStorage<'_, T> { *self.return_data.borrow_mut() = Some(return_data); } - for meta in instruction.accounts.iter() { + for meta in &instruction.accounts { if meta.pubkey == self.operator { continue; } diff --git a/evm_loader/lib/src/account_storage_tests.rs b/evm_loader/lib/src/account_storage_tests.rs index 143cdf1a5..d6ebf1e5b 100644 --- a/evm_loader/lib/src/account_storage_tests.rs +++ b/evm_loader/lib/src/account_storage_tests.rs @@ -4,6 +4,9 @@ use crate::tracing::AccountOverride; use hex_literal::hex; use std::collections::HashMap; use std::str::FromStr; + +const STORAGE_LENGTH: usize = 32 * STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT; + mod mock_rpc_client { use crate::commands::get_config::BuildConfigSimulator; use crate::NeonResult; @@ -84,7 +87,7 @@ async fn get_overriden_nonce_and_balance( nonce_chain_id: u64, overrides: Option, ) -> (u64, U256) { - let mut fixture = Fixture::new().await; + let mut fixture = Fixture::new(); fixture.state_overrides = overrides; let storage = fixture .build_account_storage_with_chain_id(Some(tx_chain_id)) @@ -112,6 +115,8 @@ where Ok(action(&balance_account?)) } + +#[allow(clippy::too_many_arguments)] fn create_legacy_ether_contract( program_id: &Pubkey, rent: &Rent, @@ -122,7 +127,7 @@ fn create_legacy_ether_contract( code: &[u8], storage: &[[u8; 32]; STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT], ) -> Account { - let data_length = if (code.len() > 0) || (generation > 0) { + let data_length = if (!code.is_empty()) || (generation > 0) { 1 + LegacyEtherData::SIZE + 32 * STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT + code.len() } else { 1 + LegacyEtherData::SIZE @@ -147,12 +152,14 @@ fn create_legacy_ether_contract( *trx_count_ptr = trx_count.to_le_bytes(); *balance_ptr = balance.to_le_bytes(); *generation_ptr = generation.to_le_bytes(); - *code_size_ptr = (code.len() as u32).to_le_bytes(); + *code_size_ptr = u32::try_from(code.len()) + .expect("Expected code value") + .to_le_bytes(); *rw_blocked_ptr = 0u8.to_le_bytes(); - if (generation > 0) || (code.len() > 0) { + if (generation > 0) || (!code.is_empty()) { let storage_offset = 1 + LegacyEtherData::SIZE; - const STORAGE_LENGTH: usize = 32 * STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT; + let storage_ptr = &mut data[storage_offset..][..STORAGE_LENGTH]; let storage_source = unsafe { let ptr: *const u8 = storage.as_ptr().cast(); @@ -167,7 +174,7 @@ fn create_legacy_ether_contract( Account { lamports: rent.minimum_balance(data.len()), - data: data, + data, owner: *program_id, executable: false, rent_epoch: 0, @@ -239,7 +246,7 @@ impl ActualStorage { } impl LegacyStorage { - pub fn required_account_size(count: usize) -> usize { + pub const fn required_account_size(count: usize) -> usize { 1 + LegacyStorageData::SIZE + std::mem::size_of::<(u8, [u8; 32])>() * count } pub fn account_with_pubkey( @@ -271,7 +278,7 @@ impl LegacyStorage { let account = Account { lamports: rent.minimum_balance(data.len()), - data: data, + data, owner: *program_id, executable: false, rent_epoch: 0, @@ -290,8 +297,8 @@ struct LegacyAccount { impl LegacyAccount { pub fn account_with_pubkey(&self, program_id: &Pubkey, rent: &Rent) -> (Pubkey, Account) { ( - self.address.find_solana_address(&program_id).0, - create_legacy_ether_account(&program_id, &rent, self.address, self.balance, self.nonce), + self.address.find_solana_address(program_id).0, + create_legacy_ether_account(program_id, rent, self.address, self.balance, self.nonce), ) } } @@ -310,15 +317,15 @@ struct LegacyContract { impl LegacyContract { fn account_with_pubkey(&self, program_id: &Pubkey, rent: &Rent) -> (Pubkey, Account) { ( - self.address.find_solana_address(&program_id).0, + self.address.find_solana_address(program_id).0, create_legacy_ether_contract( - &program_id, - &rent, + program_id, + rent, self.address, self.balance, self.nonce, self.generation, - &self.code, + self.code, &self.storage, ), ) @@ -352,9 +359,7 @@ struct ActualBalance { impl ActualBalance { pub fn account_with_pubkey(&self, program_id: &Pubkey, rent: &Rent) -> (Pubkey, Account) { - let (pubkey, _) = self - .address - .find_balance_address(&program_id, self.chain_id); + let (pubkey, _) = self.address.find_balance_address(program_id, self.chain_id); let mut account_data = AccountData::new(pubkey); account_data.assign(*program_id).unwrap(); account_data.expand(BalanceAccount::required_account_size()); @@ -397,7 +402,7 @@ struct ActualContract { impl ActualContract { pub fn account_with_pubkey(&self, program_id: &Pubkey, rent: &Rent) -> (Pubkey, Account) { - let (pubkey, _) = self.address.find_solana_address(&program_id); + let (pubkey, _) = self.address.find_solana_address(program_id); let mut account_data = AccountData::new(pubkey); account_data.assign(*program_id).unwrap(); account_data.expand(ContractAccount::required_account_size(self.code)); @@ -458,7 +463,7 @@ const LEGACY_CHAIN_ID: u64 = 1; const EXTRA_CHAIN_ID: u64 = 2; const MISSING_ADDRESS: Address = Address(hex!("7a250d5630b4cf539739df2c5dacb4c659f24800")); -const MISSING_STORAGE_INDEX: U256 = U256::new(1 * 256u128); +const MISSING_STORAGE_INDEX: U256 = U256::new(256u128); const ACTUAL_STORAGE_INDEX: U256 = U256::new(2 * 256u128); const LEGACY_STORAGE_INDEX: U256 = U256::new(3 * 256u128); const OUTDATE_STORAGE_INDEX: U256 = U256::new(4 * 256u128); @@ -597,14 +602,14 @@ struct Fixture { } impl Fixture { - pub async fn new() -> Self { + pub fn new() -> Self { let rent = Rent::default(); let program_id = Pubkey::from_str("53DfF883gyixYNXnM7s5xhdeyV8mVk9T4i2hGV9vG9io").unwrap(); let accounts = vec![ ( Pubkey::from_str("SysvarRent111111111111111111111111111111111").unwrap(), Account { - lamports: 1009200, + lamports: 1_009_200, data: bincode::serialize(&rent).unwrap(), owner: Pubkey::from_str("Sysvar1111111111111111111111111111111111111").unwrap(), executable: false, @@ -724,9 +729,9 @@ impl Fixture { } pub fn legacy_rent(&self, code_len: Option) -> u64 { - let data_length = code_len - .map(|len| 1 + LegacyEtherData::SIZE + 32 * STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT + len) - .unwrap_or(1 + LegacyEtherData::SIZE); + let data_length = code_len.map_or(1 + LegacyEtherData::SIZE, |len| { + 1 + LegacyEtherData::SIZE + 32 * STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT + len + }); self.rent.minimum_balance(data_length) } @@ -766,7 +771,7 @@ impl<'rpc, T: Rpc> EmulatorAccountStorage<'rpc, T> { #[tokio::test] async fn test_read_balance_missing_account() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let storage = fixture.build_account_storage().await; assert_eq!( @@ -789,7 +794,7 @@ async fn test_read_balance_missing_account() { #[tokio::test] async fn test_read_balance_missing_account_extra_chain() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let storage = fixture.build_account_storage().await; assert_eq!( @@ -809,7 +814,7 @@ async fn test_read_balance_missing_account_extra_chain() { #[tokio::test] async fn test_read_balance_actual_account() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let storage = fixture.build_account_storage().await; let acc = &ACTUAL_BALANCE; @@ -830,7 +835,7 @@ async fn test_read_balance_actual_account() { #[tokio::test] async fn test_read_balance_actual_account_extra_chain() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let storage = fixture.build_account_storage().await; let acc = &ACTUAL_BALANCE2; @@ -852,7 +857,7 @@ async fn test_read_balance_actual_account_extra_chain() { #[tokio::test] async fn test_read_balance_legacy_account() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let storage = fixture.build_account_storage().await; let acc = &LEGACY_ACCOUNT; @@ -876,19 +881,16 @@ async fn test_read_balance_legacy_account() { #[tokio::test] async fn test_modify_actual_and_missing_account() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let mut storage = fixture.build_account_storage().await; let from = &ACTUAL_BALANCE; let amount = U256::new(10); assert_eq!(from.chain_id, LEGACY_CHAIN_ID); - assert_eq!( - storage - .transfer(from.address, MISSING_ADDRESS, from.chain_id, amount) - .await - .is_ok(), - true - ); + assert!(storage + .transfer(from.address, MISSING_ADDRESS, from.chain_id, amount) + .await + .is_ok()); storage.verify_used_accounts(&[ ( @@ -918,19 +920,16 @@ async fn test_modify_actual_and_missing_account() { #[tokio::test] async fn test_modify_actual_and_missing_account_extra_chain() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let mut storage = fixture.build_account_storage().await; let from = &ACTUAL_BALANCE2; let amount = U256::new(11); assert_eq!(from.chain_id, EXTRA_CHAIN_ID); - assert_eq!( - storage - .transfer(from.address, MISSING_ADDRESS, from.chain_id, amount) - .await - .is_ok(), - true - ); + assert!(storage + .transfer(from.address, MISSING_ADDRESS, from.chain_id, amount) + .await + .is_ok()); storage.verify_used_accounts(&[ ( @@ -959,20 +958,17 @@ async fn test_modify_actual_and_missing_account_extra_chain() { #[tokio::test] async fn test_modify_actual_and_legacy_account() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let mut storage = fixture.build_account_storage().await; let from = &ACTUAL_BALANCE; let to = &LEGACY_ACCOUNT; let amount = U256::new(10); assert_eq!(from.chain_id, LEGACY_CHAIN_ID); - assert_eq!( - storage - .transfer(from.address, to.address, from.chain_id, amount) - .await - .is_ok(), - true - ); + assert!(storage + .transfer(from.address, to.address, from.chain_id, amount) + .await + .is_ok()); storage.verify_used_accounts(&[ ( @@ -1002,7 +998,7 @@ async fn test_modify_actual_and_legacy_account() { #[tokio::test] async fn test_read_missing_contract() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let storage = fixture.build_account_storage().await; assert_eq!(*storage.code(MISSING_ADDRESS).await, [0u8; 0]); @@ -1027,7 +1023,7 @@ async fn test_read_missing_contract() { #[tokio::test] async fn test_read_legacy_contract() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let storage = fixture.build_account_storage().await; assert_eq!( @@ -1055,7 +1051,7 @@ async fn test_read_legacy_contract() { #[tokio::test] async fn test_read_legacy_contract_no_balance() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let storage = fixture.build_account_storage().await; let contract = &LEGACY_CONTRACT_NO_BALANCE; @@ -1081,7 +1077,7 @@ async fn test_read_legacy_contract_no_balance() { #[tokio::test] async fn test_read_actual_suicide_contract() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let storage = fixture.build_account_storage().await; let contract = &ACTUAL_SUICIDE; @@ -1097,7 +1093,7 @@ async fn test_read_actual_suicide_contract() { #[tokio::test] async fn test_read_legacy_suicide_contract() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let storage = fixture.build_account_storage().await; let contract = &LEGACY_SUICIDE; @@ -1123,17 +1119,14 @@ async fn test_read_legacy_suicide_contract() { #[tokio::test] async fn test_deploy_at_missing_contract() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let mut storage = fixture.build_account_storage().await; let code = hex!("14643165").to_vec(); - assert_eq!( - storage - .set_code(MISSING_ADDRESS, LEGACY_CHAIN_ID, code.clone()) - .await - .is_ok(), - true - ); + assert!(storage + .set_code(MISSING_ADDRESS, LEGACY_CHAIN_ID, code.clone()) + .await + .is_ok()); storage.verify_used_accounts(&[(fixture.contract_pubkey(MISSING_ADDRESS), true, false)]); storage.verify_upgrade_rent(0, 0); storage.verify_regular_rent(fixture.contract_rent(&code), 0); @@ -1141,18 +1134,15 @@ async fn test_deploy_at_missing_contract() { #[tokio::test] async fn test_deploy_at_actual_balance() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let mut storage = fixture.build_account_storage().await; let code = hex!("14643165").to_vec(); let acc = &ACTUAL_BALANCE; - assert_eq!( - storage - .set_code(acc.address, LEGACY_CHAIN_ID, code.clone()) - .await - .is_ok(), - true - ); + assert!(storage + .set_code(acc.address, LEGACY_CHAIN_ID, code.clone()) + .await + .is_ok()); storage.verify_used_accounts(&[(fixture.contract_pubkey(acc.address), true, false)]); storage.verify_upgrade_rent(0, 0); storage.verify_regular_rent(fixture.contract_rent(&code), 0); @@ -1160,7 +1150,7 @@ async fn test_deploy_at_actual_balance() { #[tokio::test] async fn test_deploy_at_actual_contract() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let mut storage = fixture.build_account_storage().await; let code = hex!("62345987").to_vec(); @@ -1181,18 +1171,15 @@ async fn test_deploy_at_actual_contract() { #[tokio::test] async fn test_deploy_at_legacy_account() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let mut storage = fixture.build_account_storage().await; let code = hex!("37455846").to_vec(); let contract = &LEGACY_ACCOUNT; - assert_eq!( - storage - .set_code(contract.address, LEGACY_CHAIN_ID, code.clone()) - .await - .is_ok(), - true - ); + assert!(storage + .set_code(contract.address, LEGACY_CHAIN_ID, code.clone()) + .await + .is_ok()); storage.verify_used_accounts(&[ ( fixture.balance_pubkey(contract.address, LEGACY_CHAIN_ID), @@ -1207,7 +1194,7 @@ async fn test_deploy_at_legacy_account() { #[tokio::test] async fn test_deploy_at_legacy_contract() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let mut storage = fixture.build_account_storage().await; let code = hex!("13412971").to_vec(); @@ -1238,19 +1225,16 @@ async fn test_deploy_at_legacy_contract() { #[tokio::test] async fn test_deploy_at_actual_suicide() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let mut storage = fixture.build_account_storage().await; let code = hex!("13412971").to_vec(); let contract = &ACTUAL_SUICIDE; // TODO: Should we deploy new contract by the previous address? - assert_eq!( - storage - .set_code(contract.address, LEGACY_CHAIN_ID, code.clone()) - .await - .is_ok(), - true, - ); + assert!(storage + .set_code(contract.address, LEGACY_CHAIN_ID, code.clone()) + .await + .is_ok(),); storage.verify_used_accounts(&[(fixture.contract_pubkey(contract.address), true, false)]); storage.verify_upgrade_rent(0, 0); storage.verify_regular_rent( @@ -1261,19 +1245,16 @@ async fn test_deploy_at_actual_suicide() { #[tokio::test] async fn test_deploy_at_legacy_suicide() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let mut storage = fixture.build_account_storage().await; let code = hex!("13412971").to_vec(); let contract = &LEGACY_SUICIDE; // TODO: Should we deploy new contract by the previous address? - assert_eq!( - storage - .set_code(contract.address, LEGACY_CHAIN_ID, code.clone()) - .await - .is_ok(), - true, - ); + assert!(storage + .set_code(contract.address, LEGACY_CHAIN_ID, code.clone()) + .await + .is_ok(),); storage.verify_used_accounts(&[ ( fixture.balance_pubkey(contract.address, LEGACY_CHAIN_ID), @@ -1283,18 +1264,18 @@ async fn test_deploy_at_legacy_suicide() { (fixture.contract_pubkey(contract.address), true, true), ]); storage.verify_upgrade_rent( - fixture.balance_rent() + fixture.contract_rent(&contract.code), + fixture.balance_rent() + fixture.contract_rent(contract.code), fixture.legacy_rent(Some(contract.code.len())), ); storage.verify_regular_rent( fixture.contract_rent(&code), - fixture.contract_rent(&contract.code), + fixture.contract_rent(contract.code), ); } #[tokio::test] async fn test_read_missing_storage_for_missing_contract() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let storage = fixture.build_account_storage().await; assert_eq!( @@ -1314,7 +1295,7 @@ async fn test_read_missing_storage_for_missing_contract() { #[tokio::test] async fn test_read_missing_storage_for_actual_contract() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let storage = fixture.build_account_storage().await; let contract = &ACTUAL_CONTRACT; @@ -1335,7 +1316,7 @@ async fn test_read_missing_storage_for_actual_contract() { #[tokio::test] async fn test_read_actual_storage_for_actual_contract() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let storage = fixture.build_account_storage().await; let contract = &ACTUAL_CONTRACT; @@ -1356,7 +1337,7 @@ async fn test_read_actual_storage_for_actual_contract() { #[tokio::test] async fn test_modify_new_storage_for_actual_contract() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let mut storage = fixture.build_account_storage().await; let contract = &ACTUAL_CONTRACT; @@ -1370,17 +1351,10 @@ async fn test_modify_new_storage_for_actual_contract() { storage.verify_regular_rent(0, 0); let new_value = [0x01u8; 32]; - assert_eq!( - storage - .set_storage( - contract.address, - ACTUAL_STORAGE_INDEX + 1, - new_value.clone() - ) - .await - .is_ok(), - true - ); + assert!(storage + .set_storage(contract.address, ACTUAL_STORAGE_INDEX + 1, new_value) + .await + .is_ok()); assert_eq!( storage .storage(contract.address, ACTUAL_STORAGE_INDEX + 1) @@ -1398,18 +1372,15 @@ async fn test_modify_new_storage_for_actual_contract() { #[tokio::test] async fn test_modify_missing_storage_for_actual_contract() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let mut storage = fixture.build_account_storage().await; let contract = &ACTUAL_CONTRACT; let new_value = [0x02u8; 32]; - assert_eq!( - storage - .set_storage(contract.address, MISSING_STORAGE_INDEX, new_value.clone()) - .await - .is_ok(), - true - ); + assert!(storage + .set_storage(contract.address, MISSING_STORAGE_INDEX, new_value) + .await + .is_ok()); assert_eq!( storage .storage(contract.address, MISSING_STORAGE_INDEX) @@ -1427,19 +1398,16 @@ async fn test_modify_missing_storage_for_actual_contract() { #[tokio::test] async fn test_modify_internal_storage_for_actual_contract() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let mut storage = fixture.build_account_storage().await; let contract = &ACTUAL_CONTRACT; let new_value = [0x03u8; 32]; let index = U256::new(0); - assert_eq!( - storage - .set_storage(contract.address, index, new_value.clone()) - .await - .is_ok(), - true - ); + assert!(storage + .set_storage(contract.address, index, new_value) + .await + .is_ok()); assert_eq!(storage.storage(contract.address, index).await, new_value); storage.verify_used_accounts(&[(fixture.contract_pubkey(contract.address), true, false)]); storage.verify_upgrade_rent(0, 0); @@ -1448,7 +1416,7 @@ async fn test_modify_internal_storage_for_actual_contract() { #[tokio::test] async fn test_read_legacy_storage_for_actual_contract() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let storage = fixture.build_account_storage().await; let contract = &ACTUAL_CONTRACT; @@ -1472,7 +1440,7 @@ async fn test_read_legacy_storage_for_actual_contract() { #[tokio::test] async fn test_read_outdate_storage_for_actual_contract() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let storage = fixture.build_account_storage().await; let contract = &ACTUAL_CONTRACT; @@ -1496,7 +1464,7 @@ async fn test_read_outdate_storage_for_actual_contract() { #[tokio::test] async fn test_read_missing_storage_for_legacy_contract() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let storage = fixture.build_account_storage().await; let contract = &LEGACY_CONTRACT; @@ -1517,7 +1485,7 @@ async fn test_read_missing_storage_for_legacy_contract() { #[tokio::test] async fn test_read_legacy_storage_for_legacy_contract() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let storage = fixture.build_account_storage().await; let contract = &LEGACY_CONTRACT; @@ -1549,7 +1517,7 @@ async fn test_read_legacy_storage_for_legacy_contract() { #[tokio::test] async fn test_read_outdate_storage_for_legacy_contract() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let storage = fixture.build_account_storage().await; let contract = &LEGACY_CONTRACT; @@ -1581,7 +1549,7 @@ async fn test_read_outdate_storage_for_legacy_contract() { #[tokio::test] async fn test_read_missing_storage_for_legacy_suicide() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let storage = fixture.build_account_storage().await; let contract = &LEGACY_SUICIDE; @@ -1602,7 +1570,7 @@ async fn test_read_missing_storage_for_legacy_suicide() { #[tokio::test] async fn test_read_outdate_storage_for_legacy_suicide() { - let fixture = Fixture::new().await; + let fixture = Fixture::new(); let storage = fixture.build_account_storage().await; let contract = &LEGACY_SUICIDE; @@ -1723,7 +1691,7 @@ async fn test_storage_with_accounts_and_override() { account_tuple.clone(), ]; let rpc_client = mock_rpc_client::MockRpcClient::new(&accounts_for_rpc); - let accounts_for_storage: Vec = vec![account_tuple.0.clone()]; + let accounts_for_storage: Vec = vec![account_tuple.0]; let storage = EmulatorAccountStorage::with_accounts( &rpc_client, program_id, @@ -1749,13 +1717,13 @@ async fn test_storage_with_accounts_and_override() { .await .expect("Failed to create storage"); assert_eq!( - get_balance_account_info(&storage, |account| account.nonce()) + get_balance_account_info(&storage, |account: &BalanceAccount| account.nonce()) .await .expect("Failed to read nonce"), expected_nonce ); assert_eq!( - get_balance_account_info(&storage, |account| account.balance()) + get_balance_account_info(&storage, |account: &BalanceAccount| account.balance()) .await .expect("Failed to read balance"), expected_balance @@ -1775,7 +1743,7 @@ async fn test_storage_new_from_other_and_override() { account_tuple.clone(), ]; let rpc_client = mock_rpc_client::MockRpcClient::new(&accounts_for_rpc); - let accounts_for_storage: Vec = vec![account_tuple.0.clone()]; + let accounts_for_storage: Vec = vec![account_tuple.0]; let storage = EmulatorAccountStorage::with_accounts( &rpc_client, program_id, @@ -1806,13 +1774,13 @@ async fn test_storage_new_from_other_and_override() { .await .expect("Failed to create a copy of storage"); assert_eq!( - get_balance_account_info(&other_storage, |account| account.nonce()) + get_balance_account_info(&other_storage, |account: &BalanceAccount| account.nonce()) .await .expect("Failed to read nonce"), expected_nonce ); assert_eq!( - get_balance_account_info(&other_storage, |account| account.balance()) + get_balance_account_info(&other_storage, |account: &BalanceAccount| account.balance()) .await .expect("Failed to read balance"), expected_balance diff --git a/evm_loader/lib/src/build_info.rs b/evm_loader/lib/src/build_info.rs index f7d76fa9a..7007d2c47 100644 --- a/evm_loader/lib/src/build_info.rs +++ b/evm_loader/lib/src/build_info.rs @@ -2,6 +2,7 @@ use crate::build_info_common::SlimBuildInfo; build_info::build_info!(fn build_info); +#[must_use] pub fn get_build_info() -> SlimBuildInfo { build_info().into() } diff --git a/evm_loader/lib/src/build_info_common.rs b/evm_loader/lib/src/build_info_common.rs index 94cff87e0..712145ca4 100644 --- a/evm_loader/lib/src/build_info_common.rs +++ b/evm_loader/lib/src/build_info_common.rs @@ -44,7 +44,7 @@ impl From<&BuildInfo> for SlimBuildInfo { .version_control .expect("Project should be built inside version control"); - SlimBuildInfo { + Self { timestamp: build_info.timestamp, profile: build_info.profile, optimization_level: build_info.optimization_level, diff --git a/evm_loader/lib/src/commands/emulate.rs b/evm_loader/lib/src/commands/emulate.rs index a385c5f39..f98c79aca 100644 --- a/evm_loader/lib/src/commands/emulate.rs +++ b/evm_loader/lib/src/commands/emulate.rs @@ -45,7 +45,7 @@ pub struct EmulateResponse { } impl EmulateResponse { - pub fn revert(e: E) -> Self { + pub fn revert(e: &E) -> Self { let revert_message = build_revert_message(&e.to_string()); let exit_status = ExitStatus::Revert(revert_message); Self { @@ -92,22 +92,18 @@ pub async fn execute( block_overrides, state_overrides, solana_overrides, - emulate_request.tx.chain_id.clone(), + emulate_request.tx.chain_id, ) .await?; - let step_limit = emulate_request.step_limit.unwrap_or(100000); + let step_limit = emulate_request.step_limit.unwrap_or(100_000); let result = emulate_trx(emulate_request.tx.clone(), &mut storage, step_limit, tracer).await?; if storage.is_timestamp_used() { - let mut storage2 = EmulatorAccountStorage::new_from_other( - &storage, - 5, - 3, - emulate_request.tx.chain_id.clone(), - ) - .await?; + let mut storage2 = + EmulatorAccountStorage::new_from_other(&storage, 5, 3, emulate_request.tx.chain_id) + .await?; if let Ok(result2) = emulate_trx( emulate_request.tx, &mut storage2, @@ -173,7 +169,7 @@ async fn emulate_trx( let mut backend = SyncedExecutorState::new(storage); let mut evm = match Machine::new(&tx, origin, &mut backend, tracer).await { Ok(evm) => evm, - Err(e) => return Ok((EmulateResponse::revert(e), None)), + Err(e) => return Ok((EmulateResponse::revert(&e), None)), }; let (exit_status, steps_executed, tracer) = evm.execute(step_limit, &mut backend).await?; diff --git a/evm_loader/lib/src/commands/get_balance.rs b/evm_loader/lib/src/commands/get_balance.rs index e9d6561a9..f0e893cf2 100644 --- a/evm_loader/lib/src/commands/get_balance.rs +++ b/evm_loader/lib/src/commands/get_balance.rs @@ -1,3 +1,5 @@ +#![allow(clippy::future_not_send)] + use ethnum::U256; use evm_loader::account::legacy::LegacyEtherData; use evm_loader::account::BalanceAccount; @@ -30,6 +32,7 @@ pub struct GetBalanceResponse { } impl GetBalanceResponse { + #[must_use] pub fn empty(program_id: &Pubkey, address: &BalanceAddress) -> Self { Self { solana_address: address.find_pubkey(program_id), diff --git a/evm_loader/lib/src/commands/get_config.rs b/evm_loader/lib/src/commands/get_config.rs index 48c01c789..3a592fafc 100644 --- a/evm_loader/lib/src/commands/get_config.rs +++ b/evm_loader/lib/src/commands/get_config.rs @@ -1,3 +1,5 @@ +#![allow(clippy::future_not_send)] + use async_trait::async_trait; use base64::Engine; use enum_dispatch::enum_dispatch; @@ -137,10 +139,10 @@ impl ConfigInstructionSimulator for SolanaSimulator { } impl ConfigSimulator<'_> { - fn program_id(&self) -> Pubkey { + const fn program_id(&self) -> Pubkey { match self { - ConfigSimulator::CloneRpcClient { program_id, .. } => *program_id, - ConfigSimulator::ProgramTestContext { program_id, .. } => *program_id, + ConfigSimulator::CloneRpcClient { program_id, .. } + | ConfigSimulator::ProgramTestContext { program_id, .. } => *program_id, } } @@ -198,9 +200,9 @@ impl ConfigSimulator<'_> { async fn get_status(&mut self) -> NeonResult { let return_data = self.simulate_evm_instruction(0xA6, &[]).await?; - match return_data[0] { - 0 => Ok(Status::Emergency), - 1 => Ok(Status::Ok), + match return_data.first() { + Some(0) => Ok(Status::Emergency), + Some(1) => Ok(Status::Ok), _ => Ok(Status::Unknown), } } @@ -299,7 +301,7 @@ mod tests { 104, 24, 221, 71, 67, 82, 33, 243, 198, 0, 0, 0, 0, ]); assert_eq!( - format!("{}", pubkey), + format!("{pubkey}"), "BPFLoader2111111111111111111111111111111111" ); } diff --git a/evm_loader/lib/src/commands/get_contract.rs b/evm_loader/lib/src/commands/get_contract.rs index 6f1a3d324..64aab5c3e 100644 --- a/evm_loader/lib/src/commands/get_contract.rs +++ b/evm_loader/lib/src/commands/get_contract.rs @@ -22,7 +22,8 @@ pub struct GetContractResponse { } impl GetContractResponse { - pub fn empty(solana_address: Pubkey) -> Self { + #[must_use] + pub const fn empty(solana_address: Pubkey) -> Self { Self { solana_address, chain_id: None, @@ -46,31 +47,35 @@ fn read_account( legacy_chain_id: u64, solana_address: Pubkey, account: Option, -) -> NeonResult { +) -> GetContractResponse { let Some(mut account) = account else { - return Ok(GetContractResponse::empty(solana_address)); + return GetContractResponse::empty(solana_address); }; let account_info = account_info(&solana_address, &mut account); - let (chain_id, code) = - if let Ok(contract) = ContractAccount::from_account(program_id, account_info.clone()) { - (Some(contract.chain_id()), contract.code().to_vec()) - } else if let Ok(contract) = LegacyEtherData::from_account(program_id, &account_info) { - if contract.code_size > 0 || contract.generation > 0 { - let code = contract.read_code(&account_info); - (Some(legacy_chain_id), code) - } else { - (None, vec![]) - } - } else { - (None, vec![]) - }; + let (chain_id, code) = ContractAccount::from_account(program_id, account_info.clone()) + .map_or_else( + |_| { + LegacyEtherData::from_account(program_id, &account_info).map_or_else( + |_| (None, vec![]), + |contract| { + if contract.code_size > 0 || contract.generation > 0 { + let code = contract.read_code(&account_info); + (Some(legacy_chain_id), code) + } else { + (None, vec![]) + } + }, + ) + }, + |contract| (Some(contract.chain_id()), contract.code().to_vec()), + ); - Ok(GetContractResponse { + GetContractResponse { solana_address, chain_id, code, - }) + } } pub async fn execute( @@ -90,7 +95,7 @@ pub async fn execute( let mut result = Vec::with_capacity(accounts.len()); for (key, account) in pubkeys.into_iter().zip(accounts) { - let response = read_account(program_id, legacy_chain_id, key, account)?; + let response = read_account(program_id, legacy_chain_id, key, account); result.push(response); } diff --git a/evm_loader/lib/src/commands/get_holder.rs b/evm_loader/lib/src/commands/get_holder.rs index 4fe77e84e..85782c81c 100644 --- a/evm_loader/lib/src/commands/get_holder.rs +++ b/evm_loader/lib/src/commands/get_holder.rs @@ -51,6 +51,7 @@ pub struct GetHolderResponse { } impl GetHolderResponse { + #[must_use] pub fn empty() -> Self { Self { status: Status::Empty, diff --git a/evm_loader/lib/src/commands/get_neon_elf.rs b/evm_loader/lib/src/commands/get_neon_elf.rs index 4f81c634d..19996a626 100644 --- a/evm_loader/lib/src/commands/get_neon_elf.rs +++ b/evm_loader/lib/src/commands/get_neon_elf.rs @@ -24,11 +24,13 @@ impl CachedElfParams { .expect("read elf_params error"), } } + #[must_use] pub fn get(&self, param_name: &str) -> Option<&String> { self.elf_params.get(param_name) } } +#[must_use] pub fn read_elf_parameters(_config: &Config, program_data: &[u8]) -> GetNeonElfReturn { let mut result = HashMap::new(); let elf = goblin::elf::Elf::parse(program_data).expect("Unable to parse ELF file"); @@ -126,7 +128,7 @@ pub fn get_elf_parameter(data: &[u8], elf_parameter: &str) -> Result { ) .context("Error parsing Symtab")?; - for sym in dynsyms.iter() { + for sym in &dynsyms { let name = &elf.dynstrtab[sym.st_name]; if name == elf_parameter { let end = program_data.len(); @@ -143,9 +145,9 @@ pub fn get_elf_parameter(data: &[u8], elf_parameter: &str) -> Result { let buf = &program_data[from..to]; let value = std::str::from_utf8(buf).context("Read ELF value error")?; return Ok(String::from(value)); - } else { - return Err(anyhow::anyhow!("{name} is out of bounds")); } + + return Err(anyhow::anyhow!("{name} is out of bounds")); } } diff --git a/evm_loader/lib/src/commands/init_environment.rs b/evm_loader/lib/src/commands/init_environment.rs index 044dfc52e..20f3e7c8a 100644 --- a/evm_loader/lib/src/commands/init_environment.rs +++ b/evm_loader/lib/src/commands/init_environment.rs @@ -47,7 +47,7 @@ struct Parameters { } impl Parameters { - pub fn new(params: HashMap) -> Self { + pub const fn new(params: HashMap) -> Self { Self { params } } @@ -117,10 +117,10 @@ pub async fn execute( send_trx, force ); - let fee_payer: &dyn Signer = match config.fee_payer.as_ref() { - Some(fee_payer) => fee_payer, - None => signer, - }; + let fee_payer: &dyn Signer = config + .fee_payer + .as_ref() + .map_or(signer, |fee_payer| fee_payer); let executor = Rc::new(TransactionExecutor::new(client, fee_payer, send_trx)); let keys = keys_dir.map_or(Ok(HashMap::new()), read_keys_dir)?; diff --git a/evm_loader/lib/src/commands/simulate_solana.rs b/evm_loader/lib/src/commands/simulate_solana.rs index de9402d16..b4aae0452 100644 --- a/evm_loader/lib/src/commands/simulate_solana.rs +++ b/evm_loader/lib/src/commands/simulate_solana.rs @@ -126,7 +126,7 @@ pub async fn execute( error: r.status.err(), logs: r.log_messages.unwrap_or_default(), executed_units: r.executed_units, - }) + }); } Ok(SimulateSolanaResponse { diff --git a/evm_loader/lib/src/commands/trace.rs b/evm_loader/lib/src/commands/trace.rs index dfb2f98fd..b3d59a321 100644 --- a/evm_loader/lib/src/commands/trace.rs +++ b/evm_loader/lib/src/commands/trace.rs @@ -1,3 +1,5 @@ +#![allow(clippy::missing_errors_doc)] + use serde_json::Value; use solana_sdk::pubkey::Pubkey; @@ -20,8 +22,8 @@ pub async fn trace_transaction( let tracer = new_tracer(&emulate_request.tx, trace_config)?; - let (_, traces) = + let (_, emulated_traces) = super::emulate::execute(rpc, program_id, emulate_request, Some(tracer)).await?; - Ok(traces.expect("traces should not be None")) + Ok(emulated_traces.expect("traces should not be None")) } diff --git a/evm_loader/lib/src/errors.rs b/evm_loader/lib/src/errors.rs index 6cc0865d9..1c3858e1c 100644 --- a/evm_loader/lib/src/errors.rs +++ b/evm_loader/lib/src/errors.rs @@ -126,7 +126,7 @@ pub enum NeonError { } impl NeonError { - pub fn error_code(&self) -> i32 { + pub const fn error_code(&self) -> u32 { match self { NeonError::IncompleteEnvironment => 50, NeonError::WrongEnvironment => 51, diff --git a/evm_loader/lib/src/lib.rs b/evm_loader/lib/src/lib.rs index 279153337..29eadd71d 100644 --- a/evm_loader/lib/src/lib.rs +++ b/evm_loader/lib/src/lib.rs @@ -1,3 +1,13 @@ +#![deny(warnings)] +#![deny(clippy::all, clippy::pedantic, clippy::nursery)] +#![allow( + clippy::future_not_send, + clippy::missing_errors_doc, + clippy::missing_panics_doc, + clippy::too_many_lines, + clippy::module_name_repetitions +)] + pub mod abi; pub mod account_data; pub mod account_storage; @@ -23,13 +33,14 @@ pub type NeonResult = Result; const MODULE: NeonEVMLib_Ref = NeonEVMLib_Ref(_MODULE_WM_.static_as_prefix()); #[export_root_module] -pub fn get_root_module() -> NeonEVMLib_Ref { +#[must_use] +pub const fn get_root_module() -> NeonEVMLib_Ref { MODULE } use strum_macros::{AsRefStr, Display, EnumString, IntoStaticStr}; -#[derive(Debug, Clone, Copy, PartialEq, Display, EnumString, IntoStaticStr, AsRefStr)] +#[derive(Debug, Clone, Copy, Eq, PartialEq, Display, EnumString, IntoStaticStr, AsRefStr)] pub enum LibMethod { #[strum(serialize = "emulate")] Emulate, diff --git a/evm_loader/lib/src/rpc/validator_client.rs b/evm_loader/lib/src/rpc/validator_client.rs index 0c84e743a..bace210c0 100644 --- a/evm_loader/lib/src/rpc/validator_client.rs +++ b/evm_loader/lib/src/rpc/validator_client.rs @@ -22,6 +22,7 @@ pub struct CloneRpcClient { } impl CloneRpcClient { + #[must_use] pub fn new_from_config(config: &Config) -> Self { let url = config.json_rpc_url.clone(); let commitment = config.commitment; @@ -33,6 +34,7 @@ impl CloneRpcClient { } } + #[must_use] pub fn new_from_api_config(config: &APIOptions) -> Self { let url = config.json_rpc_url.clone(); let commitment = config.commitment; diff --git a/evm_loader/lib/src/solana_simulator/mod.rs b/evm_loader/lib/src/solana_simulator/mod.rs index 8e9981853..1c731203c 100644 --- a/evm_loader/lib/src/solana_simulator/mod.rs +++ b/evm_loader/lib/src/solana_simulator/mod.rs @@ -63,13 +63,13 @@ impl SolanaSimulator { genesis_bank.set_capitalization(); genesis_bank.fill_bank_with_ticks_for_tests(); - let mut bank = Bank::new_from_parent( + let bank = Bank::new_from_parent( Arc::clone(&genesis_bank), genesis_bank.collector_id(), genesis_bank.slot() + 1, ); - utils::sync_sysvar_accounts(rpc, &mut bank).await?; + utils::sync_sysvar_accounts(rpc, &bank).await?; Ok(Self { bank, @@ -116,11 +116,11 @@ impl SolanaSimulator { Ok(()) } - fn bank(&self) -> &Bank { + const fn bank(&self) -> &Bank { &self.bank } - pub fn payer(&self) -> &Keypair { + pub const fn payer(&self) -> &Keypair { &self.payer } diff --git a/evm_loader/lib/src/solana_simulator/utils.rs b/evm_loader/lib/src/solana_simulator/utils.rs index 35612bd75..5fa6772d2 100644 --- a/evm_loader/lib/src/solana_simulator/utils.rs +++ b/evm_loader/lib/src/solana_simulator/utils.rs @@ -87,10 +87,9 @@ pub async fn deactivated_features(rpc: &impl Rpc) -> Result, Error> Ok(result) } -pub async fn sync_sysvar_accounts(rpc: &impl Rpc, bank: &mut Bank) -> Result<(), Error> { +pub async fn sync_sysvar_accounts(rpc: &impl Rpc, bank: &Bank) -> Result<(), Error> { let keys = sysvar::ALL_IDS.clone(); let accounts = rpc.get_multiple_accounts(&keys).await?; - for (key, account) in keys.into_iter().zip(accounts) { let Some(account) = account else { continue; diff --git a/evm_loader/lib/src/tracing/tracers/call_tracer.rs b/evm_loader/lib/src/tracing/tracers/call_tracer.rs index d9b3d2087..a455b82ec 100644 --- a/evm_loader/lib/src/tracing/tracers/call_tracer.rs +++ b/evm_loader/lib/src/tracing/tracers/call_tracer.rs @@ -23,7 +23,7 @@ pub struct CallTracer { impl CallTracer { pub fn new(trace_config: TraceConfig, tx: &TxParams) -> Self { - CallTracer { + Self { config: trace_config.into(), call_stack: vec![CallFrame { gas: tx.gas_limit.map(to_web3_u256).unwrap_or_default(), @@ -47,10 +47,11 @@ pub struct CallTracerConfig { impl From for CallTracerConfig { fn from(trace_config: TraceConfig) -> Self { - let tracer_config = trace_config + let tracer_call_config = trace_config .tracer_config .expect("tracer_config should not be None for \"callTracer\""); - serde_json::from_value(tracer_config).expect("tracer_config should be CallTracerConfig") + serde_json::from_value(tracer_call_config) + .expect("tracer_config should be CallTracerConfig") } } @@ -139,7 +140,7 @@ fn get_panic_message(reason: ethnum::U256) -> String { let reason = reason.as_u64(); PANIC_REASONS .get(&reason) - .map(|s| s.to_string()) + .map(|s| (*s).to_string()) .unwrap_or(format!("unknown panic code: {reason:#x}")) } @@ -263,7 +264,7 @@ impl CallTracer { value: Some(to_web3_u256(context.value)), type_string: opcode, ..CallFrame::default() - }) + }); } fn handle_end_vm(&mut self, status: ExitStatus) { @@ -293,9 +294,10 @@ impl CallTracer { impl Tracer for CallTracer { fn into_traces(mut self, emulator_gas_used: u64) -> Value { - if self.call_stack.len() != 1 { - panic!("incorrect number of top-level calls"); - } + assert!( + self.call_stack.len() == 1, + "incorrect number of top-level calls" + ); let call_frame = &mut self.call_stack[0]; if call_frame.gas_used.is_zero() { diff --git a/evm_loader/lib/src/tracing/tracers/mod.rs b/evm_loader/lib/src/tracing/tracers/mod.rs index cd8cd941c..3c2996334 100644 --- a/evm_loader/lib/src/tracing/tracers/mod.rs +++ b/evm_loader/lib/src/tracing/tracers/mod.rs @@ -34,10 +34,10 @@ impl EventListener for TracerTypeEnum { event: Event, ) -> evm_loader::error::Result<()> { match self { - TracerTypeEnum::StructLogger(tracer) => tracer.event(executor_state, event).await, - TracerTypeEnum::OpenEthereumTracer(tracer) => tracer.event(executor_state, event).await, - TracerTypeEnum::PrestateTracer(tracer) => tracer.event(executor_state, event).await, - TracerTypeEnum::CallTracer(tracer) => tracer.event(executor_state, event).await, + Self::StructLogger(tracer) => tracer.event(executor_state, event).await, + Self::OpenEthereumTracer(tracer) => tracer.event(executor_state, event).await, + Self::PrestateTracer(tracer) => tracer.event(executor_state, event).await, + Self::CallTracer(tracer) => tracer.event(executor_state, event).await, } } } diff --git a/evm_loader/lib/src/tracing/tracers/openeth/state_diff.rs b/evm_loader/lib/src/tracing/tracers/openeth/state_diff.rs index 7fb825e18..8fb4611d1 100644 --- a/evm_loader/lib/src/tracing/tracers/openeth/state_diff.rs +++ b/evm_loader/lib/src/tracing/tracers/openeth/state_diff.rs @@ -2,10 +2,11 @@ use crate::tracing::tracers::state_diff::StateMap; use std::collections::BTreeMap; use web3::types::{AccountDiff, ChangedType, Diff, StateDiff, H160, H256}; +#[must_use] pub fn into_state_diff(state_map: StateMap) -> StateDiff { let mut state_diff = BTreeMap::new(); - for (address, states) in state_map.into_iter() { + for (address, states) in state_map { let pre_account = states.pre; let post_account = states.post; @@ -48,7 +49,7 @@ fn storage_diff( let mut storage_diff = BTreeMap::new(); for (key, initial_value) in account_initial_storage { - let final_value = account_final_storage.get(key).cloned(); + let final_value = account_final_storage.get(key).copied(); storage_diff.insert(*key, build_diff(Some(*initial_value), final_value)); } diff --git a/evm_loader/lib/src/tracing/tracers/openeth/tracer.rs b/evm_loader/lib/src/tracing/tracers/openeth/tracer.rs index 135eecaae..a60384192 100644 --- a/evm_loader/lib/src/tracing/tracers/openeth/tracer.rs +++ b/evm_loader/lib/src/tracing/tracers/openeth/tracer.rs @@ -22,7 +22,7 @@ pub struct OpenEthereumTracer { impl OpenEthereumTracer { #[must_use] pub fn new(trace_config: TraceConfig, tx: &TxParams) -> Self { - OpenEthereumTracer { + Self { output: None, call_analytics: trace_config.into(), state_diff_tracer: StateDiffTracer::new(tx), @@ -32,10 +32,10 @@ impl OpenEthereumTracer { impl From for CallAnalytics { fn from(trace_config: TraceConfig) -> Self { - let tracer_config = trace_config + let trace_call_config = trace_config .tracer_config .expect("tracer_config should not be None for \"openethereum\" tracer"); - serde_json::from_value(tracer_config).expect("tracer_config should be CallAnalytics") + serde_json::from_value(trace_call_config).expect("tracer_config should be CallAnalytics") } } diff --git a/evm_loader/lib/src/tracing/tracers/prestate_tracer/state_diff.rs b/evm_loader/lib/src/tracing/tracers/prestate_tracer/state_diff.rs index de4dd245c..5245bb758 100644 --- a/evm_loader/lib/src/tracing/tracers/prestate_tracer/state_diff.rs +++ b/evm_loader/lib/src/tracing/tracers/prestate_tracer/state_diff.rs @@ -24,10 +24,7 @@ pub struct PrestateTracerAccount { } fn is_empty(bytes: &Option) -> bool { - match bytes { - None => true, - Some(bytes) => bytes.0.is_empty(), - } + bytes.as_ref().map_or(true, |bytes| bytes.0.is_empty()) } /// See @@ -73,25 +70,25 @@ pub fn build_prestate_tracer_diff_mode_result(state_map: StateMap) -> PrestateTr let mut modified = false; - let balance = if post_account.balance != pre_account.balance { + let balance = if post_account.balance == pre_account.balance { + None + } else { modified = true; Some(post_account.balance) - } else { - None }; - let code = if post_account.code != pre_account.code { + let code = if post_account.code == pre_account.code { + None + } else { modified = true; Some(post_account.code.clone()) - } else { - None }; - let nonce = if post_account.nonce != pre_account.nonce { + let nonce = if post_account.nonce == pre_account.nonce { + None + } else { modified = true; Some(post_account.nonce) - } else { - None }; let mut storage = BTreeMap::new(); @@ -104,7 +101,7 @@ pub fn build_prestate_tracer_diff_mode_result(state_map: StateMap) -> PrestateTr }); } - let final_value = post_account.storage.get(&key).cloned().unwrap_or_default(); + let final_value = post_account.storage.get(&key).copied().unwrap_or_default(); // Omit unchanged slots if initial_value == final_value { diff --git a/evm_loader/lib/src/tracing/tracers/prestate_tracer/tracer.rs b/evm_loader/lib/src/tracing/tracers/prestate_tracer/tracer.rs index 75857bba5..1c0916013 100644 --- a/evm_loader/lib/src/tracing/tracers/prestate_tracer/tracer.rs +++ b/evm_loader/lib/src/tracing/tracers/prestate_tracer/tracer.rs @@ -18,8 +18,9 @@ pub struct PrestateTracer { } impl PrestateTracer { + #[must_use] pub fn new(trace_config: TraceConfig, tx: &TxParams) -> Self { - PrestateTracer { + Self { config: trace_config.into(), state_diff_tracer: StateDiffTracer::new(tx), } diff --git a/evm_loader/lib/src/tracing/tracers/state_diff.rs b/evm_loader/lib/src/tracing/tracers/state_diff.rs index 84caa03e5..f01b6b328 100644 --- a/evm_loader/lib/src/tracing/tracers/state_diff.rs +++ b/evm_loader/lib/src/tracing/tracers/state_diff.rs @@ -24,6 +24,7 @@ pub struct Account { } impl Account { + #[must_use] pub fn is_empty(&self) -> bool { self.balance.is_zero() && self.nonce == 0 && self.code.0.is_empty() } @@ -36,7 +37,7 @@ pub struct States { pub pre: Account, } -fn map_code(buffer: Buffer) -> Bytes { +fn map_code(buffer: &Buffer) -> Bytes { buffer.to_vec().into() } @@ -110,7 +111,7 @@ impl EventListener for StateDiffTracer { balance: to_web3_u256( executor_state.balance(*address, chain_id).await?, ), - code: map_code(executor_state.code(*address).await?), + code: map_code(&executor_state.code(*address).await?), nonce: executor_state.nonce(*address, chain_id).await?, storage: { let mut new_storage = BTreeMap::new(); @@ -208,7 +209,7 @@ impl EventListener for StateDiffTracer { impl StateDiffTracer { pub fn new(tx: &TxParams) -> Self { - StateDiffTracer { + Self { from: tx.from, gas_price: tx.gas_price.map(to_web3_u256).unwrap_or_default(), tx_fee: to_web3_u256( @@ -216,11 +217,12 @@ impl StateDiffTracer { .unwrap_or_default() .saturating_mul(tx.gas_price.unwrap_or_default()), ), - ..StateDiffTracer::default() + ..Self::default() } } /// See + async fn lookup_account( &mut self, executor_state: &impl Database, @@ -230,10 +232,10 @@ impl StateDiffTracer { match self.state_map.entry(address) { Entry::Vacant(entry) => { entry.insert(States { - post: Default::default(), + post: Account::default(), pre: Account { balance: to_web3_u256(executor_state.balance(address, chain_id).await?), - code: map_code(executor_state.code(address).await?), + code: map_code(&executor_state.code(address).await?), nonce: executor_state.nonce(address, chain_id).await?, storage: BTreeMap::new(), }, @@ -245,6 +247,7 @@ impl StateDiffTracer { } /// See + async fn lookup_storage( &mut self, executor_state: &impl Database, @@ -270,7 +273,7 @@ impl StateDiffTracer { }; Ok(()) } - + #[must_use] pub fn into_state_map(mut self, emulator_gas_used: u64) -> StateMap { if self.tx_fee.is_zero() { self.state_map.entry(self.from).or_default().post.balance -= diff --git a/evm_loader/lib/src/tracing/tracers/struct_logger.rs b/evm_loader/lib/src/tracing/tracers/struct_logger.rs index 825153ca2..c512a67b7 100644 --- a/evm_loader/lib/src/tracing/tracers/struct_logger.rs +++ b/evm_loader/lib/src/tracing/tracers/struct_logger.rs @@ -74,7 +74,7 @@ fn is_empty(bytes: &Bytes) -> bool { /// This is only used for serialize #[allow(clippy::trivially_copy_pass_by_ref)] -fn is_zero(num: &u64) -> bool { +const fn is_zero(num: &u64) -> bool { *num == 0 } @@ -90,7 +90,7 @@ pub struct StructLogger { impl StructLogger { #[must_use] pub fn new(config: TraceConfig, tx: &TxParams) -> Self { - StructLogger { + Self { actual_gas_used: tx.actual_gas_used, config, logs: vec![], @@ -132,40 +132,37 @@ impl EventListener for StructLogger { return Ok(()); } - let storage = if !self.config.disable_storage { - if opcode == opcode_table::SLOAD && !stack.is_empty() { - let index = U256::from_be_bytes(stack[stack.len() - 1]); + let storage = if self.config.disable_storage { + None + } else if opcode == opcode_table::SLOAD && !stack.is_empty() { + let index = U256::from_be_bytes(stack[stack.len() - 1]); - self.storage.entry(context.contract).or_default().insert( - hex::encode(index.to_be_bytes()), - hex::encode(executor_state.storage(context.contract, index).await?), - ); + self.storage.entry(context.contract).or_default().insert( + hex::encode(index.to_be_bytes()), + hex::encode(executor_state.storage(context.contract, index).await?), + ); - Some( - self.storage - .get(&context.contract) - .cloned() - .unwrap_or_default(), - ) - } else if opcode == opcode_table::SSTORE && stack.len() >= 2 { - self.storage.entry(context.contract).or_default().insert( - hex::encode(stack[stack.len() - 1]), - hex::encode(stack[stack.len() - 2]), - ); + Some( + self.storage + .get(&context.contract) + .cloned() + .unwrap_or_default(), + ) + } else if opcode == opcode_table::SSTORE && stack.len() >= 2 { + self.storage.entry(context.contract).or_default().insert( + hex::encode(stack[stack.len() - 1]), + hex::encode(stack[stack.len() - 2]), + ); - Some( - self.storage - .get(&context.contract) - .cloned() - .unwrap_or_default(), - ) - } else { - None - } + Some( + self.storage + .get(&context.contract) + .cloned() + .unwrap_or_default(), + ) } else { None }; - let stack = if self.config.disable_stack { None } else { diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index 4420fc651..7d25e07fa 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -117,7 +117,7 @@ impl std::fmt::Debug for TxParams { } #[serde_as] -#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)] pub struct SerializedAccount { pub lamports: u64, #[serde_as(as = "DisplayFromStr")] @@ -130,7 +130,7 @@ pub struct SerializedAccount { impl From<&SerializedAccount> for Account { fn from(account: &SerializedAccount) -> Self { - Account { + Self { lamports: account.lamports, owner: account.owner, executable: account.executable, @@ -168,12 +168,14 @@ pub struct BalanceAddress { } impl BalanceAddress { + #[must_use] pub fn find_pubkey(&self, program_id: &Pubkey) -> Pubkey { self.address .find_balance_address(program_id, self.chain_id) .0 } + #[must_use] pub fn find_contract_pubkey(&self, program_id: &Pubkey) -> Pubkey { self.address.find_solana_address(program_id).0 } @@ -255,7 +257,7 @@ mod tests { fn test_build_ranges_empty() { let results = Vec::new(); let exp = Vec::new(); - let res = RevisionMap::build_ranges(results); + let res = RevisionMap::build_ranges(&results); assert_eq!(res, exp); } @@ -263,24 +265,24 @@ mod tests { fn test_build_ranges_single_element() { let results = vec![(1u64, String::from("Rev1"))]; let exp = vec![(1u64, 2u64, String::from("Rev1"))]; - let res = RevisionMap::build_ranges(results); + let res = RevisionMap::build_ranges(&results); assert_eq!(res, exp); } #[test] fn test_build_ranges_multiple_elements_different_revision() { let results = vec![ - (222222222u64, String::from("Rev1")), - (333333333u64, String::from("Rev2")), - (444444444u64, String::from("Rev3")), + (222_222_222u64, String::from("Rev1")), + (333_333_333u64, String::from("Rev2")), + (444_444_444u64, String::from("Rev3")), ]; let exp = vec![ - (222222222u64, 333333333u64, String::from("Rev1")), - (333333334u64, 444444444u64, String::from("Rev2")), - (444444445u64, 444444445u64, String::from("Rev3")), + (222_222_222u64, 333_333_333u64, String::from("Rev1")), + (333_333_334u64, 444_444_444u64, String::from("Rev2")), + (444_444_445u64, 444_444_445u64, String::from("Rev3")), ]; - let res = RevisionMap::build_ranges(results); + let res = RevisionMap::build_ranges(&results); assert_eq!(res, exp); } @@ -288,27 +290,27 @@ mod tests { #[test] fn test_rangemap() { let ranges = vec![ - (123456780, 123456788, String::from("Rev1")), - (123456789, 123456793, String::from("Rev2")), - (123456794, 123456799, String::from("Rev3")), + (123_456_780, 123_456_788, String::from("Rev1")), + (123_456_789, 123_456_793, String::from("Rev2")), + (123_456_794, 123_456_799, String::from("Rev3")), ]; let map = RevisionMap::new(ranges); - assert_eq!(map.get(123456779), None); // Below the bottom bound of the first range + assert_eq!(map.get(123_456_779), None); // Below the bottom bound of the first range - assert_eq!(map.get(123456780), Some(String::from("Rev1"))); // The bottom bound of the first range - assert_eq!(map.get(123456785), Some(String::from("Rev1"))); // Within the first range - assert_eq!(map.get(123456788), Some(String::from("Rev1"))); // The top bound of the first range + assert_eq!(map.get(123_456_780), Some(String::from("Rev1"))); // The bottom bound of the first range + assert_eq!(map.get(123_456_785), Some(String::from("Rev1"))); // Within the first range + assert_eq!(map.get(123_456_788), Some(String::from("Rev1"))); // The top bound of the first range - assert_eq!(map.get(123456793), Some(String::from("Rev2"))); // The bottom bound of the second range - assert_eq!(map.get(123456790), Some(String::from("Rev2"))); // Within the second range - assert_eq!(map.get(123456793), Some(String::from("Rev2"))); // The top bound of the second range + assert_eq!(map.get(123_456_793), Some(String::from("Rev2"))); // The bottom bound of the second range + assert_eq!(map.get(123_456_790), Some(String::from("Rev2"))); // Within the second range + assert_eq!(map.get(123_456_793), Some(String::from("Rev2"))); // The top bound of the second range - assert_eq!(map.get(123456799), Some(String::from("Rev3"))); // The bottom bound of the third range - assert_eq!(map.get(123456795), Some(String::from("Rev3"))); // Within the third range - assert_eq!(map.get(123456799), Some(String::from("Rev3"))); // The top bound of the third range + assert_eq!(map.get(123_456_799), Some(String::from("Rev3"))); // The bottom bound of the third range + assert_eq!(map.get(123_456_795), Some(String::from("Rev3"))); // Within the third range + assert_eq!(map.get(123_456_799), Some(String::from("Rev3"))); // The top bound of the third range - assert_eq!(map.get(123456800), None); // Beyond the top end of the last range + assert_eq!(map.get(123_456_800), None); // Beyond the top end of the last range } #[test] @@ -360,6 +362,6 @@ mod tests { "#; let request: super::EmulateRequest = serde_json::from_str(txt).unwrap(); - println!("{:?}", request); + println!("{request:?}"); } } diff --git a/evm_loader/lib/src/types/tracer_ch_common.rs b/evm_loader/lib/src/types/tracer_ch_common.rs index ad251156c..6293a8812 100644 --- a/evm_loader/lib/src/types/tracer_ch_common.rs +++ b/evm_loader/lib/src/types/tracer_ch_common.rs @@ -40,7 +40,7 @@ pub struct SlotParentRooted { impl From for SlotParent { fn from(slot_parent_rooted: SlotParentRooted) -> Self { - SlotParent { + Self { slot: slot_parent_rooted.slot, parent: slot_parent_rooted.parent, status: SlotStatus::Rooted as u8, @@ -49,7 +49,8 @@ impl From for SlotParent { } impl SlotParent { - pub fn is_rooted(&self) -> bool { + #[must_use] + pub const fn is_rooted(&self) -> bool { self.status == SlotStatus::Rooted as u8 } } @@ -67,7 +68,9 @@ pub struct AccountRow { pub lamports: u64, pub executable: bool, pub rent_epoch: u64, + #[allow(clippy::missing_fields_in_debug)] pub data: Vec, + #[allow(clippy::missing_fields_in_debug)] pub txn_signature: Vec>, } @@ -91,6 +94,8 @@ impl fmt::Debug for AccountRow { .field("lamports", &self.lamports) .field("executable", &self.executable) .field("rent_epoch", &self.rent_epoch) + .field("data", &self.data) + .field("txn_signature:", &self.txn_signature) .finish() } } @@ -122,12 +127,9 @@ pub enum EthSyncStatus { } impl EthSyncStatus { + #[must_use] pub fn new(syncing_status: Option) -> Self { - if let Some(syncing_status) = syncing_status { - Self::Syncing(syncing_status) - } else { - Self::Synced - } + syncing_status.map_or(Self::Synced, Self::Syncing) } } @@ -145,6 +147,7 @@ pub struct RevisionMap { } impl RevisionMap { + #[must_use] pub fn new(neon_revision_ranges: Vec<(u64, u64, String)>) -> Self { let mut map = BTreeMap::new(); @@ -155,13 +158,14 @@ impl RevisionMap { let last_update = std::time::Instant::now(); - RevisionMap { map, last_update } + Self { map, last_update } } // When deploying a program for the first time it is now only available in the next slot (the slot after the one the deployment transaction landed in). // When undeploying / closing a program the change is visible immediately and the very next instruction even within the transaction can not access it anymore. // When redeploying the program becomes temporarily closed immediately and will reopen with the new version in the next slot. - pub fn build_ranges(input: Vec<(u64, String)>) -> Vec<(u64, u64, String)> { + #[must_use] + pub fn build_ranges(input: &[(u64, String)]) -> Vec<(u64, u64, String)> { let mut ranges = Vec::new(); for i in 0..input.len() { @@ -180,7 +184,7 @@ impl RevisionMap { } ranges } - + #[must_use] pub fn get(&self, slot: u64) -> Option { // Check if slot is less than the starting range or // greater than the ending range diff --git a/evm_loader/lib/src/types/tracer_ch_db.rs b/evm_loader/lib/src/types/tracer_ch_db.rs index f8ab57eee..a61817420 100644 --- a/evm_loader/lib/src/types/tracer_ch_db.rs +++ b/evm_loader/lib/src/types/tracer_ch_db.rs @@ -28,6 +28,7 @@ pub struct ClickHouseDb { } impl ClickHouseDb { + #[must_use] pub fn new(config: &ChDbConfig) -> Self { let url_id = rand::thread_rng().gen_range(0..config.clickhouse_url.len()); let url = config.clickhouse_url.get(url_id).unwrap(); @@ -41,10 +42,10 @@ impl ClickHouseDb { .with_password(password), }; - ClickHouseDb { client } + Self { client } } - // return value is not used for tracer methods + // Returned value is not used for tracer methods. pub async fn get_block_time(&self, slot: Slot) -> ChResult { let time_start = Instant::now(); let query = @@ -141,9 +142,7 @@ impl ClickHouseDb { .fetch_all::() .await?; - let first = if let Some(first) = rows.pop() { - first - } else { + let Some(first) = rows.pop() else { let err = clickhouse::error::Error::Custom("Rooted slot not found".to_string()); return Err(ChError::Db(err)); }; @@ -307,7 +306,7 @@ impl ClickHouseDb { } let result = row - .map(|a| a.try_into()) + .map(std::convert::TryInto::try_into) .transpose() .map_err(|e| ChError::Db(clickhouse::error::Error::Custom(e))); @@ -351,7 +350,7 @@ impl ClickHouseDb { error!("get_account_at_index_in_block error: {e}"); ChError::Db(e) })? - .map(|a| a.try_into()) + .map(std::convert::TryInto::try_into) .transpose() .map_err(|e| ChError::Db(clickhouse::error::Error::Custom(e)))?; @@ -410,9 +409,7 @@ impl ClickHouseDb { .fetch_one::() .await, ) - .map(|slot_parent_rooted_opt| { - slot_parent_rooted_opt.map(|slot_parent_rooted| slot_parent_rooted.into()) - }) + .map(|slot_parent_rooted_opt| slot_parent_rooted_opt.map(std::convert::Into::into)) .map_err(|e| { println!("get_sol_sig_rooted_slot error: {e}"); ChError::Db(e) @@ -474,9 +471,7 @@ impl ClickHouseDb { ); } - let slot = if let Some(slot) = slot_opt { - slot - } else { + let Some(slot) = slot_opt else { return Ok(None); }; @@ -564,23 +559,19 @@ impl ClickHouseDb { .fetch_one::>() .await, )?; - - match data { - Some(data) => { - let neon_revision = - get_elf_parameter(data.as_slice(), "NEON_REVISION").map_err(|e| { - ChError::Db(clickhouse::error::Error::Custom(format!( - "Failed to get NEON_REVISION, error: {e:?}", - ))) - })?; - Ok(neon_revision) - } - None => { - let err = clickhouse::error::Error::Custom(format!( - "get_neon_revision: for slot {slot} and pubkey {pubkey} not found", - )); - Err(ChError::Db(err)) - } + if let Some(data) = data { + let neon_revision = + get_elf_parameter(data.as_slice(), "NEON_REVISION").map_err(|e| { + ChError::Db(clickhouse::error::Error::Custom(format!( + "Failed to get NEON_REVISION, error: {e:?}", + ))) + })?; + Ok(neon_revision) + } else { + let err = clickhouse::error::Error::Custom(format!( + "get_neon_revision: for slot {slot} and pubkey {pubkey} not found", + )); + Err(ChError::Db(err)) } } @@ -606,13 +597,12 @@ impl ClickHouseDb { for row in rows { let neon_revision = get_elf_parameter(&row.data, "NEON_REVISION").map_err(|e| { ChError::Db(clickhouse::error::Error::Custom(format!( - "Failed to get NEON_REVISION, error: {:?}", - e + "Failed to get NEON_REVISION, error: {e}", ))) })?; results.push((row.slot, neon_revision)); } - let ranges = RevisionMap::build_ranges(results); + let ranges = RevisionMap::build_ranges(&results); Ok(RevisionMap::new(ranges)) } @@ -631,13 +621,14 @@ impl ClickHouseDb { .fetch_one::() .await, )?; - - match slot { - Some(slot) => Ok(slot), - None => Err(ChError::Db(clickhouse::error::Error::Custom( - "get_slot_by_blockhash: no data available".to_string(), - ))), - } + slot.map_or_else( + || { + Err(ChError::Db(clickhouse::error::Error::Custom( + "get_slot_by_blockhash: no data available".to_string(), + ))) + }, + Ok, + ) } pub async fn get_sync_status(&self) -> ChResult { @@ -657,7 +648,7 @@ impl ClickHouseDb { .await, )?; - if let Some(true) = is_startup { + if is_startup == Some(true) { let query = r#"SELECT slot FROM ( (SELECT MIN(slot) as slot FROM events.notify_block_distributed) @@ -671,12 +662,14 @@ impl ClickHouseDb { let data = Self::row_opt(self.client.query(query).fetch_one::().await)?; - return match data { - Some(data) => Ok(EthSyncStatus::new(Some(data))), - None => Err(ChError::Db(clickhouse::error::Error::Custom( - "get_sync_status: no data available".to_string(), - ))), - }; + return data.map_or_else( + || { + Err(ChError::Db(clickhouse::error::Error::Custom( + "get_sync_status: no data available".to_string(), + ))) + }, + |data| Ok(EthSyncStatus::new(Some(data))), + ); } Ok(EthSyncStatus::new(None)) diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index d25dbf3e9..37933a375 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -72,6 +72,3 @@ crate-type = ["cdylib", "lib"] [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] - -[profile.test] -debug = true diff --git a/evm_loader/program/src/evm/mod.rs b/evm_loader/program/src/evm/mod.rs index 6399e305a..f409893b3 100644 --- a/evm_loader/program/src/evm/mod.rs +++ b/evm_loader/program/src/evm/mod.rs @@ -1,6 +1,7 @@ #![allow(clippy::trait_duplication_in_bounds)] #![allow(clippy::type_repetition_in_bounds)] #![allow(clippy::unsafe_derive_deserialize)] +#![allow(clippy::future_not_send)] use std::{fmt::Display, marker::PhantomData, ops::Range}; diff --git a/evm_loader/rpc-client/src/config.rs b/evm_loader/rpc-client/src/config.rs index 41a62c1fe..f26026b01 100644 --- a/evm_loader/rpc-client/src/config.rs +++ b/evm_loader/rpc-client/src/config.rs @@ -3,7 +3,7 @@ pub struct NeonRpcClientConfig { } impl NeonRpcClientConfig { - pub fn new(url: impl Into) -> NeonRpcClientConfig { - NeonRpcClientConfig { url: url.into() } + pub fn new(url: impl Into) -> Self { + Self { url: url.into() } } } diff --git a/evm_loader/rpc-client/src/http.rs b/evm_loader/rpc-client/src/http.rs index 9312d20c7..d81134619 100644 --- a/evm_loader/rpc-client/src/http.rs +++ b/evm_loader/rpc-client/src/http.rs @@ -1,3 +1,5 @@ +#![allow(clippy::future_not_send)] + use async_trait::async_trait; use jsonrpsee_core::{client::ClientT, rpc_params}; use jsonrpsee_http_client::{HttpClient, HttpClientBuilder}; @@ -23,8 +25,8 @@ pub struct NeonRpcHttpClient { } impl NeonRpcHttpClient { - pub async fn new(config: NeonRpcClientConfig) -> NeonRpcClientResult { - Ok(NeonRpcHttpClient { + pub fn new(config: NeonRpcClientConfig) -> NeonRpcClientResult { + Ok(Self { client: HttpClientBuilder::default().build(config.url)?, }) } @@ -33,13 +35,14 @@ impl NeonRpcHttpClient { pub struct NeonRpcHttpClientBuilder {} impl NeonRpcHttpClientBuilder { - pub fn new() -> NeonRpcHttpClientBuilder { - NeonRpcHttpClientBuilder {} + #[must_use] + pub const fn new() -> Self { + Self {} } - pub async fn build(&self, url: impl Into) -> NeonRpcClientResult { + pub fn build(&self, url: impl Into) -> NeonRpcClientResult { let config = NeonRpcClientConfig::new(url); - NeonRpcHttpClient::new(config).await + NeonRpcHttpClient::new(config) } } diff --git a/evm_loader/rpc-client/src/lib.rs b/evm_loader/rpc-client/src/lib.rs index 609805d17..36233df2f 100644 --- a/evm_loader/rpc-client/src/lib.rs +++ b/evm_loader/rpc-client/src/lib.rs @@ -1,3 +1,7 @@ +#![deny(warnings)] +#![deny(clippy::all, clippy::pedantic, clippy::nursery)] +#![allow(clippy::module_name_repetitions, clippy::missing_errors_doc)] + mod config; mod error; pub mod http; diff --git a/evm_loader/rpc/src/error.rs b/evm_loader/rpc/src/error.rs index bc7f2818f..18119963f 100644 --- a/evm_loader/rpc/src/error.rs +++ b/evm_loader/rpc/src/error.rs @@ -22,6 +22,6 @@ pub enum NeonRPCError { impl From for jsonrpc_v2::Error { fn from(value: NeonRPCError) -> Self { - jsonrpc_v2::Error::internal(value) + Self::internal(value) } } diff --git a/evm_loader/rpc/src/handlers/emulate.rs b/evm_loader/rpc/src/handlers/emulate.rs index 9e068282c..b169683b0 100644 --- a/evm_loader/rpc/src/handlers/emulate.rs +++ b/evm_loader/rpc/src/handlers/emulate.rs @@ -1,3 +1,5 @@ +#![allow(clippy::future_not_send)] + use super::invoke; use crate::{context::Context, error::NeonRPCError}; use jsonrpc_v2::{Data, Params}; diff --git a/evm_loader/rpc/src/handlers/get_balance.rs b/evm_loader/rpc/src/handlers/get_balance.rs index 5d78d4b95..5ecaefd9f 100644 --- a/evm_loader/rpc/src/handlers/get_balance.rs +++ b/evm_loader/rpc/src/handlers/get_balance.rs @@ -1,3 +1,5 @@ +#![allow(clippy::future_not_send)] + use super::invoke; use crate::{context::Context, error::NeonRPCError}; use jsonrpc_v2::{Data, Params}; diff --git a/evm_loader/rpc/src/handlers/get_config.rs b/evm_loader/rpc/src/handlers/get_config.rs index d7f579eb7..b1f1f4c74 100644 --- a/evm_loader/rpc/src/handlers/get_config.rs +++ b/evm_loader/rpc/src/handlers/get_config.rs @@ -1,3 +1,5 @@ +#![allow(clippy::future_not_send)] + use super::invoke; use crate::context::Context; use jsonrpc_v2::Data; diff --git a/evm_loader/rpc/src/handlers/get_contract.rs b/evm_loader/rpc/src/handlers/get_contract.rs index 422bd73b4..094246593 100644 --- a/evm_loader/rpc/src/handlers/get_contract.rs +++ b/evm_loader/rpc/src/handlers/get_contract.rs @@ -1,3 +1,5 @@ +#![allow(clippy::future_not_send)] + use super::invoke; use crate::{context::Context, error::NeonRPCError}; use jsonrpc_v2::{Data, Params}; diff --git a/evm_loader/rpc/src/handlers/get_holder.rs b/evm_loader/rpc/src/handlers/get_holder.rs index 8140401bf..2c8efa2fc 100644 --- a/evm_loader/rpc/src/handlers/get_holder.rs +++ b/evm_loader/rpc/src/handlers/get_holder.rs @@ -1,3 +1,5 @@ +#![allow(clippy::future_not_send)] + use super::invoke; use crate::{context::Context, error::NeonRPCError}; use jsonrpc_v2::{Data, Params}; diff --git a/evm_loader/rpc/src/handlers/get_storage_at.rs b/evm_loader/rpc/src/handlers/get_storage_at.rs index 8bf80a4a9..2e265e7e7 100644 --- a/evm_loader/rpc/src/handlers/get_storage_at.rs +++ b/evm_loader/rpc/src/handlers/get_storage_at.rs @@ -1,3 +1,5 @@ +#![allow(clippy::future_not_send)] + use super::invoke; use crate::{context::Context, error::NeonRPCError}; use jsonrpc_v2::{Data, Params}; diff --git a/evm_loader/rpc/src/handlers/mod.rs b/evm_loader/rpc/src/handlers/mod.rs index 08f6f978d..ea541301a 100644 --- a/evm_loader/rpc/src/handlers/mod.rs +++ b/evm_loader/rpc/src/handlers/mod.rs @@ -1,3 +1,5 @@ +#![allow(clippy::future_not_send)] + pub mod emulate; pub mod get_balance; pub mod get_config; @@ -15,20 +17,17 @@ use neon_lib_interface::{types::NeonEVMLibError, NeonEVMLib_Ref}; use serde::Serialize; use serde_json::Value; -async fn get_library(context: &Data) -> Result<&NeonEVMLib_Ref, jsonrpc_v2::Error> { +fn get_library(context: &Data) -> Result<&NeonEVMLib_Ref, jsonrpc_v2::Error> { // just for testing let hash = context .libraries .keys() .last() - .ok_or(jsonrpc_v2::Error::internal("library collection is empty"))?; - - let library = context - .libraries - .get(hash) - .ok_or(jsonrpc_v2::Error::internal(format!( - "Library not found for hash {hash}" - )))?; + .ok_or_else(|| jsonrpc_v2::Error::internal("library collection is empty")); + let has_ref = &hash?.clone(); + let library = context.libraries.get(has_ref).ok_or_else(|| { + jsonrpc_v2::Error::internal(format!("Library not found for hash {has_ref:?}")) + })?; tracing::debug!("ver {:?}", library.hash()()); @@ -40,10 +39,10 @@ pub async fn invoke( context: Data, params: Option, ) -> Result { - let library = get_library(&context).await?; + let library = get_library(&context)?; let method_str: &str = method.into(); - let mut params_str: String = "".to_string(); + let mut params_str: String = String::new(); if let Some(params_value) = params { params_str = serde_json::to_string(¶ms_value).unwrap(); } @@ -59,7 +58,7 @@ pub async fn invoke( } = serde_json::from_str(s.as_str()).unwrap(); jsonrpc_v2::Error::Full { - code: code as i64, + code: i64::from(code), message, data: Some(Box::new( data.as_ref() @@ -75,7 +74,7 @@ pub async fn invoke( pub async fn lib_build_info( context: Data, ) -> Result { - let library = get_library(&context).await?; + let library = get_library(&context)?; let build_info = library.get_build_info()(); Ok(serde_json::from_str::(&build_info).unwrap()) diff --git a/evm_loader/rpc/src/handlers/trace.rs b/evm_loader/rpc/src/handlers/trace.rs index 826c65f5c..dd38ffaa5 100644 --- a/evm_loader/rpc/src/handlers/trace.rs +++ b/evm_loader/rpc/src/handlers/trace.rs @@ -1,3 +1,5 @@ +#![allow(clippy::future_not_send)] + use super::invoke; use crate::{context::Context, error::NeonRPCError}; use jsonrpc_v2::{Data, Params}; diff --git a/evm_loader/rpc/src/main.rs b/evm_loader/rpc/src/main.rs index 7c0f5a7af..921947704 100644 --- a/evm_loader/rpc/src/main.rs +++ b/evm_loader/rpc/src/main.rs @@ -1,3 +1,7 @@ +#![deny(warnings)] +#![deny(clippy::all, clippy::pedantic, clippy::nursery)] +#![allow(clippy::module_name_repetitions)] + // use std::{collections::HashMap, error::Error}; mod build_info; mod context; @@ -54,7 +58,9 @@ async fn main() -> NeonRPCResult<()> { let listener_addr = matches .value_of("host") .map(std::borrow::ToOwned::to_owned) - .or_else(|| Some(env::var("NEON_API_LISTENER_ADDR").unwrap_or("0.0.0.0:3100".to_owned()))) + .or_else(|| { + Some(env::var("NEON_API_LISTENER_ADDR").unwrap_or_else(|_| "0.0.0.0:3100".to_owned())) + }) .unwrap(); let addr = SocketAddr::from_str(listener_addr.as_str())?; From 63e97cbf46285afc4e2a55510f7072d386c5a27e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 May 2024 15:58:27 +0300 Subject: [PATCH 203/318] --- (#433) updated-dependencies: - dependency-name: proc-macro2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 806900951..2cdb5b8bc 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -3987,9 +3987,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.80" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56dea16b0a29e94408b9aa5e2940a4eedbd128a1ba20e8f7ae60fd3d465af0e" +checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" dependencies = [ "unicode-ident", ] From 4e03cae71043f118900c9419fec5c1638b6aed71 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Wed, 22 May 2024 17:14:18 +0300 Subject: [PATCH 204/318] NDEV-3034: Remove unused solana_emulator module (#423) --- evm_loader/lib/src/solana_emulator.rs | 439 -------------------------- 1 file changed, 439 deletions(-) delete mode 100644 evm_loader/lib/src/solana_emulator.rs diff --git a/evm_loader/lib/src/solana_emulator.rs b/evm_loader/lib/src/solana_emulator.rs deleted file mode 100644 index 0b5eb55c2..000000000 --- a/evm_loader/lib/src/solana_emulator.rs +++ /dev/null @@ -1,439 +0,0 @@ -use solana_banks_interface::TransactionMetadata; -use solana_program_test::{ - processor, BanksClientError, BanksTransactionResultWithMetadata, ProgramTest, - ProgramTestContext, -}; -use solana_sdk::{ - account::AccountSharedData, - account::WritableAccount, - account::{Account, ReadableAccount}, - account_info::AccountInfo, - bpf_loader_upgradeable::{self, UpgradeableLoaderState}, - instruction::{AccountMeta, Instruction}, - message::Message, - program_error::ProgramError, - pubkey, - pubkey::Pubkey, - rent::Rent, - signature::Signer, - system_instruction::MAX_PERMITTED_DATA_LENGTH, - transaction::{Transaction, TransactionError}, -}; - -use log::info; -use maybe_async::maybe_async; -use tokio::sync::{Mutex, MutexGuard, OnceCell}; - -use crate::rpc::Rpc; -use crate::NeonError; - -#[maybe_async(?Send)] -pub trait ProgramCache { - type Error: std::error::Error; - - async fn get_account(&self, pubkey: Pubkey) -> Result, Self::Error>; - - async fn get_programdata( - &self, - programdata_pubkey: Pubkey, - ) -> evm_loader::error::Result> { - info!("ProgramData pubkey: {:?}", programdata_pubkey); - let programdata = self - .get_account(programdata_pubkey) - .await - .map_err(|e| evm_loader::error::Error::Custom(e.to_string()))? - .ok_or(ProgramError::UninitializedAccount)?; - if programdata.owner == bpf_loader_upgradeable::ID { - if let UpgradeableLoaderState::ProgramData { .. } = - bincode::deserialize(&programdata.data)? - { - return Ok(programdata.data - [UpgradeableLoaderState::size_of_programdata_metadata()..] - .to_vec()); - } - } - Err(solana_sdk::program_error::ProgramError::InvalidAccountData.into()) - } -} - -/// SolanaEmulator -/// Note: -/// 1. Use global program_stubs variable (new() function changes it inside ProgramTest::start_with_context) -/// 2. Get list of activated features from solana cluster (this list can't be changed after initialization) -pub struct SolanaEmulator { - pub program_id: Pubkey, - pub emulator_context: ProgramTestContext, - pub evm_loader_program: Account, -} - -static SOLANA_EMULATOR: OnceCell> = OnceCell::const_new(); -const SEEDS_PUBKEY: Pubkey = pubkey!("Seeds11111111111111111111111111111111111111"); - -pub async fn get_solana_emulator() -> MutexGuard<'static, SolanaEmulator> { - SOLANA_EMULATOR - .get() - .expect("SolanaEmulator is not initialized") - .lock() - .await -} - -pub async fn init_solana_emulator( - program_id: Pubkey, - rpc_client: &impl Rpc, -) -> &'static Mutex { - SOLANA_EMULATOR - .get_or_init(|| async { - let emulator = SolanaEmulator::new(program_id, rpc_client) - .await - .expect("Initialize SolanaEmulator"); - - Mutex::new(emulator) - }) - .await -} - -// evm_loader stub to call solana programs like from original program -// Pass signer seeds through the special account's data. -fn process_emulator_instruction( - program_id: &Pubkey, - accounts: &[AccountInfo], - instruction_data: &[u8], -) -> solana_sdk::entrypoint::ProgramResult { - let seeds: Vec>> = bincode::deserialize(&accounts[0].data.borrow()) - .map_err(|_| ProgramError::InvalidAccountData)?; - let seeds = seeds - .iter() - .map(|s| s.iter().map(|s| s.as_slice()).collect::>()) - .collect::>(); - let seeds = seeds.iter().map(|s| s.as_slice()).collect::>(); - - let signers = seeds - .iter() - .map(|s| { - Pubkey::create_program_address(s, program_id).map_err(|_| ProgramError::InvalidSeeds) - }) - .collect::, _>>()?; - - let instruction = Instruction::new_with_bytes( - *accounts[1].key, - instruction_data, - accounts[2..] - .iter() - .map(|a| AccountMeta { - pubkey: *a.key, - is_signer: if signers.contains(a.key) { - true - } else { - a.is_signer - }, - is_writable: a.is_writable, - }) - .collect::>(), - ); - - solana_sdk::program::invoke_signed_unchecked(&instruction, accounts, &seeds) -} - -impl SolanaEmulator { - pub async fn new( - program_id: Pubkey, - rpc_client: &impl Rpc, - ) -> Result { - let mut program_test = ProgramTest::default(); - program_test.prefer_bpf(false); - program_test.add_program( - "evm_loader", - program_id, - processor!(process_emulator_instruction), - ); - - // Disable features (get known feature list and disable by actual value) - let feature_list = solana_sdk::feature_set::FEATURE_NAMES - .iter() - .map(|feature| feature.0) - .cloned() - .collect::>(); - let features = rpc_client.get_multiple_accounts(&feature_list).await?; - - feature_list - .into_iter() - .zip(features) - .filter_map(|(pubkey, account)| { - let activated = account - .and_then(|ref acc| solana_sdk::feature::from_account(acc)) - .and_then(|v| v.activated_at); - match activated { - Some(_) => None, - None => Some(pubkey), - } - }) - .for_each(|feature_id| program_test.deactivate_feature(feature_id)); - - let mut emulator_context = program_test.start_with_context().await; - let evm_loader_program = emulator_context - .banks_client - .get_account(program_id) - .await - .expect("Can't get evm_loader program account") - .expect("evm_loader program account not found"); - - Ok(Self { - program_id, - emulator_context, - evm_loader_program, - }) - } - - pub fn payer(&self) -> Pubkey { - self.emulator_context.payer.pubkey() - } - - async fn set_programdata( - &mut self, - program_id: Pubkey, - programdata_address: Pubkey, - programdata: &mut Vec, - ) -> evm_loader::error::Result<()> { - if self - .emulator_context - .banks_client - .get_account(program_id) - .await - .map_err(|e| evm_loader::error::Error::Custom(e.to_string()))? - .is_none() - { - // Deploy new program - let mut program_account = AccountSharedData::new_data( - Rent::default().minimum_balance(programdata.len()), - &UpgradeableLoaderState::Program { - programdata_address, - }, - &bpf_loader_upgradeable::ID, - )?; - program_account.set_executable(true); - - let mut programdata_data = bincode::serialize(&UpgradeableLoaderState::ProgramData { - slot: 0, - upgrade_authority_address: Some(self.payer()), - })?; - programdata_data.append(programdata); - let mut programdata_account = AccountSharedData::new( - Rent::default().minimum_balance(programdata_data.len()), - programdata_data.len(), - &bpf_loader_upgradeable::ID, - ); - programdata_account.set_data(programdata_data); - - self.emulator_context - .set_account(&program_id, &program_account); - self.emulator_context - .set_account(&programdata_address, &programdata_account); - } else { - // Upgrade program - // let mut program_buffer = bincode::serialize( - // &UpgradeableLoaderState::Buffer { - // authority_address: Some(self.get_pubkey()) - // } - // )?; - // program_buffer.append(programdata); - // self.emulator_context.set_account(&BUFFER_PUBKEY, &Account { - // lamports: Rent::default().minimum_balance(program_buffer.len()), - // data: program_buffer, - // owner: solana_sdk::bpf_loader_upgradeable::ID, - // executable: false, - // rent_epoch: 0, - // }.into()); - - // self.process_transaction(&[ - // bpf_loader_upgradeable::upgrade( - // &program_id, - // &BUFFER_PUBKEY, - // &self.get_pubkey(), - // &self.get_pubkey(), - // ), - // ]).await?; - } - Ok(()) - } - - async fn set_account<'a, B: ProgramCache>( - &mut self, - program_cache: &B, - pubkey: &Pubkey, - account: &AccountSharedData, - ) -> evm_loader::error::Result<()> { - if *pubkey == self.payer() { - return Err(evm_loader::error::Error::InvalidAccountForCall(*pubkey)); - } - - if solana_sdk::bpf_loader_upgradeable::check_id(account.owner()) { - if let UpgradeableLoaderState::Program { - programdata_address, - } = account - .deserialize_data() - .map_err(|_| evm_loader::error::Error::AccountInvalidData(*pubkey))? - { - let mut programdata = program_cache.get_programdata(programdata_address).await?; - self.set_programdata(*pubkey, programdata_address, &mut programdata) - .await?; - info!("set_programdata: {:?}", pubkey); - return Ok(()); - } - } - - self.emulator_context.set_account(pubkey, account); - Ok(()) - } - - async fn prepare_transaction( - &mut self, - instructions: &[Instruction], - ) -> evm_loader::error::Result { - self.emulator_context - .get_new_latest_blockhash() - .await - .map_err(|e| evm_loader::error::Error::Custom(e.to_string()))?; - - let mut trx = Transaction::new_unsigned(Message::new(instructions, Some(&self.payer()))); - - trx.try_sign( - &[&self.emulator_context.payer], - self.emulator_context.last_blockhash, - ) - .map_err(|e| evm_loader::error::Error::Custom(e.to_string()))?; - - Ok(trx) - } - - pub async fn emulate_solana_call<'a, B: ProgramCache>( - &mut self, - program_cache: &B, - instruction: &Instruction, - accounts: &[AccountInfo<'a>], - seeds: &[Vec>], - ) -> evm_loader::error::Result> { - for account in accounts { - self.set_account(program_cache, account.key, &from_account_info(account)) - .await?; - } - - let signers = seeds - .iter() - .map(|s| { - let seed = s.iter().map(|s| s.as_slice()).collect::>(); - Pubkey::create_program_address(&seed, &self.program_id) - .expect("Create signer from seeds") - }) - .collect::>(); - - self.set_account( - program_cache, - &SEEDS_PUBKEY, - &AccountSharedData::new_data( - Rent::default().minimum_balance(MAX_PERMITTED_DATA_LENGTH as usize), - &seeds, - &self.program_id, - )?, - ) - .await?; - - let mut accounts_meta = vec![ - AccountMeta::new_readonly(SEEDS_PUBKEY, false), - AccountMeta::new_readonly(instruction.program_id, false), - ]; - accounts_meta.extend(instruction.accounts.iter().map(|m| AccountMeta { - pubkey: m.pubkey, - is_signer: !signers.contains(&m.pubkey) && m.is_signer, - is_writable: m.is_writable, - })); - - let emulate_trx = self - .prepare_transaction(&[Instruction::new_with_bytes( - self.program_id, - &instruction.data, - accounts_meta, - )]) - .await?; - - let trx_metadata = match self - .emulator_context - .banks_client - .process_transaction_with_metadata(emulate_trx) - .await - { - Ok(BanksTransactionResultWithMetadata { - result: Ok(()), - metadata, - }) => Ok(metadata), - Ok(BanksTransactionResultWithMetadata { - result: Err(err), .. - }) - | Err(BanksClientError::SimulationError { err, .. }) - | Err(BanksClientError::TransactionError(err)) => match err { - TransactionError::InstructionError(_, err) => { - Err(evm_loader::error::Error::ExternalCallFailed( - instruction.program_id, - err.to_string(), - )) - } - _ => Err(evm_loader::error::Error::Custom(err.to_string())), - }, - Err(err) => Err(evm_loader::error::Error::Custom(err.to_string())), - }?; - - let next_slot = self - .emulator_context - .banks_client - .get_root_slot() - .await - .unwrap() - + 1; - self.emulator_context - .warp_to_slot(next_slot) - .expect("Warp to next slot"); - - // Update writable accounts - let payer = self.payer(); - for pubkey in instruction.accounts.iter().filter_map(|m| { - if m.is_writable && m.pubkey != payer { - Some(m.pubkey) - } else { - None - } - }) { - let account = self - .emulator_context - .banks_client - .get_account(pubkey) - .await - .unwrap() - .unwrap_or_default(); - - let original = accounts - .iter() - .find(|a| a.key == &pubkey) - .expect("Missing pubkey in accounts map"); - - **original.try_borrow_mut_lamports()? = account.lamports; - if original.data_len() != account.data.len() { - original.realloc(account.data.len(), true)?; - } - original - .try_borrow_mut_data()? - .copy_from_slice(account.data.as_slice()); - if *original.owner != account.owner { - original.assign(&account.owner); - } - } - - Ok(trx_metadata) - } -} - -fn from_account_info(account: &AccountInfo) -> AccountSharedData { - let mut acc = AccountSharedData::new(account.lamports(), 0, account.owner); - acc.set_data(account.data.as_ref().borrow().to_vec()); - acc.set_executable(account.executable); - acc.set_rent_epoch(account.rent_epoch); - acc -} From 20fbec7b8a76c2d6a27f7556777de1391c4b5e0e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 May 2024 17:54:12 +0300 Subject: [PATCH 205/318] --- (#436) updated-dependencies: - dependency-name: actix-web dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 50 +++++++++++++++++++++++++++++++-------- evm_loader/api/Cargo.toml | 2 +- evm_loader/rpc/Cargo.toml | 2 +- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 2cdb5b8bc..89f580b2a 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -79,18 +79,18 @@ dependencies = [ [[package]] name = "actix-http" -version = "3.6.0" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d223b13fd481fc0d1f83bb12659ae774d9e3601814c68a0bc539731698cca743" +checksum = "4eb9843d84c775696c37d9a418bbb01b932629d01870722c0f13eb3f95e2536d" dependencies = [ "actix-codec", "actix-rt", "actix-service", "actix-utils", "ahash 0.8.5", - "base64 0.21.7", + "base64 0.22.1", "bitflags 2.4.0", - "brotli", + "brotli 6.0.0", "bytes", "bytestring", "derive_more", @@ -139,13 +139,15 @@ dependencies = [ [[package]] name = "actix-router" -version = "0.5.1" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66ff4d247d2b160861fa2866457e85706833527840e4133f8f49aa423a38799" +checksum = "13d324164c51f63867b57e73ba5936ea151b8a41a1d23d1031eeb9f70d0236f8" dependencies = [ "bytestring", + "cfg-if", "http", "regex", + "regex-lite", "serde", "tracing", ] @@ -200,9 +202,9 @@ dependencies = [ [[package]] name = "actix-web" -version = "4.5.1" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a6556ddebb638c2358714d853257ed226ece6023ef9364f23f0c70737ea984" +checksum = "b1cf67dadb19d7c95e5a299e2dda24193b89d5d4f33a3b9800888ede9e19aa32" dependencies = [ "actix-codec", "actix-http", @@ -229,6 +231,7 @@ dependencies = [ "once_cell", "pin-project-lite", "regex", + "regex-lite", "serde", "serde_json", "serde_urlencoded", @@ -594,7 +597,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d495b6dc0184693324491a5ac05f559acc97bf937ab31d7a1c33dd0016be6d2b" dependencies = [ - "brotli", + "brotli 3.3.4", "flate2", "futures-core", "memchr", @@ -884,7 +887,18 @@ checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", - "brotli-decompressor", + "brotli-decompressor 2.3.4", +] + +[[package]] +name = "brotli" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor 4.0.0", ] [[package]] @@ -897,6 +911,16 @@ dependencies = [ "alloc-stdlib", ] +[[package]] +name = "brotli-decompressor" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6221fe77a248b9117d431ad93761222e1cf8ff282d9d1d5d9f53d6299a1cf76" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + [[package]] name = "bs58" version = "0.4.0" @@ -4289,6 +4313,12 @@ dependencies = [ "regex-syntax 0.8.2", ] +[[package]] +name = "regex-lite" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b661b2f27137bdbc16f00eda72866a92bb28af1753ffbd56744fb6e2e9cd8e" + [[package]] name = "regex-syntax" version = "0.6.29" diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 459b8fef6..654da8021 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -18,7 +18,7 @@ tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } tracing-appender = "0.2.3" neon-lib = { path = "../lib" } -actix-web = "4.5.1" +actix-web = "4.6.0" actix-request-identifier = "4.2.0" hex = "0.4.2" build-info = { version = "0.0.31", features = ["serde"] } diff --git a/evm_loader/rpc/Cargo.toml b/evm_loader/rpc/Cargo.toml index 29b248823..85d089335 100644 --- a/evm_loader/rpc/Cargo.toml +++ b/evm_loader/rpc/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -actix-web = "4.5.1" +actix-web = "4.6.0" clap = "2.33.3" jsonrpc-v2 = "0.13.0" neon-lib-interface = { path = "../lib-interface" } From 61e03efbd7437039de085b99c6907adfe16111a7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 May 2024 18:55:29 +0300 Subject: [PATCH 206/318] Bump serde_json from 1.0.115 to 1.0.117 in /evm_loader (#437) Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.115 to 1.0.117. - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.115...v1.0.117) --- updated-dependencies: - dependency-name: serde_json dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- evm_loader/api/Cargo.toml | 2 +- evm_loader/cli/Cargo.toml | 2 +- evm_loader/lib-interface/Cargo.toml | 2 +- evm_loader/program/Cargo.toml | 2 +- evm_loader/rpc-client/Cargo.toml | 2 +- evm_loader/rpc/Cargo.toml | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 89f580b2a..d11ccfbfa 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -4722,9 +4722,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.115" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ "indexmap 2.2.3", "itoa", diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 654da8021..7db35bf01 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -11,7 +11,7 @@ evm-loader = { path = "../program", default-features = false, features = ["log"] solana-sdk.workspace = true solana-client.workspace = true serde = "1.0.202" -serde_json = { version = "1.0.115", features = ["preserve_order"] } +serde_json = { version = "1.0.117", features = ["preserve_order"] } ethnum = { version = "1.5", default-features = false, features = ["serde"] } tokio = { version = "1", features = ["full"] } tracing = "0.1" diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index fa9b0dd4f..8233fcda8 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -14,7 +14,7 @@ solana-clap-utils.workspace = true solana-cli-config.workspace = true hex = "0.4.2" serde = "1.0.202" -serde_json = { version = "1.0.115", features = ["preserve_order"] } +serde_json = { version = "1.0.117", features = ["preserve_order"] } log = "0.4.21" fern = "0.6" ethnum = { version = "1.5", default-features = false, features = ["serde"] } diff --git a/evm_loader/lib-interface/Cargo.toml b/evm_loader/lib-interface/Cargo.toml index efd4af896..d7e8c2f30 100644 --- a/evm_loader/lib-interface/Cargo.toml +++ b/evm_loader/lib-interface/Cargo.toml @@ -10,4 +10,4 @@ abi_stable = "0.11.1" thiserror = "1" async-ffi = { version = "0.5.0", features = ["abi_stable"] } serde = "1.0.202" -serde_json = "1.0.115" +serde_json = "1.0.117" diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 37933a375..f466dcb67 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -63,7 +63,7 @@ features = ["is_sync"] [dev-dependencies] tokio = { version = "1.0", features = ["full"] } -serde_json = { version = "1.0.115", features = ["preserve_order"] } +serde_json = { version = "1.0.117", features = ["preserve_order"] } solana-sdk.workspace = true diff --git a/evm_loader/rpc-client/Cargo.toml b/evm_loader/rpc-client/Cargo.toml index 4171eb9f6..0c1950900 100644 --- a/evm_loader/rpc-client/Cargo.toml +++ b/evm_loader/rpc-client/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] serde = "1.0.202" -serde_json = "1.0.115" +serde_json = "1.0.117" neon-lib = { path = "../lib" } thiserror = "1.0.58" async-trait = "0.1.80" diff --git a/evm_loader/rpc/Cargo.toml b/evm_loader/rpc/Cargo.toml index 85d089335..707283f1a 100644 --- a/evm_loader/rpc/Cargo.toml +++ b/evm_loader/rpc/Cargo.toml @@ -13,7 +13,7 @@ neon-lib-interface = { path = "../lib-interface" } neon-lib = { path = "../lib" } semver = "1.0.23" serde = "1.0.202" -serde_json = "1.0.115" +serde_json = "1.0.117" tokio = { version = "1", features = ["full"] } build-info = { version = "0.0.31", features = ["serde"] } thiserror = "1.0" From 336d75f30b7bf24671798b5d254e0a0fa285228b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 May 2024 10:05:45 +0300 Subject: [PATCH 207/318] Bump itertools from 0.12.1 to 0.13.0 in /evm_loader (#439) Bumps [itertools](https://github.com/rust-itertools/itertools) from 0.12.1 to 0.13.0. - [Changelog](https://github.com/rust-itertools/itertools/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-itertools/itertools/compare/v0.12.1...v0.13.0) --- updated-dependencies: - dependency-name: itertools dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 6 +++--- evm_loader/program-macro/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index d11ccfbfa..bbd5882c7 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -2038,7 +2038,7 @@ name = "evm-loader-macro" version = "1.0.0" dependencies = [ "bs58 0.5.1", - "itertools 0.12.1", + "itertools 0.13.0", "proc-macro2", "quote", "serde", @@ -2810,9 +2810,9 @@ dependencies = [ [[package]] name = "itertools" -version = "0.12.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] diff --git a/evm_loader/program-macro/Cargo.toml b/evm_loader/program-macro/Cargo.toml index 6beb96c78..2734fa151 100644 --- a/evm_loader/program-macro/Cargo.toml +++ b/evm_loader/program-macro/Cargo.toml @@ -12,7 +12,7 @@ proc-macro = true syn = "2" proc-macro2 = "1" quote = "1" -itertools = "0.12" +itertools = "0.13" bs58 = "0.5" serde = { version = "1.0", features = [ "derive" ] } toml = "0.8" From 45514e693b96ec27c0d947dacd919fafe28de493 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 May 2024 12:00:56 +0300 Subject: [PATCH 208/318] Bump syn from 2.0.61 to 2.0.66 in /evm_loader (#440) Bumps [syn](https://github.com/dtolnay/syn) from 2.0.61 to 2.0.66. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.61...2.0.66) --- updated-dependencies: - dependency-name: syn dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 78 +++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index bbd5882c7..8cfafb495 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -123,7 +123,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -250,7 +250,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -631,7 +631,7 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -1006,7 +1006,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.61", + "syn 2.0.66", "xz2", ] @@ -1049,7 +1049,7 @@ checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -1576,7 +1576,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -1593,7 +1593,7 @@ checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -1617,7 +1617,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -1628,7 +1628,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -1800,7 +1800,7 @@ checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -1891,7 +1891,7 @@ checksum = "eecf8589574ce9b895052fa12d69af7a233f99e6107f5cb8dd1044f2a17bfdcb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -1903,7 +1903,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -2042,7 +2042,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.61", + "syn 2.0.66", "toml 0.8.2", ] @@ -2217,7 +2217,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -3157,7 +3157,7 @@ checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -3549,7 +3549,7 @@ checksum = "cfb77679af88f8b125209d354a202862602672222e7f2313fdd6dc349bad4712" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -3631,7 +3631,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -3643,7 +3643,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -3705,7 +3705,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -3875,7 +3875,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -4035,7 +4035,7 @@ checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -4706,7 +4706,7 @@ checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -4790,7 +4790,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -4802,7 +4802,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -5403,7 +5403,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -5872,7 +5872,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -6198,7 +6198,7 @@ checksum = "fadbefec4f3c678215ca72bd71862697bb06b41fd77c0088902dd3203354387b" dependencies = [ "quote", "spl-discriminator-syn", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -6210,7 +6210,7 @@ dependencies = [ "proc-macro2", "quote", "sha2 0.10.8", - "syn 2.0.61", + "syn 2.0.66", "thiserror", ] @@ -6258,7 +6258,7 @@ dependencies = [ "proc-macro2", "quote", "sha2 0.10.8", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -6432,7 +6432,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -6460,9 +6460,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.61" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c993ed8ccba56ae856363b1845da7266a7cb78e1d146c8a32d54b45a8b831fc9" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote", @@ -6551,7 +6551,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -6668,7 +6668,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -6845,7 +6845,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -7148,7 +7148,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.66", "wasm-bindgen-shared", ] @@ -7182,7 +7182,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.66", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -7624,7 +7624,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] @@ -7644,7 +7644,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.66", ] [[package]] From c2569f3b1e8336aa16d8b09e3627c8bff7ce045b Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Fri, 24 May 2024 19:47:45 +0300 Subject: [PATCH 209/318] Check the revisions for the read accounts only (#388) --- evm_loader/lib/src/account_storage.rs | 14 ++ evm_loader/program/config/common.toml | 2 +- .../program/src/account/ether_balance.rs | 97 +++++++++-- evm_loader/program/src/account/mod.rs | 14 -- evm_loader/program/src/account/state.rs | 105 ++++++++++-- .../program/src/account_storage/apply.rs | 7 + .../program/src/account_storage/backend.rs | 13 ++ .../program/src/account_storage/base.rs | 7 +- evm_loader/program/src/account_storage/mod.rs | 5 + evm_loader/program/src/executor/cache.rs | 46 +----- .../precompile_extension/neon_token.rs | 4 +- evm_loader/program/src/executor/state.rs | 150 +++++++++++++----- .../src/instruction/neon_tokens_deposit.rs | 1 + .../instruction/operator_withdraw_balance.rs | 17 +- .../src/instruction/transaction_cancel.rs | 4 + .../src/instruction/transaction_step.rs | 52 ++++-- .../transaction_step_from_account.rs | 13 +- 17 files changed, 390 insertions(+), 161 deletions(-) diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index adcac0fad..2df59a10f 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -1034,6 +1034,20 @@ impl AccountStorage for EmulatorAccountStorage<'_, T> { address.find_solana_address(self.program_id()) } + fn balance_pubkey(&self, address: Address, chain_id: u64) -> (Pubkey, u8) { + address.find_balance_address(self.program_id(), chain_id) + } + + fn storage_cell_pubkey(&self, address: Address, index: U256) -> Pubkey { + let base = self.contract_pubkey(address).0; + if index < U256::from(STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT as u64) { + base + } else { + let address = StorageCellAddress::new(self.program_id(), &base, &index); + *address.pubkey() + } + } + async fn code_size(&self, address: Address) -> usize { info!("code_size {address}"); diff --git a/evm_loader/program/config/common.toml b/evm_loader/program/config/common.toml index 3c431349a..3ff81fe8d 100644 --- a/evm_loader/program/config/common.toml +++ b/evm_loader/program/config/common.toml @@ -2,7 +2,7 @@ account_seed_version = [3, "u8"] payment_to_treasure = 5000 holder_msg_size = 950 evm_steps_min = 500 -evm_steps_last_iteration_max = 1 +evm_steps_last_iteration_max = 0 gas_limit_multiplier_no_chainid = 1000 storage_entries_in_contract_account = [64, "usize"] treasury_pool_count = 128 diff --git a/evm_loader/program/src/account/ether_balance.rs b/evm_loader/program/src/account/ether_balance.rs index 400e052e9..44de0c590 100644 --- a/evm_loader/program/src/account/ether_balance.rs +++ b/evm_loader/program/src/account/ether_balance.rs @@ -15,16 +15,31 @@ use super::{ }; #[repr(C, packed)] -pub struct Header { +pub struct HeaderV0 { pub address: Address, pub chain_id: u64, pub trx_count: u64, pub balance: U256, } -impl AccountHeader for Header { +impl AccountHeader for HeaderV0 { const VERSION: u8 = 0; } +#[repr(C, packed)] +pub struct HeaderWithRevision { + pub v0: HeaderV0, + pub revision: u32, +} + +impl AccountHeader for HeaderWithRevision { + const VERSION: u8 = 2; +} + +// Set the last version of the Header struct here +// and change the `header_size` and `header_upgrade` functions +pub type Header = HeaderWithRevision; + +#[derive(Clone)] pub struct BalanceAccount<'a> { account: AccountInfo<'a>, } @@ -35,6 +50,12 @@ impl<'a> BalanceAccount<'a> { ACCOUNT_PREFIX_LEN + size_of::
() } + #[must_use] + pub fn required_header_realloc(&self) -> usize { + let allocated_header_size = self.header_size(); + size_of::
().saturating_sub(allocated_header_size) + } + pub fn from_account(program_id: &Pubkey, account: AccountInfo<'a>) -> Result { super::validate_tag(program_id, &account, TAG_ACCOUNT_BALANCE)?; @@ -114,15 +135,38 @@ impl<'a> BalanceAccount<'a> { super::set_tag(program_id, &account, TAG_ACCOUNT_BALANCE, Header::VERSION)?; { let mut header = super::header_mut::
(&account); - header.address = address; - header.chain_id = chain_id; - header.trx_count = 0; - header.balance = U256::ZERO; + header.v0.address = address; + header.v0.chain_id = chain_id; + header.v0.trx_count = 0; + header.v0.balance = U256::ZERO; + header.revision = 1; } Ok(Self { account }) } + fn header_size(&self) -> usize { + match super::header_version(&self.account) { + 0 | 1 => size_of::(), + HeaderWithRevision::VERSION => size_of::(), + _ => panic!("Unknown header version"), + } + } + + fn header_upgrade(&mut self, rent: &Rent, db: &AccountsDB<'a>) -> Result<()> { + match super::header_version(&self.account) { + 0 | 1 => { + super::expand_header::(&self.account, rent, db)?; + } + HeaderWithRevision::VERSION => { + super::expand_header::(&self.account, rent, db)?; + } + _ => panic!("Unknown header version"), + } + + Ok(()) + } + #[must_use] pub fn pubkey(&self) -> &'a Pubkey { self.account.key @@ -130,35 +174,35 @@ impl<'a> BalanceAccount<'a> { #[must_use] pub fn address(&self) -> Address { - let header = super::header::
(&self.account); + let header = super::header::(&self.account); header.address } #[must_use] pub fn chain_id(&self) -> u64 { - let header = super::header::
(&self.account); + let header = super::header::(&self.account); header.chain_id } #[must_use] pub fn nonce(&self) -> u64 { - let header = super::header::
(&self.account); + let header = super::header::(&self.account); header.trx_count } pub fn override_nonce_by(&mut self, value: u64) { - let mut header = super::header_mut::
(&self.account); + let mut header = super::header_mut::(&self.account); header.trx_count = value; } pub fn override_balance_by(&mut self, value: U256) { - let mut header = super::header_mut::
(&self.account); + let mut header = super::header_mut::(&self.account); header.balance = value; } #[must_use] pub fn exists(&self) -> bool { - let header = super::header::
(&self.account); + let header = super::header::(&self.account); ({ header.trx_count } > 0) || ({ header.balance } > 0) } @@ -168,7 +212,7 @@ impl<'a> BalanceAccount<'a> { } pub fn increment_nonce_by(&mut self, value: u64) -> Result<()> { - let mut header = super::header_mut::
(&self.account); + let mut header = super::header_mut::(&self.account); header.trx_count = header .trx_count @@ -180,7 +224,7 @@ impl<'a> BalanceAccount<'a> { #[must_use] pub fn balance(&self) -> U256 { - let header = super::header::
(&self.account); + let header = super::header::(&self.account); header.balance } @@ -196,7 +240,7 @@ impl<'a> BalanceAccount<'a> { } pub fn burn(&mut self, value: U256) -> Result<()> { - let mut header = super::header_mut::
(&self.account); + let mut header = super::header_mut::(&self.account); header.balance = header .balance @@ -211,7 +255,7 @@ impl<'a> BalanceAccount<'a> { } pub fn mint(&mut self, value: U256) -> Result<()> { - let mut header = super::header_mut::
(&self.account); + let mut header = super::header_mut::(&self.account); header.balance = header .balance @@ -220,4 +264,25 @@ impl<'a> BalanceAccount<'a> { Ok(()) } + + #[must_use] + pub fn revision(&self) -> u32 { + if super::header_version(&self.account) < HeaderWithRevision::VERSION { + return 0; + } + + let header = super::header::(&self.account); + header.revision + } + + pub fn increment_revision(&mut self, rent: &Rent, db: &AccountsDB<'a>) -> Result<()> { + if super::header_version(&self.account) < HeaderWithRevision::VERSION { + self.header_upgrade(rent, db)?; + } + + let mut header = super::header_mut::(&self.account); + header.revision = header.revision.wrapping_add(1); + + Ok(()) + } } diff --git a/evm_loader/program/src/account/mod.rs b/evm_loader/program/src/account/mod.rs index d0bef519f..99580761c 100644 --- a/evm_loader/program/src/account/mod.rs +++ b/evm_loader/program/src/account/mod.rs @@ -176,20 +176,6 @@ pub fn validate_tag(program_id: &Pubkey, info: &AccountInfo, tag: u8) -> Result< } } -pub fn revision(program_id: &Pubkey, info: &AccountInfo) -> Result { - match tag(program_id, info)? { - TAG_STORAGE_CELL => { - let cell = StorageCell::from_account(program_id, info.clone())?; - Ok(cell.revision()) - } - TAG_ACCOUNT_CONTRACT => { - let contract = ContractAccount::from_account(program_id, info.clone())?; - Ok(contract.revision()) - } - _ => Ok(0), - } -} - /// # Safety /// *Permanently delete all data* in the account. Transfer lamports to the operator. pub unsafe fn delete(account: &AccountInfo, operator: &Operator) { diff --git a/evm_loader/program/src/account/state.rs b/evm_loader/program/src/account/state.rs index ec4a52122..1539d3654 100644 --- a/evm_loader/program/src/account/state.rs +++ b/evm_loader/program/src/account/state.rs @@ -1,24 +1,64 @@ use std::cell::{Ref, RefMut}; +use std::collections::btree_map::Entry; use std::collections::BTreeMap; use std::mem::size_of; use crate::account_storage::AccountStorage; use crate::config::DEFAULT_CHAIN_ID; use crate::error::{Error, Result}; +use crate::types::serde::bytes_32; use crate::types::{Address, Transaction}; use ethnum::U256; use serde::{Deserialize, Serialize}; +use solana_program::system_program; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; use super::{ - revision, AccountHeader, AccountsDB, BalanceAccount, Holder, OperatorBalanceAccount, - StateFinalizedAccount, ACCOUNT_PREFIX_LEN, TAG_HOLDER, TAG_STATE, TAG_STATE_FINALIZED, + AccountHeader, AccountsDB, BalanceAccount, ContractAccount, Holder, OperatorBalanceAccount, + StateFinalizedAccount, StorageCell, ACCOUNT_PREFIX_LEN, TAG_ACCOUNT_BALANCE, + TAG_ACCOUNT_CONTRACT, TAG_HOLDER, TAG_STATE, TAG_STATE_FINALIZED, TAG_STORAGE_CELL, }; #[derive(PartialEq, Eq)] pub enum AccountsStatus { Ok, - RevisionChanged, + NeedRestart, +} + +#[derive(Serialize, Deserialize, PartialEq, Eq)] +enum AccountRevision { + Revision(u32), + Hash(#[serde(with = "bytes_32")] [u8; 32]), +} + +impl AccountRevision { + pub fn new(program_id: &Pubkey, info: &AccountInfo) -> Self { + if (info.owner != program_id) && !system_program::check_id(info.owner) { + let hash = solana_program::hash::hashv(&[ + info.owner.as_ref(), + &info.lamports().to_le_bytes(), + &info.data.borrow(), + ]); + + return AccountRevision::Hash(hash.to_bytes()); + } + + match crate::account::tag(program_id, info) { + Ok(TAG_STORAGE_CELL) => { + let cell = StorageCell::from_account(program_id, info.clone()).unwrap(); + Self::Revision(cell.revision()) + } + Ok(TAG_ACCOUNT_CONTRACT) => { + let contract = ContractAccount::from_account(program_id, info.clone()).unwrap(); + Self::Revision(contract.revision()) + } + Ok(TAG_ACCOUNT_BALANCE) => { + let balance = BalanceAccount::from_account(program_id, info.clone()).unwrap(); + Self::Revision(balance.revision()) + } + _ => Self::Revision(0), + } + } } /// Storage data account to store execution metainfo between steps for iterative execution @@ -28,8 +68,10 @@ struct Data { pub transaction: Transaction, /// Ethereum transaction caller address pub origin: Address, - /// Stored accounts - pub revisions: BTreeMap, + /// Stored revision + pub revisions: BTreeMap, + /// Accounts that been read during the transaction + pub touched_accounts: BTreeMap, /// Ethereum transaction gas used and paid #[serde(with = "ethnum::serde::bytes::le")] pub gas_used: U256, @@ -103,7 +145,7 @@ impl<'a> StateAccount<'a> { let revisions = accounts .into_iter() .map(|account| { - let revision = revision(program_id, account).unwrap_or(0); + let revision = AccountRevision::new(program_id, account); (*account.key, revision) }) .collect(); @@ -113,6 +155,7 @@ impl<'a> StateAccount<'a> { transaction, origin, revisions, + touched_accounts: BTreeMap::new(), gas_used: U256::ZERO, steps_executed: 0_u64, }; @@ -137,20 +180,34 @@ impl<'a> StateAccount<'a> { info: AccountInfo<'a>, accounts: &AccountsDB, ) -> Result<(Self, AccountsStatus)> { - let mut state = Self::from_account(program_id, info)?; let mut status = AccountsStatus::Ok; + let mut state = Self::from_account(program_id, info)?; - for account in accounts { - let account_revision = revision(program_id, account).unwrap_or(0); - let stored_revision = state + let is_touched_account = |key: &Pubkey| -> bool { + state .data - .revisions - .entry(*account.key) - .or_insert(account_revision); + .touched_accounts + .get(key) + .map(|counter| counter > &1) + .is_some() + }; + + let touched_accounts = accounts.into_iter().filter(|a| is_touched_account(a.key)); + for account in touched_accounts { + let account_revision = AccountRevision::new(program_id, account); + let revision_entry = &state.data.revisions[account.key]; + + if revision_entry != &account_revision { + status = AccountsStatus::NeedRestart; + break; + } + } - if stored_revision != &account_revision { - status = AccountsStatus::RevisionChanged; - *stored_revision = account_revision; + if status == AccountsStatus::NeedRestart { + // update all accounts revisions + for account in accounts { + let account_revision = AccountRevision::new(program_id, account); + state.data.revisions.insert(*account.key, account_revision); } } @@ -166,6 +223,22 @@ impl<'a> StateAccount<'a> { Ok(()) } + pub fn update_touched_accounts(&mut self, touched: BTreeMap) -> Result<()> { + for (key, counter) in touched { + match self.data.touched_accounts.entry(key) { + Entry::Vacant(e) => { + e.insert(counter); + } + Entry::Occupied(e) => { + let value = e.into_mut(); + *value = value.checked_add(counter).ok_or(Error::IntegerOverflow)?; + } + } + } + + Ok(()) + } + pub fn accounts(&self) -> impl Iterator { self.data.revisions.keys() } diff --git a/evm_loader/program/src/account_storage/apply.rs b/evm_loader/program/src/account_storage/apply.rs index 2ae41b9c9..efe8cbaac 100644 --- a/evm_loader/program/src/account_storage/apply.rs +++ b/evm_loader/program/src/account_storage/apply.rs @@ -42,6 +42,8 @@ impl<'a> ProgramAccountStorage<'a> { let mut source = BalanceAccount::from_account(&crate::ID, source)?; let mut target = self.accounts.operator_balance(); + + source.increment_revision(&self.rent, &self.accounts)?; target.consume_gas(&mut source, value) } @@ -82,6 +84,10 @@ impl<'a> ProgramAccountStorage<'a> { } => { let mut source = self.balance_account(source, chain_id)?; let mut target = self.create_balance_account(target, chain_id)?; + + source.increment_revision(&self.rent, &self.accounts)?; + target.increment_revision(&self.rent, &self.accounts)?; + source.transfer(&mut target, value)?; } Action::Burn { @@ -90,6 +96,7 @@ impl<'a> ProgramAccountStorage<'a> { value, } => { let mut account = self.create_balance_account(source, chain_id)?; + account.increment_revision(&self.rent, &self.accounts)?; account.burn(value)?; } Action::EvmSetStorage { diff --git a/evm_loader/program/src/account_storage/backend.rs b/evm_loader/program/src/account_storage/backend.rs index e5cea5d91..56564513c 100644 --- a/evm_loader/program/src/account_storage/backend.rs +++ b/evm_loader/program/src/account_storage/backend.rs @@ -85,6 +85,19 @@ impl<'a> AccountStorage for ProgramAccountStorage<'a> { .contract_with_bump_seed(self.program_id(), address) } + fn balance_pubkey(&self, address: Address, chain_id: u64) -> (Pubkey, u8) { + self.keys + .balance_with_bump_seed(self.program_id(), address, chain_id) + } + + fn storage_cell_pubkey(&self, address: Address, index: U256) -> Pubkey { + if index < U256::from(STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT as u64) { + self.keys.contract(self.program_id(), address) + } else { + self.keys.storage_cell(self.program_id(), address, index) + } + } + fn code_size(&self, address: Address) -> usize { self.contract_account(address).map_or(0, |a| a.code_len()) } diff --git a/evm_loader/program/src/account_storage/base.rs b/evm_loader/program/src/account_storage/base.rs index e898c5b72..abcef7079 100644 --- a/evm_loader/program/src/account_storage/base.rs +++ b/evm_loader/program/src/account_storage/base.rs @@ -73,6 +73,7 @@ impl<'a> ProgramAccountStorage<'a> { if result.is_err() && (chain_id == DEFAULT_CHAIN_ID) { let contract_pubkey = self.keys.contract(&crate::ID, address); + let contract = self.accounts.get(&contract_pubkey); let legacy_tag = crate::account::legacy::TAG_ACCOUNT_CONTRACT_DEPRECATED; @@ -87,13 +88,15 @@ impl<'a> ProgramAccountStorage<'a> { address: Address, chain_id: u64, ) -> Result> { - BalanceAccount::create( + let account = BalanceAccount::create( address, chain_id, &self.accounts, Some(&self.keys), &self.rent, - ) + )?; + + Ok(account) } pub fn origin( diff --git a/evm_loader/program/src/account_storage/mod.rs b/evm_loader/program/src/account_storage/mod.rs index 9a3aba7c1..e4baef638 100644 --- a/evm_loader/program/src/account_storage/mod.rs +++ b/evm_loader/program/src/account_storage/mod.rs @@ -69,8 +69,13 @@ pub trait AccountStorage { /// Get contract chain_id async fn contract_chain_id(&self, address: Address) -> Result; + /// Get contract solana address fn contract_pubkey(&self, address: Address) -> (Pubkey, u8); + /// Get balance solana address + fn balance_pubkey(&self, address: Address, chain_id: u64) -> (Pubkey, u8); + /// Get cell solana address + fn storage_cell_pubkey(&self, address: Address, index: U256) -> Pubkey; /// Get code size async fn code_size(&self, address: Address) -> usize; diff --git a/evm_loader/program/src/executor/cache.rs b/evm_loader/program/src/executor/cache.rs index ecf338c44..ad4a5db90 100644 --- a/evm_loader/program/src/executor/cache.rs +++ b/evm_loader/program/src/executor/cache.rs @@ -1,12 +1,9 @@ -use std::{cell::RefCell, collections::BTreeMap, rc::Rc}; +use std::{cell::RefCell, rc::Rc}; use ethnum::U256; -use maybe_async::maybe_async; use serde::{Deserialize, Serialize}; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; -use crate::{account_storage::AccountStorage, types::Address}; - #[derive(Clone, Serialize, Deserialize)] pub struct OwnedAccountInfo { pub key: Pubkey, @@ -59,49 +56,8 @@ impl<'a> solana_program::account_info::IntoAccountInfo<'a> for &'a mut OwnedAcco #[derive(Serialize, Deserialize)] pub struct Cache { - pub solana_accounts: BTreeMap, - pub native_balances: BTreeMap<(Address, u64), U256>, #[serde(with = "ethnum::serde::bytes::le")] pub block_number: U256, #[serde(with = "ethnum::serde::bytes::le")] pub block_timestamp: U256, } - -#[maybe_async] -#[allow(clippy::await_holding_refcell_ref)] // We don't use this RefCell in other execution context -pub async fn cache_get_or_insert_account( - cache: &RefCell, - key: Pubkey, - backend: &B, -) -> OwnedAccountInfo { - use std::collections::btree_map::Entry; - - let mut cache = cache.borrow_mut(); - match cache.solana_accounts.entry(key) { - Entry::Vacant(entry) => { - let owned_account_info = backend.clone_solana_account(&key).await; - entry.insert(owned_account_info).clone() - } - Entry::Occupied(entry) => entry.get().clone(), - } -} - -#[maybe_async] -#[allow(clippy::await_holding_refcell_ref)] // We don't use this RefCell in other execution context -pub async fn cache_get_or_insert_balance( - cache: &RefCell, - key: (Address, u64), - backend: &B, -) -> U256 { - use std::collections::btree_map::Entry; - - let mut cache = cache.borrow_mut(); - - match cache.native_balances.entry(key) { - Entry::Vacant(entry) => { - let balance = backend.balance(key.0, key.1).await; - *entry.insert(balance) - } - Entry::Occupied(entry) => *entry.get(), - } -} diff --git a/evm_loader/program/src/executor/precompile_extension/neon_token.rs b/evm_loader/program/src/executor/precompile_extension/neon_token.rs index bbbb73242..48865df7b 100644 --- a/evm_loader/program/src/executor/precompile_extension/neon_token.rs +++ b/evm_loader/program/src/executor/precompile_extension/neon_token.rs @@ -134,11 +134,11 @@ async fn withdraw( mint_data.decimals, )?; let transfer_seeds = vec![b"Deposit".to_vec(), vec![bump_seed]]; + + state.burn(source, chain_id, value).await?; state .queue_external_instruction(transfer, vec![transfer_seeds], 0, true) .await?; - state.burn(source, chain_id, value).await?; - Ok(()) } diff --git a/evm_loader/program/src/executor/state.rs b/evm_loader/program/src/executor/state.rs index e7ec6bc52..66831ca7d 100644 --- a/evm_loader/program/src/executor/state.rs +++ b/evm_loader/program/src/executor/state.rs @@ -15,10 +15,13 @@ use crate::evm::{Context, ExitStatus}; use crate::types::Address; use super::action::Action; -use super::cache::{cache_get_or_insert_account, cache_get_or_insert_balance, Cache}; +use super::cache::Cache; use super::precompile_extension::PrecompiledContracts; use super::OwnedAccountInfo; +pub type ExecutionResult = Option<(ExitStatus, Vec)>; +pub type TouchedAccounts = BTreeMap; + /// Represents the state of executor abstracted away from a self.backend. /// UPDATE `serialize/deserialize` WHEN THIS STRUCTURE CHANGES pub struct ExecutorState<'a, B: AccountStorage> { @@ -27,6 +30,8 @@ pub struct ExecutorState<'a, B: AccountStorage> { actions: Vec, stack: Vec, exit_status: Option, + // #[serde(skip)] + touched_accounts: RefCell, } impl<'a, B: AccountStorage> ExecutorState<'a, B> { @@ -47,14 +52,13 @@ impl<'a, B: AccountStorage> ExecutorState<'a, B> { actions, stack, exit_status, + touched_accounts: RefCell::new(TouchedAccounts::new()), }) } #[must_use] pub fn new(backend: &'a B) -> Self { let cache = Cache { - solana_accounts: BTreeMap::new(), - native_balances: BTreeMap::new(), block_number: backend.block_number(), block_timestamp: backend.block_timestamp(), }; @@ -65,9 +69,20 @@ impl<'a, B: AccountStorage> ExecutorState<'a, B> { actions: Vec::with_capacity(64), stack: Vec::with_capacity(16), exit_status: None, + touched_accounts: RefCell::new(TouchedAccounts::new()), } } + pub fn deconstruct(self) -> (ExecutionResult, TouchedAccounts) { + let result = if let Some(exit_status) = self.exit_status { + Some((exit_status, self.actions)) + } else { + None + }; + + (result, self.touched_accounts.into_inner()) + } + pub fn into_actions(self) -> Vec { assert!(self.stack.is_empty()); self.actions @@ -78,12 +93,79 @@ impl<'a, B: AccountStorage> ExecutorState<'a, B> { } pub fn set_exit_status(&mut self, status: ExitStatus) { + assert!(self.stack.is_empty()); + self.exit_status = Some(status); } pub fn call_depth(&self) -> usize { self.stack.len() } + + #[maybe_async] + async fn balance_internal(&self, from_address: Address, from_chain_id: u64) -> Result { + let mut balance = self.backend.balance(from_address, from_chain_id).await; + + for action in &self.actions { + match action { + Action::Transfer { + source, + target, + chain_id, + value, + } if (&from_chain_id == chain_id) => { + if &from_address == source { + balance = balance.checked_sub(*value).ok_or(Error::IntegerOverflow)?; + } + + if &from_address == target { + balance = balance.checked_add(*value).ok_or(Error::IntegerOverflow)?; + } + } + Action::Burn { + source, + chain_id, + value, + } if (&from_chain_id == chain_id) && (&from_address == source) => { + balance = balance.checked_sub(*value).ok_or(Error::IntegerOverflow)?; + } + _ => {} + } + } + + Ok(balance) + } + + fn touch_balance(&self, address: Address, chain_id: u64) { + let (pubkey, _) = self.backend.balance_pubkey(address, chain_id); + self.touch_account(pubkey, 2); + } + + fn touch_balance_indirect(&self, address: Address, chain_id: u64) { + let (pubkey, _) = self.backend.balance_pubkey(address, chain_id); + self.touch_account(pubkey, 1); + } + + fn touch_contract(&self, address: Address) { + let (pubkey, _) = self.backend.contract_pubkey(address); + self.touch_account(pubkey, 2); + } + + fn touch_storage(&self, address: Address, index: U256) { + let pubkey = self.backend.storage_cell_pubkey(address, index); + self.touch_account(pubkey, 2); + } + + fn touch_solana(&self, pubkey: Pubkey) { + self.touch_account(pubkey, 2); + } + + fn touch_account(&self, pubkey: Pubkey, count: u64) { + let mut touched_accounts = self.touched_accounts.borrow_mut(); + + let counter = touched_accounts.entry(pubkey).or_insert(0); + *counter = counter.checked_add(count).unwrap(); // Technically, this could overflow with infinite compute budget + } } #[maybe_async(?Send)] @@ -125,38 +207,10 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { Ok(()) } - async fn balance(&self, from_address: Address, from_chain_id: u64) -> Result { - let cache_key = (from_address, from_chain_id); - let mut balance = cache_get_or_insert_balance(&self.cache, cache_key, self.backend).await; + async fn balance(&self, address: Address, chain_id: u64) -> Result { + self.touch_balance(address, chain_id); - for action in &self.actions { - match action { - Action::Transfer { - source, - target, - chain_id, - value, - } if (&from_chain_id == chain_id) => { - if &from_address == source { - balance = balance.checked_sub(*value).ok_or(Error::IntegerOverflow)?; - } - - if &from_address == target { - balance = balance.checked_add(*value).ok_or(Error::IntegerOverflow)?; - } - } - Action::Burn { - source, - chain_id, - value, - } if (&from_chain_id == chain_id) && (&from_address == source) => { - balance = balance.checked_sub(*value).ok_or(Error::IntegerOverflow)?; - } - _ => {} - } - } - - Ok(balance) + self.balance_internal(address, chain_id).await } async fn transfer( @@ -170,6 +224,8 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { return Ok(()); } + self.touch_contract(target); + let target_chain_id = self.contract_chain_id(target).await.unwrap_or(chain_id); if (self.code_size(target).await? > 0) && (target_chain_id != chain_id) { @@ -180,7 +236,8 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { return Ok(()); } - if self.balance(source, chain_id).await? < value { + self.touch_balance_indirect(source, chain_id); + if self.balance_internal(source, chain_id).await? < value { return Err(Error::InsufficientBalance(source, chain_id, value)); } @@ -196,6 +253,11 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { } async fn burn(&mut self, source: Address, chain_id: u64, value: U256) -> Result<()> { + self.touch_balance_indirect(source, chain_id); + if self.balance_internal(source, chain_id).await? < value { + return Err(Error::InsufficientBalance(source, chain_id, value)); + } + let burn = Action::Burn { source, chain_id, @@ -211,6 +273,8 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { return Ok(1); // This is required in order to make a normal call to an extension contract } + self.touch_contract(from_address); + for action in &self.actions { if let Action::EvmSetCode { address, code, .. } = action { if &from_address == address { @@ -223,6 +287,8 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { } async fn code(&self, from_address: Address) -> Result { + self.touch_contract(from_address); + for action in &self.actions { if let Action::EvmSetCode { address, code, .. } = action { if &from_address == address { @@ -256,6 +322,8 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { } async fn storage(&self, from_address: Address, from_index: U256) -> Result<[u8; 32]> { + self.touch_storage(from_address, from_index); + for action in self.actions.iter().rev() { if let Action::EvmSetStorage { address, @@ -352,6 +420,8 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { } async fn external_account(&self, address: Pubkey) -> Result { + self.touch_solana(address); + let metas = self .actions .iter() @@ -366,14 +436,16 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { .collect::>(); if !metas.iter().any(|m| (m.pubkey == address) && m.is_writable) { - let account = cache_get_or_insert_account(&self.cache, address, self.backend).await; + let account = self.backend.clone_solana_account(&address).await; return Ok(account); } let mut accounts = BTreeMap::::new(); for m in metas { - let account = cache_get_or_insert_account(&self.cache, m.pubkey, self.backend).await; + self.touch_solana(m.pubkey); + + let account = self.backend.clone_solana_account(&m.pubkey).await; accounts.insert(account.key, account); } @@ -441,6 +513,8 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { where F: FnOnce(&solana_program::account_info::AccountInfo) -> R, { + self.touch_solana(*address); + self.backend.map_solana_account(address, action).await } @@ -488,6 +562,8 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { } async fn contract_chain_id(&self, contract: Address) -> Result { + self.touch_contract(contract); + for action in self.actions.iter().rev() { if let Action::EvmSetCode { address, chain_id, .. diff --git a/evm_loader/program/src/instruction/neon_tokens_deposit.rs b/evm_loader/program/src/instruction/neon_tokens_deposit.rs index dd524b66c..3c0fc3962 100644 --- a/evm_loader/program/src/instruction/neon_tokens_deposit.rs +++ b/evm_loader/program/src/instruction/neon_tokens_deposit.rs @@ -165,6 +165,7 @@ fn execute(program_id: &Pubkey, accounts: Accounts, address: Address, chain_id: let rent = Rent::get()?; let mut balance_account = BalanceAccount::create(address, chain_id, &accounts_db, None, &rent)?; + balance_account.increment_revision(&rent, &accounts_db)?; balance_account.mint(deposit)?; **accounts_db.operator().try_borrow_mut_lamports()? += excessive_lamports; diff --git a/evm_loader/program/src/instruction/operator_withdraw_balance.rs b/evm_loader/program/src/instruction/operator_withdraw_balance.rs index 935efa439..be11dc7af 100644 --- a/evm_loader/program/src/instruction/operator_withdraw_balance.rs +++ b/evm_loader/program/src/instruction/operator_withdraw_balance.rs @@ -1,6 +1,9 @@ +use solana_program::rent::Rent; +use solana_program::sysvar::Sysvar; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; -use crate::account::{BalanceAccount, Operator, OperatorBalanceAccount}; +use crate::account::program::System; +use crate::account::{AccountsDB, BalanceAccount, Operator, OperatorBalanceAccount}; use crate::error::Result; pub fn process<'a>( @@ -10,10 +13,14 @@ pub fn process<'a>( ) -> Result<()> { log_msg!("Instruction: Withdraw Operator Balance Account"); - let operator = unsafe { Operator::from_account_not_whitelisted(&accounts[0]) }?; - let mut operator_balance = OperatorBalanceAccount::from_account(program_id, &accounts[1])?; - let mut target_balance = BalanceAccount::from_account(program_id, accounts[2].clone())?; + let system = System::from_account(&accounts[0])?; + let operator = unsafe { Operator::from_account_not_whitelisted(&accounts[1]) }?; + let mut operator_balance = OperatorBalanceAccount::from_account(program_id, &accounts[2])?; + let mut target_balance = BalanceAccount::from_account(program_id, accounts[3].clone())?; operator_balance.validate_owner(&operator)?; - operator_balance.withdraw(&mut target_balance) + operator_balance.withdraw(&mut target_balance)?; + + let accounts_db = AccountsDB::new(&[], operator, Some(operator_balance), Some(system), None); + target_balance.increment_revision(&Rent::get()?, &accounts_db) } diff --git a/evm_loader/program/src/instruction/transaction_cancel.rs b/evm_loader/program/src/instruction/transaction_cancel.rs index 74944f799..e700cc2ab 100644 --- a/evm_loader/program/src/instruction/transaction_cancel.rs +++ b/evm_loader/program/src/instruction/transaction_cancel.rs @@ -5,6 +5,8 @@ use crate::error::{Error, Result}; use crate::gasometer::{CANCEL_TRX_COST, LAST_ITERATION_COST}; use arrayref::array_ref; use ethnum::U256; +use solana_program::rent::Rent; +use solana_program::sysvar::Sysvar; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; pub fn process<'a>( @@ -67,6 +69,8 @@ fn execute<'a>( { let origin_info = accounts.get(&origin_pubkey).clone(); let mut account = BalanceAccount::from_account(program_id, origin_info)?; + account.increment_revision(&Rent::get()?, &accounts)?; + storage.refund_unused_gas(&mut account)?; } diff --git a/evm_loader/program/src/instruction/transaction_step.rs b/evm_loader/program/src/instruction/transaction_step.rs index 7f9dd0b65..d0bfea5d7 100644 --- a/evm_loader/program/src/instruction/transaction_step.rs +++ b/evm_loader/program/src/instruction/transaction_step.rs @@ -1,3 +1,7 @@ +use std::collections::BTreeMap; + +use solana_program::pubkey::Pubkey; + use crate::account::{AccountsDB, AllocateResult, StateAccount}; use crate::account_storage::{AccountStorage, ProgramAccountStorage}; use crate::config::{EVM_STEPS_LAST_ITERATION_MAX, EVM_STEPS_MIN}; @@ -29,6 +33,7 @@ pub fn do_begin<'a>( // These transactions are guaranteed to start in a correct sequence // BUT they finalize in an undefined order let mut origin_account = account_storage.origin(origin, storage.trx())?; + origin_account.increment_revision(account_storage.rent(), account_storage.db())?; origin_account.increment_nonce()?; // Burn `gas_limit` tokens from the origin account @@ -42,7 +47,16 @@ pub fn do_begin<'a>( let evm = Machine::new(storage.trx(), origin, &mut backend, None)?; serialize_evm_state(&mut storage, &backend, &evm)?; - finalize(0, storage, account_storage, None, gasometer) + + let (_, touched_accounts) = backend.deconstruct(); + finalize( + 0, + storage, + account_storage, + None, + gasometer, + touched_accounts, + ) } pub fn do_continue<'a>( @@ -71,24 +85,31 @@ pub fn do_continue<'a>( deserialize_evm_state(&storage, &account_storage)? }; - let (result, steps_executed, _) = match backend.exit_status() { - Some(status) => (status.clone(), 0_u64, None), - None => evm.execute(step_count, &mut backend)?, - }; + let mut steps_executed = 0; + if backend.exit_status().is_none() { + let (exit_status, steps_returned, _) = evm.execute(step_count, &mut backend)?; + if exit_status != ExitStatus::StepLimit { + backend.set_exit_status(exit_status) + } - if (result != ExitStatus::StepLimit) && (steps_executed > 0) { - backend.set_exit_status(result.clone()); + steps_executed = steps_returned; } serialize_evm_state(&mut storage, &backend, &evm)?; - let results = match result { - ExitStatus::StepLimit => None, - _ if steps_executed > EVM_STEPS_LAST_ITERATION_MAX => None, - result => Some((result, backend.into_actions())), - }; + let (mut results, touched_accounts) = backend.deconstruct(); + if steps_executed > EVM_STEPS_LAST_ITERATION_MAX { + results = None; + } - finalize(steps_executed, storage, account_storage, results, gasometer) + finalize( + steps_executed, + storage, + account_storage, + results, + gasometer, + touched_accounts, + ) } fn finalize<'a>( @@ -97,9 +118,11 @@ fn finalize<'a>( mut accounts: ProgramAccountStorage<'a>, results: Option<(ExitStatus, Vec)>, mut gasometer: Gasometer, + touched_accounts: BTreeMap, ) -> Result<()> { debug_print!("finalize"); + storage.update_touched_accounts(touched_accounts)?; storage.increment_steps_executed(steps_executed)?; log_data(&[ b"STEPS", @@ -138,8 +161,9 @@ fn finalize<'a>( log_return_value(&status); let mut origin = accounts.origin(storage.trx_origin(), storage.trx())?; - storage.refund_unused_gas(&mut origin)?; + origin.increment_revision(accounts.rent(), accounts.db())?; + storage.refund_unused_gas(&mut origin)?; storage.finalize(accounts.program_id())?; } else { storage.save_data()?; diff --git a/evm_loader/program/src/instruction/transaction_step_from_account.rs b/evm_loader/program/src/instruction/transaction_step_from_account.rs index fac16e504..df3c4db12 100644 --- a/evm_loader/program/src/instruction/transaction_step_from_account.rs +++ b/evm_loader/program/src/instruction/transaction_step_from_account.rs @@ -31,7 +31,7 @@ pub fn process_inner<'a>( let treasury_index = u32::from_le_bytes(*array_ref![instruction, 0, 4]); let step_count = u64::from(u32::from_le_bytes(*array_ref![instruction, 4, 4])); - let holder_or_storage = &accounts[0]; + let holder_or_storage = accounts[0].clone(); let operator = Operator::from_account(&accounts[1])?; let treasury = Treasury::from_account(program_id, treasury_index, &accounts[2])?; @@ -89,19 +89,14 @@ pub fn process_inner<'a>( excessive_lamports += crate::account::legacy::update_legacy_accounts(&accounts_db)?; gasometer.refund_lamports(excessive_lamports); - let storage = StateAccount::new( - program_id, - holder_or_storage.clone(), - &accounts_db, - origin, - trx, - )?; + let storage = + StateAccount::new(program_id, holder_or_storage, &accounts_db, origin, trx)?; do_begin(accounts_db, storage, gasometer) } TAG_STATE => { let (storage, accounts_status) = - StateAccount::restore(program_id, holder_or_storage.clone(), &accounts_db)?; + StateAccount::restore(program_id, holder_or_storage, &accounts_db)?; operator_balance.validate_transaction(storage.trx())?; let miner_address = operator_balance.miner(storage.trx_origin()); From d8142503b40083f8d2eb16ac8b3f0160c08f1317 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Fri, 24 May 2024 19:52:12 +0300 Subject: [PATCH 210/318] Set version to v1.13.0-dev --- evm_loader/Cargo.lock | 10 +++++----- evm_loader/api/Cargo.toml | 2 +- evm_loader/cli/Cargo.toml | 2 +- evm_loader/lib/Cargo.toml | 2 +- evm_loader/program/Cargo.toml | 2 +- evm_loader/rpc/Cargo.toml | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 8cfafb495..8d2c3f35d 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -2005,7 +2005,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "evm-loader" -version = "1.11.0-dev" +version = "1.13.0-dev" dependencies = [ "arrayref", "async-trait", @@ -3301,7 +3301,7 @@ dependencies = [ [[package]] name = "neon-api" -version = "1.11.0-dev" +version = "1.13.0-dev" dependencies = [ "actix-request-identifier", "actix-web", @@ -3324,7 +3324,7 @@ dependencies = [ [[package]] name = "neon-cli" -version = "1.11.0-dev" +version = "1.13.0-dev" dependencies = [ "build-info", "build-info-build", @@ -3346,7 +3346,7 @@ dependencies = [ [[package]] name = "neon-lib" -version = "1.11.0-dev" +version = "1.13.0-dev" dependencies = [ "abi_stable", "anyhow", @@ -3405,7 +3405,7 @@ dependencies = [ [[package]] name = "neon-rpc" -version = "0.1.0" +version = "1.13.0-dev" dependencies = [ "actix-web", "build-info", diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 7db35bf01..48067663f 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "neon-api" -version = "1.11.0-dev" +version = "1.13.0-dev" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index 8233fcda8..b0be1bb42 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "neon-cli" -version = "1.11.0-dev" +version = "1.13.0-dev" authors = ["NeonLabs Maintainers "] edition = "2021" diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 19acef3f9..cd446a63e 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "neon-lib" -version = "1.11.0-dev" +version = "1.13.0-dev" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index f466dcb67..0d43ae79a 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "evm-loader" -version = "1.11.0-dev" +version = "1.13.0-dev" description = "Neon EVM loader" authors = ["NeonLabs Maintainers "] edition = "2021" diff --git a/evm_loader/rpc/Cargo.toml b/evm_loader/rpc/Cargo.toml index 707283f1a..a9fc197af 100644 --- a/evm_loader/rpc/Cargo.toml +++ b/evm_loader/rpc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "neon-rpc" -version = "0.1.0" +version = "1.13.0-dev" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From e70336a3955c70661edc02b69989ddd3594f5700 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 May 2024 11:24:11 +0300 Subject: [PATCH 211/318] Bump thiserror from 1.0.58 to 1.0.61 in /evm_loader (#441) Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.58 to 1.0.61. - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](https://github.com/dtolnay/thiserror/compare/1.0.58...1.0.61) --- updated-dependencies: - dependency-name: thiserror dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 8 ++++---- evm_loader/rpc-client/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 8d2c3f35d..ba2b5dad0 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -6536,18 +6536,18 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.58" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.58" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", diff --git a/evm_loader/rpc-client/Cargo.toml b/evm_loader/rpc-client/Cargo.toml index 0c1950900..acb93d216 100644 --- a/evm_loader/rpc-client/Cargo.toml +++ b/evm_loader/rpc-client/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" serde = "1.0.202" serde_json = "1.0.117" neon-lib = { path = "../lib" } -thiserror = "1.0.58" +thiserror = "1.0.61" async-trait = "0.1.80" jsonrpsee-core = "0.22.3" jsonrpsee-http-client = "0.22.3" From 71588b899ec9b8d1e400421123fe361b86bf161b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 May 2024 16:45:36 +0300 Subject: [PATCH 212/318] Bump serde from 1.0.202 to 1.0.203 in /evm_loader (#443) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.202 to 1.0.203. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.202...v1.0.203) --- updated-dependencies: - dependency-name: serde dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 8 ++++---- evm_loader/api/Cargo.toml | 2 +- evm_loader/cli/Cargo.toml | 2 +- evm_loader/lib-interface/Cargo.toml | 2 +- evm_loader/program/Cargo.toml | 2 +- evm_loader/rpc-client/Cargo.toml | 2 +- evm_loader/rpc/Cargo.toml | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index ba2b5dad0..d654476d2 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -4682,9 +4682,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.202" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] @@ -4700,9 +4700,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.202" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 48067663f..a80107971 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -10,7 +10,7 @@ clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } solana-sdk.workspace = true solana-client.workspace = true -serde = "1.0.202" +serde = "1.0.203" serde_json = { version = "1.0.117", features = ["preserve_order"] } ethnum = { version = "1.5", default-features = false, features = ["serde"] } tokio = { version = "1", features = ["full"] } diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index b0be1bb42..09e011153 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -13,7 +13,7 @@ solana-client.workspace = true solana-clap-utils.workspace = true solana-cli-config.workspace = true hex = "0.4.2" -serde = "1.0.202" +serde = "1.0.203" serde_json = { version = "1.0.117", features = ["preserve_order"] } log = "0.4.21" fern = "0.6" diff --git a/evm_loader/lib-interface/Cargo.toml b/evm_loader/lib-interface/Cargo.toml index d7e8c2f30..b8889e67a 100644 --- a/evm_loader/lib-interface/Cargo.toml +++ b/evm_loader/lib-interface/Cargo.toml @@ -9,5 +9,5 @@ edition = "2021" abi_stable = "0.11.1" thiserror = "1" async-ffi = { version = "0.5.0", features = ["abi_stable"] } -serde = "1.0.202" +serde = "1.0.203" serde_json = "1.0.117" diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 0d43ae79a..b1714ae4c 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -50,7 +50,7 @@ static_assertions = "1" borsh = "0.10" bincode = "1" serde_bytes = "0.11.14" -serde = { version = "1.0.202", default-features = false, features = ["derive", "rc"] } +serde = { version = "1.0.203", default-features = false, features = ["derive", "rc"] } ethnum = { version = "1.5", default-features = false, features = ["serde"] } cfg-if = { version = "1.0" } log = { version = "0.4", default-features = false, optional = true } diff --git a/evm_loader/rpc-client/Cargo.toml b/evm_loader/rpc-client/Cargo.toml index acb93d216..2923cb505 100644 --- a/evm_loader/rpc-client/Cargo.toml +++ b/evm_loader/rpc-client/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -serde = "1.0.202" +serde = "1.0.203" serde_json = "1.0.117" neon-lib = { path = "../lib" } thiserror = "1.0.61" diff --git a/evm_loader/rpc/Cargo.toml b/evm_loader/rpc/Cargo.toml index a9fc197af..adcf73ddd 100644 --- a/evm_loader/rpc/Cargo.toml +++ b/evm_loader/rpc/Cargo.toml @@ -12,7 +12,7 @@ jsonrpc-v2 = "0.13.0" neon-lib-interface = { path = "../lib-interface" } neon-lib = { path = "../lib" } semver = "1.0.23" -serde = "1.0.202" +serde = "1.0.203" serde_json = "1.0.117" tokio = { version = "1", features = ["full"] } build-info = { version = "0.0.31", features = ["serde"] } From 121ffbf0585d2957c7720e6df62a9f99b4f52a09 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 May 2024 10:31:58 +0300 Subject: [PATCH 213/318] Bump proc-macro2 from 1.0.83 to 1.0.84 in /evm_loader (#444) Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.83 to 1.0.84. - [Release notes](https://github.com/dtolnay/proc-macro2/releases) - [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.83...1.0.84) --- updated-dependencies: - dependency-name: proc-macro2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index d654476d2..7e7778cf6 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -4011,9 +4011,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.83" +version = "1.0.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" +checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6" dependencies = [ "unicode-ident", ] From 35868ba3cab971fa9ae2833ba4acfca8ea369bf5 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Tue, 28 May 2024 10:38:19 +0300 Subject: [PATCH 214/318] NDEV-3064: Truncate AccountRow::data Debug representation (#445) --- evm_loader/lib/src/types/tracer_ch_common.rs | 39 ++++++++++---------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/evm_loader/lib/src/types/tracer_ch_common.rs b/evm_loader/lib/src/types/tracer_ch_common.rs index 6293a8812..16ab260e7 100644 --- a/evm_loader/lib/src/types/tracer_ch_common.rs +++ b/evm_loader/lib/src/types/tracer_ch_common.rs @@ -1,6 +1,7 @@ use std::fmt; use clickhouse::Row; +use evm_loader::solana_program::debug_account_data::debug_account_data; use serde::{Deserialize, Serialize}; use solana_sdk::{account::Account, pubkey::Pubkey}; use std::collections::BTreeMap; @@ -68,35 +69,35 @@ pub struct AccountRow { pub lamports: u64, pub executable: bool, pub rent_epoch: u64, - #[allow(clippy::missing_fields_in_debug)] pub data: Vec, - #[allow(clippy::missing_fields_in_debug)] pub txn_signature: Vec>, } -impl fmt::Display for AccountRow { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "AccountRow {{\n owner: {},\n lamports: {},\n executable: {},\n rent_epoch: {},\n}}", - bs58::encode(&self.owner).into_string(), - self.lamports, - self.executable, - self.rent_epoch, - ) - } -} - impl fmt::Debug for AccountRow { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Account") + let mut debug_struct = f.debug_struct("Account"); + + debug_struct .field("owner", &bs58::encode(&self.owner).into_string()) .field("lamports", &self.lamports) .field("executable", &self.executable) .field("rent_epoch", &self.rent_epoch) - .field("data", &self.data) - .field("txn_signature:", &self.txn_signature) - .finish() + .field("data_len", &self.data.len()); + + debug_account_data(&self.data, &mut debug_struct); + + debug_struct.field( + "txn_signature", + &bs58::encode( + self.txn_signature + .iter() + .filter_map(|option| *option) + .collect::>(), + ) + .into_string(), + ); + + debug_struct.finish() } } From 7cc79ec6c44f116f302f0e6717bff8f4bd590c96 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Fri, 31 May 2024 10:22:18 +0300 Subject: [PATCH 215/318] NDEV-3080 Reduce number of requests for config (#448) --- evm_loader/lib/src/account_storage_tests.rs | 3 ++ evm_loader/lib/src/commands/get_config.rs | 33 ++++++++++++------- .../lib/src/commands/simulate_solana.rs | 7 ++-- evm_loader/lib/src/solana_simulator/mod.rs | 14 ++++++-- evm_loader/lib/src/solana_simulator/utils.rs | 13 ++++++-- 5 files changed, 51 insertions(+), 19 deletions(-) diff --git a/evm_loader/lib/src/account_storage_tests.rs b/evm_loader/lib/src/account_storage_tests.rs index d6ebf1e5b..84066b3ad 100644 --- a/evm_loader/lib/src/account_storage_tests.rs +++ b/evm_loader/lib/src/account_storage_tests.rs @@ -75,6 +75,9 @@ mod mock_rpc_client { #[async_trait(?Send)] impl BuildConfigSimulator for MockRpcClient { + fn use_cache(&self) -> bool { + false + } async fn build_config_simulator(&self, _program_id: Pubkey) -> NeonResult { unimplemented!(); } diff --git a/evm_loader/lib/src/commands/get_config.rs b/evm_loader/lib/src/commands/get_config.rs index 3a592fafc..0219afc33 100644 --- a/evm_loader/lib/src/commands/get_config.rs +++ b/evm_loader/lib/src/commands/get_config.rs @@ -5,6 +5,7 @@ use base64::Engine; use enum_dispatch::enum_dispatch; use solana_sdk::signer::Signer; use std::collections::BTreeMap; +use tokio::sync::OnceCell; use serde::{Deserialize, Serialize}; use solana_sdk::{instruction::Instruction, pubkey::Pubkey, transaction::Transaction}; @@ -57,11 +58,16 @@ pub enum ConfigSimulator<'r> { #[async_trait(?Send)] #[enum_dispatch] pub trait BuildConfigSimulator { + fn use_cache(&self) -> bool; async fn build_config_simulator(&self, program_id: Pubkey) -> NeonResult; } #[async_trait(?Send)] impl BuildConfigSimulator for CloneRpcClient { + fn use_cache(&self) -> bool { + true + } + async fn build_config_simulator(&self, program_id: Pubkey) -> NeonResult { Ok(ConfigSimulator::CloneRpcClient { program_id, @@ -72,8 +78,12 @@ impl BuildConfigSimulator for CloneRpcClient { #[async_trait(?Send)] impl BuildConfigSimulator for CallDbClient { + fn use_cache(&self) -> bool { + false + } + async fn build_config_simulator(&self, program_id: Pubkey) -> NeonResult { - let mut simulator = SolanaSimulator::new(self).await?; + let mut simulator = SolanaSimulator::new_without_sync(self).await?; simulator.sync_accounts(self, &[program_id]).await?; Ok(ConfigSimulator::ProgramTestContext { @@ -269,25 +279,24 @@ pub async fn execute( }) } +static CHAINS_CACHE: OnceCell> = OnceCell::const_new(); + pub async fn read_chains( rpc: &impl BuildConfigSimulator, program_id: Pubkey, ) -> NeonResult> { - let mut simulator = rpc.build_config_simulator(program_id).await?; - - simulator.get_chains().await -} + if rpc.use_cache() && CHAINS_CACHE.initialized() { + return Ok(CHAINS_CACHE.get().unwrap().clone()); + } -pub async fn read_default_chain_id( - rpc: &impl BuildConfigSimulator, - program_id: Pubkey, -) -> NeonResult { let mut simulator = rpc.build_config_simulator(program_id).await?; - let chains = simulator.get_chains().await?; - let default_chain = chains.iter().find(|chain| chain.name == "neon").unwrap(); - Ok(default_chain.id) + if rpc.use_cache() { + CHAINS_CACHE.set(chains.clone()).unwrap(); + } + + Ok(chains) } #[cfg(test)] diff --git a/evm_loader/lib/src/commands/simulate_solana.rs b/evm_loader/lib/src/commands/simulate_solana.rs index b4aae0452..44bee35fc 100644 --- a/evm_loader/lib/src/commands/simulate_solana.rs +++ b/evm_loader/lib/src/commands/simulate_solana.rs @@ -11,7 +11,10 @@ use solana_sdk::{ }; use crate::{ - rpc::Rpc, solana_simulator::SolanaSimulator, types::SimulateSolanaRequest, NeonResult, + rpc::Rpc, + solana_simulator::{SolanaSimulator, SyncState}, + types::SimulateSolanaRequest, + NeonResult, }; #[serde_as] @@ -92,7 +95,7 @@ pub async fn execute( let verify = request.verify.unwrap_or(true); let config = runtime_config(&request); - let mut simulator = SolanaSimulator::new_with_config(rpc, config).await?; + let mut simulator = SolanaSimulator::new_with_config(rpc, config, SyncState::Yes).await?; // Decode transactions from bytes let mut transactions: Vec = vec![]; diff --git a/evm_loader/lib/src/solana_simulator/mod.rs b/evm_loader/lib/src/solana_simulator/mod.rs index 1c731203c..ea431a323 100644 --- a/evm_loader/lib/src/solana_simulator/mod.rs +++ b/evm_loader/lib/src/solana_simulator/mod.rs @@ -25,6 +25,7 @@ mod error; mod utils; pub use error::Error; +pub use utils::SyncState; pub struct SolanaSimulator { bank: Bank, @@ -34,16 +35,21 @@ pub struct SolanaSimulator { impl SolanaSimulator { pub async fn new(rpc: &impl Rpc) -> Result { - Self::new_with_config(rpc, RuntimeConfig::default()).await + Self::new_with_config(rpc, RuntimeConfig::default(), SyncState::Yes).await + } + + pub async fn new_without_sync(rpc: &impl Rpc) -> Result { + Self::new_with_config(rpc, RuntimeConfig::default(), SyncState::No).await } pub async fn new_with_config( rpc: &impl Rpc, runtime_config: RuntimeConfig, + sync_state: SyncState, ) -> Result { let runtime_config = Arc::new(runtime_config); - let info = utils::genesis_config_info(rpc, 1_000.0).await?; + let info = utils::genesis_config_info(rpc, sync_state, 1_000.0).await?; let payer = info.mint_keypair; let genesis_bank = Arc::new(Bank::new_with_paths( @@ -69,7 +75,9 @@ impl SolanaSimulator { genesis_bank.slot() + 1, ); - utils::sync_sysvar_accounts(rpc, &bank).await?; + if sync_state == SyncState::Yes { + utils::sync_sysvar_accounts(rpc, &bank).await?; + } Ok(Self { bank, diff --git a/evm_loader/lib/src/solana_simulator/utils.rs b/evm_loader/lib/src/solana_simulator/utils.rs index 5fa6772d2..9e44dffcc 100644 --- a/evm_loader/lib/src/solana_simulator/utils.rs +++ b/evm_loader/lib/src/solana_simulator/utils.rs @@ -21,8 +21,15 @@ use solana_sdk::{ use crate::rpc::Rpc; +#[derive(Eq, PartialEq, Copy, Clone)] +pub enum SyncState { + No, + Yes, +} + pub async fn genesis_config_info( rpc: &impl Rpc, + sync: SyncState, mint_sol: f64, ) -> Result { let rent = sysvar::rent::Rent::default(); @@ -53,8 +60,10 @@ pub async fn genesis_config_info( vec![], ); - for feature in deactivated_features(rpc).await? { - genesis_config.accounts.remove(&feature); + if sync == SyncState::Yes { + for feature in deactivated_features(rpc).await? { + genesis_config.accounts.remove(&feature); + } } Ok(GenesisConfigInfo { From 44d7ddad00dffa3d3d803ee6498749ffe0895786 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 16:21:54 +0300 Subject: [PATCH 216/318] Bump proc-macro2 from 1.0.84 to 1.0.85 in /evm_loader (#449) Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.84 to 1.0.85. - [Release notes](https://github.com/dtolnay/proc-macro2/releases) - [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.84...1.0.85) --- updated-dependencies: - dependency-name: proc-macro2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 7e7778cf6..81c0d32fb 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -4011,9 +4011,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.84" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" dependencies = [ "unicode-ident", ] From 02a82cc05414eef54b8e97a3a265783168c24957 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Tue, 4 Jun 2024 15:06:33 +0300 Subject: [PATCH 217/318] NDEV-3080 Neon-API Optimizations (#450) --- evm_loader/lib/src/account_storage.rs | 147 +++++++++--------- evm_loader/lib/src/account_storage_tests.rs | 13 +- .../lib/src/commands/collect_treasury.rs | 2 +- evm_loader/lib/src/commands/get_neon_elf.rs | 13 +- evm_loader/lib/src/rpc/db_call_client.rs | 13 +- evm_loader/lib/src/rpc/emulator_client.rs | 96 ++++++++++++ evm_loader/lib/src/rpc/mod.rs | 9 +- evm_loader/lib/src/rpc/validator_client.rs | 55 +++++-- evm_loader/lib/src/solana_simulator/utils.rs | 24 +-- 9 files changed, 231 insertions(+), 141 deletions(-) create mode 100644 evm_loader/lib/src/rpc/emulator_client.rs diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index 2df59a10f..4f686a960 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -16,13 +16,10 @@ use evm_loader::{ types::Address, }; use log::{debug, info, trace}; -use solana_client::client_error::{self, Result as ClientResult}; -use solana_client::rpc_response::{Response, RpcResponseContext, RpcResult}; use solana_sdk::{ account::Account, account_info::{AccountInfo, IntoAccountInfo}, - clock::{Clock, Slot, UnixTimestamp}, - commitment_config::CommitmentConfig, + clock::Clock, instruction::Instruction, program_error::ProgramError, pubkey, @@ -34,7 +31,7 @@ use solana_sdk::{ }; use std::collections::{HashMap, HashSet}; use std::{ - cell::{RefCell, RefMut}, + cell::{Ref, RefCell, RefMut}, convert::TryInto, rc::Rc, }; @@ -119,65 +116,6 @@ pub struct EmulatorAccountStorage<'rpc, T: Rpc> { return_data: RefCell>, } -#[async_trait(?Send)] -impl<'rpc, T: Rpc> Rpc for EmulatorAccountStorage<'rpc, T> { - async fn get_account(&self, key: &Pubkey) -> RpcResult> { - let account = if *key == self.operator { - Some(Account { - lamports: 100 * 1_000_000_000, - data: vec![], - owner: system_program::ID, - executable: false, - rent_epoch: 0, - }) - } else if let Some(account) = self.accounts.get(key) { - let acc = &*account.borrow(); - Some(acc.into()) - } else { - self._get_account_from_rpc(*key).await?.cloned() - }; - - Ok(Response { - context: RpcResponseContext { - slot: self.block_number, - api_version: None, - }, - value: account, - }) - } - - async fn get_account_with_commitment( - &self, - _key: &Pubkey, - _commitment: CommitmentConfig, - ) -> RpcResult> { - unimplemented!(); - } - - async fn get_multiple_accounts( - &self, - pubkeys: &[Pubkey], - ) -> ClientResult>> { - // TODO: Optimize this!!! - let mut result = vec![]; - for key in pubkeys { - let account = self.get_account(key).await?.value; - result.push(account); - } - Ok(result) - } - - async fn get_block_time(&self, _slot: Slot) -> ClientResult { - // Ok(self.block_timestamp) - unimplemented!(); - } - - async fn get_slot(&self) -> ClientResult { - //Ok(self.block_number) - unimplemented!(); - } -} - impl<'rpc, T: Rpc + BuildConfigSimulator> EmulatorAccountStorage<'rpc, T> { pub async fn new( rpc: &'rpc T, @@ -342,10 +280,16 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { Ok(()) } + pub async fn _get_deactivated_solana_features( + &self, + ) -> solana_client::client_error::Result> { + self.rpc.get_deactivated_solana_features().await + } + pub async fn _get_account_from_rpc( &self, pubkey: Pubkey, - ) -> client_error::Result> { + ) -> solana_client::client_error::Result> { if pubkey == FAKE_OPERATOR { return Ok(None); } @@ -359,6 +303,51 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { Ok(account.as_ref()) } + pub async fn _get_multiple_accounts_from_rpc( + &self, + pubkeys: &[Pubkey], + ) -> solana_client::client_error::Result>> { + let mut accounts = vec![None; pubkeys.len()]; + + let mut exists = vec![true; pubkeys.len()]; + let mut missing_keys = Vec::with_capacity(pubkeys.len()); + + for (i, pubkey) in pubkeys.iter().enumerate() { + if pubkey == &FAKE_OPERATOR { + continue; + } + + let Some(account) = self.accounts_cache.get(pubkey) else { + exists[i] = false; + missing_keys.push(*pubkey); + continue; + }; + + accounts[i] = account.as_ref(); + } + + let mut response = self.rpc.get_multiple_accounts(&missing_keys).await?; + + let mut j = 0_usize; + for i in 0..pubkeys.len() { + if exists[i] { + continue; + } + + let pubkey = missing_keys[j]; + let account = response[j].take(); + let account = self.accounts_cache.insert(pubkey, Box::new(account)); + // ^ .insert() returns the reference to the account that was just inserted + + assert_eq!(pubkeys[i], pubkey); + accounts[i] = account.as_ref(); + + j += 1; + } + + Ok(accounts) + } + fn mark_account(&self, pubkey: Pubkey, is_writable: bool) { let mut data = self._get_account_mark(pubkey); data.is_writable |= is_writable; @@ -839,6 +828,10 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { .collect::>() } + pub fn accounts_get(&self, pubkey: &Pubkey) -> Option> { + self.accounts.get(pubkey).map(RefCell::borrow) + } + pub fn get_upgrade_rent(&self) -> evm_loader::error::Result { let mut lamports_collected = 0u64; let mut lamports_spend = 0u64; @@ -1105,16 +1098,9 @@ impl AccountStorage for EmulatorAccountStorage<'_, T> { info!("clone_solana_account {}", address); if *address == self.operator() { - OwnedAccountInfo { - key: self.operator(), - is_signer: true, - is_writable: false, - lamports: 100 * 1_000_000_000, - data: vec![], - owner: system_program::ID, - executable: false, - rent_epoch: 0, - } + let mut account = fake_operator(); + let info = account_info(address, &mut account); + OwnedAccountInfo::from_account_info(self.program_id(), &info) } else { let account = self .use_account(*address, false) @@ -1423,6 +1409,17 @@ impl SyncedAccountStorage for EmulatorAccountStorage<'_, T> { } } +#[must_use] +pub const fn fake_operator() -> Account { + Account { + lamports: 100 * 1_000_000_000, + data: vec![], + owner: system_program::ID, + executable: false, + rent_epoch: 0, + } +} + /// Creates new instance of `AccountInfo` from `Account`. pub fn account_info<'a>(key: &'a Pubkey, account: &'a mut Account) -> AccountInfo<'a> { AccountInfo { diff --git a/evm_loader/lib/src/account_storage_tests.rs b/evm_loader/lib/src/account_storage_tests.rs index 84066b3ad..25a4e6576 100644 --- a/evm_loader/lib/src/account_storage_tests.rs +++ b/evm_loader/lib/src/account_storage_tests.rs @@ -16,7 +16,6 @@ mod mock_rpc_client { use solana_client::rpc_response::{Response, RpcResponseContext, RpcResult}; use solana_sdk::account::Account; use solana_sdk::clock::{Slot, UnixTimestamp}; - use solana_sdk::commitment_config::CommitmentConfig; use solana_sdk::pubkey::Pubkey; use std::collections::HashMap; @@ -45,14 +44,6 @@ mod mock_rpc_client { }) } - async fn get_account_with_commitment( - &self, - key: &Pubkey, - _commitment: CommitmentConfig, - ) -> RpcResult> { - self.get_account(key).await - } - async fn get_multiple_accounts( &self, pubkeys: &[Pubkey], @@ -71,6 +62,10 @@ mod mock_rpc_client { async fn get_slot(&self) -> ClientResult { Ok(Slot::default()) } + + async fn get_deactivated_solana_features(&self) -> ClientResult> { + Ok(vec![]) + } } #[async_trait(?Send)] diff --git a/evm_loader/lib/src/commands/collect_treasury.rs b/evm_loader/lib/src/commands/collect_treasury.rs index 709df6a5e..42a090293 100644 --- a/evm_loader/lib/src/commands/collect_treasury.rs +++ b/evm_loader/lib/src/commands/collect_treasury.rs @@ -1,4 +1,4 @@ -use crate::rpc::{check_account_for_fee, CloneRpcClient, Rpc}; +use crate::rpc::{check_account_for_fee, CloneRpcClient}; use crate::{ commands::get_neon_elf::read_elf_parameters_from_account, errors::NeonError, Config, NeonResult, }; diff --git a/evm_loader/lib/src/commands/get_neon_elf.rs b/evm_loader/lib/src/commands/get_neon_elf.rs index 19996a626..af15c276f 100644 --- a/evm_loader/lib/src/commands/get_neon_elf.rs +++ b/evm_loader/lib/src/commands/get_neon_elf.rs @@ -168,7 +168,7 @@ pub async fn read_program_data_from_account( evm_loader: &Pubkey, ) -> Result<(Option, Vec), NeonError> { let account = rpc - .get_account_with_commitment(evm_loader, config.commitment) + .get_account(evm_loader) .await? .value .ok_or(NeonError::AccountNotFound(*evm_loader))?; @@ -180,14 +180,9 @@ pub async fn read_program_data_from_account( programdata_address, }) = account.state() { - let programdata_account = rpc - .get_account_with_commitment(&programdata_address, config.commitment) - .await? - .value - .ok_or(NeonError::AssociatedPdaNotFound( - programdata_address, - config.evm_loader, - ))?; + let programdata_account = rpc.get_account(&programdata_address).await?.value.ok_or( + NeonError::AssociatedPdaNotFound(programdata_address, config.evm_loader), + )?; if let Ok(UpgradeableLoaderState::ProgramData { upgrade_authority_address, diff --git a/evm_loader/lib/src/rpc/db_call_client.rs b/evm_loader/lib/src/rpc/db_call_client.rs index b16fc9944..baf538d3f 100644 --- a/evm_loader/lib/src/rpc/db_call_client.rs +++ b/evm_loader/lib/src/rpc/db_call_client.rs @@ -10,7 +10,6 @@ use solana_client::{ use solana_sdk::{ account::Account, clock::{Slot, UnixTimestamp}, - commitment_config::CommitmentConfig, pubkey::Pubkey, }; @@ -65,14 +64,6 @@ impl Rpc for CallDbClient { self.get_account(key).await } - async fn get_account_with_commitment( - &self, - key: &Pubkey, - _: CommitmentConfig, - ) -> RpcResult> { - self.get_account(key).await - } - async fn get_multiple_accounts( &self, pubkeys: &[Pubkey], @@ -94,4 +85,8 @@ impl Rpc for CallDbClient { async fn get_slot(&self) -> ClientResult { Ok(self.slot) } + + async fn get_deactivated_solana_features(&self) -> ClientResult> { + Ok(vec![]) // TODO + } } diff --git a/evm_loader/lib/src/rpc/emulator_client.rs b/evm_loader/lib/src/rpc/emulator_client.rs new file mode 100644 index 000000000..e90b2b2cc --- /dev/null +++ b/evm_loader/lib/src/rpc/emulator_client.rs @@ -0,0 +1,96 @@ +use async_trait::async_trait; +use evm_loader::account_storage::AccountStorage; +use solana_client::{ + client_error::Result as ClientResult, + rpc_response::{Response, RpcResponseContext, RpcResult}, +}; +use solana_sdk::{ + account::Account, + clock::{Slot, UnixTimestamp}, + pubkey::Pubkey, +}; + +use crate::account_storage::{fake_operator, EmulatorAccountStorage}; + +use super::Rpc; + +#[async_trait(?Send)] +impl<'rpc, T: Rpc> Rpc for EmulatorAccountStorage<'rpc, T> { + async fn get_account(&self, key: &Pubkey) -> RpcResult> { + let block_number = self.block_number().as_u64(); + let context = RpcResponseContext::new(block_number); + + if *key == self.operator() { + return Ok(Response { + context, + value: Some(fake_operator()), + }); + } + + if let Some(account_data) = self.accounts_get(key) { + return Ok(Response { + context, + value: Some(Account::from(&*account_data)), + }); + } + + let account = self._get_account_from_rpc(*key).await?.cloned(); + Ok(Response { + context, + value: account, + }) + } + + async fn get_multiple_accounts( + &self, + pubkeys: &[Pubkey], + ) -> ClientResult>> { + let mut accounts = vec![None; pubkeys.len()]; + + let mut exists = vec![true; pubkeys.len()]; + let mut missing_keys = Vec::with_capacity(pubkeys.len()); + + for (i, pubkey) in pubkeys.iter().enumerate() { + if pubkey == &self.operator() { + accounts[i] = Some(fake_operator()); + continue; + } + + if let Some(account_data) = self.accounts_get(pubkey) { + accounts[i] = Some(Account::from(&*account_data)); + continue; + } + + exists[i] = false; + missing_keys.push(*pubkey); + } + + let response = self._get_multiple_accounts_from_rpc(&missing_keys).await?; + + let mut j = 0_usize; + for i in 0..pubkeys.len() { + if exists[i] { + continue; + } + + assert_eq!(pubkeys[i], missing_keys[j]); + accounts[i] = response[j].cloned(); + + j += 1; + } + + Ok(accounts) + } + + async fn get_block_time(&self, _slot: Slot) -> ClientResult { + Ok(self.block_timestamp().as_i64()) + } + + async fn get_slot(&self) -> ClientResult { + Ok(self.block_number().as_u64()) + } + + async fn get_deactivated_solana_features(&self) -> ClientResult> { + self._get_deactivated_solana_features().await + } +} diff --git a/evm_loader/lib/src/rpc/mod.rs b/evm_loader/lib/src/rpc/mod.rs index 995b0203f..aee0f58d6 100644 --- a/evm_loader/lib/src/rpc/mod.rs +++ b/evm_loader/lib/src/rpc/mod.rs @@ -1,4 +1,5 @@ mod db_call_client; +mod emulator_client; mod validator_client; pub use db_call_client::CallDbClient; @@ -15,7 +16,6 @@ use solana_sdk::native_token::lamports_to_sol; use solana_sdk::{ account::Account, clock::{Slot, UnixTimestamp}, - commitment_config::CommitmentConfig, pubkey::Pubkey, }; @@ -23,15 +23,12 @@ use solana_sdk::{ #[enum_dispatch] pub trait Rpc { async fn get_account(&self, key: &Pubkey) -> RpcResult>; - async fn get_account_with_commitment( - &self, - key: &Pubkey, - commitment: CommitmentConfig, - ) -> RpcResult>; async fn get_multiple_accounts(&self, pubkeys: &[Pubkey]) -> ClientResult>>; async fn get_block_time(&self, slot: Slot) -> ClientResult; async fn get_slot(&self) -> ClientResult; + + async fn get_deactivated_solana_features(&self) -> ClientResult>; } #[enum_dispatch(BuildConfigSimulator, Rpc)] diff --git a/evm_loader/lib/src/rpc/validator_client.rs b/evm_loader/lib/src/rpc/validator_client.rs index bace210c0..871d2cd3f 100644 --- a/evm_loader/lib/src/rpc/validator_client.rs +++ b/evm_loader/lib/src/rpc/validator_client.rs @@ -9,7 +9,6 @@ use solana_client::{ use solana_sdk::{ account::Account, clock::{Slot, UnixTimestamp}, - commitment_config::CommitmentConfig, pubkey::Pubkey, }; use std::ops::Deref; @@ -63,14 +62,6 @@ impl Rpc for CloneRpcClient { .await } - async fn get_account_with_commitment( - &self, - key: &Pubkey, - commitment: CommitmentConfig, - ) -> RpcResult> { - self.rpc.get_account_with_commitment(key, commitment).await - } - async fn get_multiple_accounts( &self, pubkeys: &[Pubkey], @@ -91,4 +82,50 @@ impl Rpc for CloneRpcClient { async fn get_slot(&self) -> ClientResult { self.rpc.get_slot().await } + + async fn get_deactivated_solana_features(&self) -> ClientResult> { + use std::time::{Duration, Instant}; + use tokio::sync::Mutex; + + struct Cache { + data: Vec, + timestamp: Instant, + } + + static CACHE: Mutex> = Mutex::const_new(None); + let mut cache = CACHE.lock().await; + + if let Some(cache) = cache.as_ref() { + if cache.timestamp.elapsed() < Duration::from_secs(24 * 60 * 60) { + return Ok(cache.data.clone()); + } + } + + let feature_keys: Vec = solana_sdk::feature_set::FEATURE_NAMES + .keys() + .copied() + .collect(); + + let features = Rpc::get_multiple_accounts(self, &feature_keys).await?; + + let mut result = Vec::with_capacity(feature_keys.len()); + for (pubkey, feature) in feature_keys.iter().zip(features) { + let is_activated = feature + .and_then(|a| solana_sdk::feature::from_account(&a)) + .and_then(|f| f.activated_at) + .is_some(); + + if !is_activated { + result.push(*pubkey); + } + } + + cache.replace(Cache { + data: result.clone(), + timestamp: Instant::now(), + }); + drop(cache); + + Ok(result) + } } diff --git a/evm_loader/lib/src/solana_simulator/utils.rs b/evm_loader/lib/src/solana_simulator/utils.rs index 9e44dffcc..162a29ea2 100644 --- a/evm_loader/lib/src/solana_simulator/utils.rs +++ b/evm_loader/lib/src/solana_simulator/utils.rs @@ -61,7 +61,7 @@ pub async fn genesis_config_info( ); if sync == SyncState::Yes { - for feature in deactivated_features(rpc).await? { + for feature in rpc.get_deactivated_solana_features().await? { genesis_config.accounts.remove(&feature); } } @@ -74,28 +74,6 @@ pub async fn genesis_config_info( }) } -pub async fn deactivated_features(rpc: &impl Rpc) -> Result, Error> { - let feature_keys: Vec = solana_sdk::feature_set::FEATURE_NAMES - .keys() - .copied() - .collect(); - let features = rpc.get_multiple_accounts(&feature_keys).await?; - - let mut result = Vec::with_capacity(feature_keys.len()); - for (pubkey, feature) in feature_keys.iter().zip(features) { - let is_activated = feature - .and_then(|a| solana_sdk::feature::from_account(&a)) - .and_then(|f| f.activated_at) - .is_some(); - - if !is_activated { - result.push(*pubkey); - } - } - - Ok(result) -} - pub async fn sync_sysvar_accounts(rpc: &impl Rpc, bank: &Bank) -> Result<(), Error> { let keys = sysvar::ALL_IDS.clone(); let accounts = rpc.get_multiple_accounts(&keys).await?; From be77f29cd58a1d5028a1bd54be0e3d36db87d084 Mon Sep 17 00:00:00 2001 From: Kristina Nikolaeva <112946046+kristinaNikolaevaa@users.noreply.github.com> Date: Thu, 6 Jun 2024 08:21:30 -0700 Subject: [PATCH 218/318] fix CI neon-evm-tests step problem (#453) --- .github/workflows/deploy.py | 6 ++++-- .github/workflows/pipeline.yml | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index b825d1534..23b131ccc 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -111,7 +111,9 @@ def run_subprocess(command): @click.option('--github_sha') @click.option('--neon_test_branch') @click.option('--base_ref_branch') -def run_tests(github_sha, neon_test_branch, base_ref_branch): +@click.option('--run_number') +@click.option('--run_attempt') +def run_tests(github_sha, neon_test_branch, base_ref_branch, run_number, run_attempt): os.environ["EVM_LOADER_IMAGE"] = f"{IMAGE_NAME}:{github_sha}" if GithubClient.is_branch_exist(NEON_TESTS_ENDPOINT, neon_test_branch) \ @@ -123,7 +125,7 @@ def run_tests(github_sha, neon_test_branch, base_ref_branch): neon_test_image_tag = 'latest' os.environ["NEON_TESTS_IMAGE"] = f"{NEON_TEST_IMAGE_NAME}:{neon_test_image_tag}" click.echo(f"NEON_TESTS_IMAGE: {os.environ['NEON_TESTS_IMAGE']}") - project_name = f"neon-evm-{github_sha}" + project_name = f"neon-evm-{github_sha}-{run_number}-{run_attempt}" stop_containers(project_name) run_subprocess(f"docker-compose -p {project_name} -f ./ci/docker-compose-ci.yml pull") diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index c2d2f77a8..d0ca7826f 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -76,7 +76,9 @@ jobs: python3 ./.github/workflows/deploy.py run_tests \ --github_sha=${GITHUB_SHA} \ --neon_test_branch=${{ steps.neon_test_branch.outputs.value }} \ - --base_ref_branch=${{ github.base_ref }} + --base_ref_branch=${{ github.base_ref }} \ + --run_number=${{ github.run_number }} \ + --run_attempt=${{ github.run_attempt }} - name: Cancel the build if job failed if: "failure()" uses: "andymckay/cancel-action@0.4" From 36d8db61c4b3deabf8a610f2c73bcc945f0e21e7 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Thu, 6 Jun 2024 18:23:22 +0300 Subject: [PATCH 219/318] NDEV-3080 Neon-API Optimizations, part 2 (#454) --- evm_loader/Cargo.lock | 1 + evm_loader/api/src/api_server/handlers/mod.rs | 1 + evm_loader/lib/Cargo.toml | 1 + evm_loader/lib/src/account_storage.rs | 4 +- evm_loader/lib/src/account_storage_tests.rs | 11 +-- evm_loader/lib/src/commands/emulate.rs | 2 +- evm_loader/lib/src/commands/get_balance.rs | 77 ++++++++++------ evm_loader/lib/src/commands/get_config.rs | 13 +++ evm_loader/lib/src/commands/get_contract.rs | 53 ++++++----- evm_loader/lib/src/commands/get_holder.rs | 2 +- evm_loader/lib/src/commands/get_neon_elf.rs | 3 +- evm_loader/lib/src/config.rs | 20 ++++- evm_loader/lib/src/errors.rs | 6 +- evm_loader/lib/src/rpc/db_call_client.rs | 15 +--- evm_loader/lib/src/rpc/emulator_client.rs | 29 ++---- evm_loader/lib/src/rpc/mod.rs | 4 +- evm_loader/lib/src/rpc/validator_client.rs | 90 ++++++++++++++++--- evm_loader/lib/src/types/mod.rs | 2 +- 18 files changed, 208 insertions(+), 126 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 81c0d32fb..94ad416c6 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -3367,6 +3367,7 @@ dependencies = [ "goblin 0.6.1", "hex", "hex-literal", + "hyper", "lazy_static", "log", "neon-lib-interface", diff --git a/evm_loader/api/src/api_server/handlers/mod.rs b/evm_loader/api/src/api_server/handlers/mod.rs index 19a812265..9645f6ae2 100644 --- a/evm_loader/api/src/api_server/handlers/mod.rs +++ b/evm_loader/api/src/api_server/handlers/mod.rs @@ -67,6 +67,7 @@ fn process_error(status_code: StatusCode, e: &NeonError) -> (Json, Status Json(json!({ "result": "error", "error": e.to_string(), + "error_code": e.error_code(), })), status_code, ) diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index cd446a63e..338091728 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -9,6 +9,7 @@ edition = "2021" thiserror = "1.0" anyhow = "1.0" bincode = "1.3.1" +hyper = "0.14" evm-loader = { path = "../program", default-features = false, features = ["log", "async-trait"] } solana-sdk.workspace = true solana-client.workspace = true diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index 4f686a960..3602ea282 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -146,8 +146,8 @@ impl<'rpc, T: Rpc + BuildConfigSimulator> EmulatorAccountStorage<'rpc, T> { let rent_account = rpc .get_account(&solana_sdk::sysvar::rent::id()) .await? - .value .ok_or(NeonError::AccountNotFound(solana_sdk::sysvar::rent::id()))?; + let rent = bincode::deserialize::(&rent_account.data)?; info!("Rent: {rent:?}"); @@ -299,7 +299,7 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { } let response = self.rpc.get_account(&pubkey).await?; - let account = self.accounts_cache.insert(pubkey, Box::new(response.value)); + let account = self.accounts_cache.insert(pubkey, Box::new(response)); Ok(account.as_ref()) } diff --git a/evm_loader/lib/src/account_storage_tests.rs b/evm_loader/lib/src/account_storage_tests.rs index 25a4e6576..32ea5f277 100644 --- a/evm_loader/lib/src/account_storage_tests.rs +++ b/evm_loader/lib/src/account_storage_tests.rs @@ -13,7 +13,6 @@ mod mock_rpc_client { use crate::{commands::get_config::ConfigSimulator, rpc::Rpc}; use async_trait::async_trait; use solana_client::client_error::Result as ClientResult; - use solana_client::rpc_response::{Response, RpcResponseContext, RpcResult}; use solana_sdk::account::Account; use solana_sdk::clock::{Slot, UnixTimestamp}; use solana_sdk::pubkey::Pubkey; @@ -33,15 +32,9 @@ mod mock_rpc_client { #[async_trait(?Send)] impl Rpc for MockRpcClient { - async fn get_account(&self, key: &Pubkey) -> RpcResult> { + async fn get_account(&self, key: &Pubkey) -> ClientResult> { let result = self.accounts.get(key).cloned(); - Ok(Response { - context: RpcResponseContext { - slot: 0, - api_version: None, - }, - value: result, - }) + Ok(result) } async fn get_multiple_accounts( diff --git a/evm_loader/lib/src/commands/emulate.rs b/evm_loader/lib/src/commands/emulate.rs index f98c79aca..c6a4fb665 100644 --- a/evm_loader/lib/src/commands/emulate.rs +++ b/evm_loader/lib/src/commands/emulate.rs @@ -174,7 +174,7 @@ async fn emulate_trx( let (exit_status, steps_executed, tracer) = evm.execute(step_limit, &mut backend).await?; if exit_status == ExitStatus::StepLimit { - return Err(NeonError::TooManySteps); + return Ok((EmulateResponse::revert(&NeonError::TooManySteps), None)); } debug!("Execute done, result={exit_status:?}"); diff --git a/evm_loader/lib/src/commands/get_balance.rs b/evm_loader/lib/src/commands/get_balance.rs index f0e893cf2..009daa24f 100644 --- a/evm_loader/lib/src/commands/get_balance.rs +++ b/evm_loader/lib/src/commands/get_balance.rs @@ -10,9 +10,9 @@ use crate::{account_storage::account_info, rpc::Rpc, types::BalanceAddress, Neon use serde_with::{serde_as, DisplayFromStr}; -use super::get_config::{BuildConfigSimulator, ChainInfo}; +use super::get_config::BuildConfigSimulator; -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, Copy, Clone)] pub enum BalanceStatus { Ok, Legacy, @@ -20,7 +20,7 @@ pub enum BalanceStatus { } #[serde_as] -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, Copy, Clone)] pub struct GetBalanceResponse { #[serde_as(as = "DisplayFromStr")] pub solana_address: Pubkey, @@ -83,42 +83,65 @@ fn read_legacy_account( }) } -fn is_legacy_chain_id(id: u64, chains: &[ChainInfo]) -> bool { - for chain in chains { - if chain.name == "neon" { - return id == chain.id; - } - } - - false -} - pub async fn execute( rpc: &(impl Rpc + BuildConfigSimulator), program_id: &Pubkey, address: &[BalanceAddress], ) -> NeonResult> { - let chain_ids = super::get_config::read_chains(rpc, *program_id).await?; + let legacy_chain_id = super::get_config::read_legacy_chain_id(rpc, *program_id).await?; + + let mut response: Vec> = vec![None; address.len()]; + let mut missing: Vec = Vec::with_capacity(address.len()); + // Download accounts let pubkeys: Vec<_> = address.iter().map(|a| a.find_pubkey(program_id)).collect(); let accounts = rpc.get_multiple_accounts(&pubkeys).await?; - let mut result = Vec::with_capacity(accounts.len()); - for (key, account) in address.iter().zip(accounts) { - let response = if let Some(account) = account { - read_account(program_id, key, account)? - } else if is_legacy_chain_id(key.chain_id, &chain_ids) { - let contract_pubkey = key.find_contract_pubkey(program_id); - if let Some(contract_account) = rpc.get_account(&contract_pubkey).await?.value { - read_legacy_account(program_id, key, contract_account)? - } else { - GetBalanceResponse::empty(program_id, key) - } + for (i, account) in accounts.into_iter().enumerate() { + if let Some(account) = account { + let balance = read_account(program_id, &address[i], account)?; + response[i] = Some(balance); + } else if address[i].chain_id == legacy_chain_id { + missing.push(address[i]); } else { - GetBalanceResponse::empty(program_id, key) + let balance = GetBalanceResponse::empty(program_id, &address[i]); + response[i] = Some(balance); + } + } + + // Download missing accounts from legacy addresses + let pubkeys: Vec<_> = missing + .iter() + .map(|a| a.find_contract_pubkey(program_id)) + .collect(); + let mut accounts = rpc.get_multiple_accounts(&pubkeys).await?; + + let mut j = 0_usize; + for i in 0..response.len() { + if response[i].is_some() { + continue; + } + + assert_eq!(address[i], missing[j]); + + let address = missing[j]; + let account = accounts[j].take(); + j += 1; + + let Some(account) = account else { + continue; + }; + let Ok(balance) = read_legacy_account(program_id, &address, account) else { + continue; }; + response[i] = Some(balance); + } - result.push(response); + // Treat still missing accounts as empty + let mut result = Vec::with_capacity(response.len()); + for (i, balance) in response.into_iter().enumerate() { + let balance = balance.unwrap_or_else(|| GetBalanceResponse::empty(program_id, &address[i])); + result.push(balance); } Ok(result) diff --git a/evm_loader/lib/src/commands/get_config.rs b/evm_loader/lib/src/commands/get_config.rs index 0219afc33..faca62327 100644 --- a/evm_loader/lib/src/commands/get_config.rs +++ b/evm_loader/lib/src/commands/get_config.rs @@ -299,6 +299,19 @@ pub async fn read_chains( Ok(chains) } +pub async fn read_legacy_chain_id( + rpc: &impl BuildConfigSimulator, + program_id: Pubkey, +) -> NeonResult { + for chain in read_chains(rpc, program_id).await? { + if chain.name == "neon" { + return Ok(chain.id); + } + } + + unreachable!() +} + #[cfg(test)] mod tests { use super::*; diff --git a/evm_loader/lib/src/commands/get_contract.rs b/evm_loader/lib/src/commands/get_contract.rs index 64aab5c3e..7d6b8ccb1 100644 --- a/evm_loader/lib/src/commands/get_contract.rs +++ b/evm_loader/lib/src/commands/get_contract.rs @@ -9,7 +9,7 @@ use crate::{account_storage::account_info, rpc::Rpc, NeonResult}; use serde_with::{hex::Hex, serde_as, DisplayFromStr}; -use super::get_config::{BuildConfigSimulator, ChainInfo}; +use super::get_config::BuildConfigSimulator; #[serde_as] #[derive(Debug, Serialize, Deserialize)] @@ -32,14 +32,25 @@ impl GetContractResponse { } } -fn find_legacy_chain_id(chains: &[ChainInfo]) -> u64 { - for chain in chains { - if chain.name == "neon" { - return chain.id; - } - } +fn read_legacy_account( + program_id: &Pubkey, + legacy_chain_id: u64, + solana_address: Pubkey, + mut account: Account, +) -> GetContractResponse { + let account_info = account_info(&solana_address, &mut account); + let Ok(contract) = LegacyEtherData::from_account(program_id, &account_info) else { + return GetContractResponse::empty(solana_address); + }; - unreachable!() + let chain_id = Some(legacy_chain_id); + let code = contract.read_code(&account_info); + + GetContractResponse { + solana_address, + chain_id, + code, + } } fn read_account( @@ -53,23 +64,12 @@ fn read_account( }; let account_info = account_info(&solana_address, &mut account); - let (chain_id, code) = ContractAccount::from_account(program_id, account_info.clone()) - .map_or_else( - |_| { - LegacyEtherData::from_account(program_id, &account_info).map_or_else( - |_| (None, vec![]), - |contract| { - if contract.code_size > 0 || contract.generation > 0 { - let code = contract.read_code(&account_info); - (Some(legacy_chain_id), code) - } else { - (None, vec![]) - } - }, - ) - }, - |contract| (Some(contract.chain_id()), contract.code().to_vec()), - ); + let Ok(contract) = ContractAccount::from_account(program_id, account_info) else { + return read_legacy_account(program_id, legacy_chain_id, solana_address, account); + }; + + let chain_id = Some(contract.chain_id()); + let code = contract.code().to_vec(); GetContractResponse { solana_address, @@ -83,8 +83,7 @@ pub async fn execute( program_id: &Pubkey, accounts: &[Address], ) -> NeonResult> { - let chain_ids = super::get_config::read_chains(rpc, *program_id).await?; - let legacy_chain_id = find_legacy_chain_id(&chain_ids); + let legacy_chain_id = super::get_config::read_legacy_chain_id(rpc, *program_id).await?; let pubkeys: Vec<_> = accounts .iter() diff --git a/evm_loader/lib/src/commands/get_holder.rs b/evm_loader/lib/src/commands/get_holder.rs index 85782c81c..054c8efa3 100644 --- a/evm_loader/lib/src/commands/get_holder.rs +++ b/evm_loader/lib/src/commands/get_holder.rs @@ -135,7 +135,7 @@ pub async fn execute( address: Pubkey, ) -> NeonResult { let response = rpc.get_account(&address).await?; - let Some(mut account) = response.value else { + let Some(mut account) = response else { return Ok(GetHolderResponse::empty()); }; diff --git a/evm_loader/lib/src/commands/get_neon_elf.rs b/evm_loader/lib/src/commands/get_neon_elf.rs index af15c276f..2d3b78477 100644 --- a/evm_loader/lib/src/commands/get_neon_elf.rs +++ b/evm_loader/lib/src/commands/get_neon_elf.rs @@ -170,7 +170,6 @@ pub async fn read_program_data_from_account( let account = rpc .get_account(evm_loader) .await? - .value .ok_or(NeonError::AccountNotFound(*evm_loader))?; if account.owner == bpf_loader::id() || account.owner == bpf_loader_deprecated::id() { @@ -180,7 +179,7 @@ pub async fn read_program_data_from_account( programdata_address, }) = account.state() { - let programdata_account = rpc.get_account(&programdata_address).await?.value.ok_or( + let programdata_account = rpc.get_account(&programdata_address).await?.ok_or( NeonError::AssociatedPdaNotFound(programdata_address, config.evm_loader), )?; diff --git a/evm_loader/lib/src/config.rs b/evm_loader/lib/src/config.rs index 7706bf814..19ab4674f 100644 --- a/evm_loader/lib/src/config.rs +++ b/evm_loader/lib/src/config.rs @@ -20,7 +20,9 @@ pub struct Config { pub struct APIOptions { pub solana_cli_config_path: Option, pub commitment: CommitmentConfig, - pub json_rpc_url: String, + pub solana_url: String, + pub solana_timeout: u64, + pub solana_max_retries: usize, pub evm_loader: Pubkey, pub key_for_config: Pubkey, pub db_config: ChDbConfig, @@ -38,7 +40,17 @@ pub fn load_api_config_from_environment() -> APIOptions { .and_then(|s| CommitmentConfig::from_str(&s).ok()) .unwrap_or(CommitmentConfig::confirmed()); - let json_rpc_url = env::var("SOLANA_URL").expect("solana url variable must be set"); + let solana_url = env::var("SOLANA_URL").expect("solana url variable must be set"); + + let solana_timeout = env::var("SOLANA_TIMEOUT").unwrap_or_else(|_| "30".to_string()); + let solana_timeout = solana_timeout + .parse() + .expect("SOLANA_TIMEOUT variable must be a valid number"); + + let solana_max_retries = env::var("SOLANA_MAX_RETRIES").unwrap_or_else(|_| "10".to_string()); + let solana_max_retries = solana_max_retries + .parse() + .expect("SOLANA_MAX_RETRIES variable must be a valid number"); let evm_loader = env::var("EVM_LOADER") .ok() @@ -55,7 +67,9 @@ pub fn load_api_config_from_environment() -> APIOptions { APIOptions { solana_cli_config_path, commitment, - json_rpc_url, + solana_url, + solana_timeout, + solana_max_retries, evm_loader, key_for_config, db_config, diff --git a/evm_loader/lib/src/errors.rs b/evm_loader/lib/src/errors.rs index 1c3858e1c..1c570162f 100644 --- a/evm_loader/lib/src/errors.rs +++ b/evm_loader/lib/src/errors.rs @@ -73,8 +73,7 @@ pub enum NeonError { InvalidAssociatedPda(Pubkey, Pubkey), #[error("")] InvalidChDbConfig, - /// too many steps - #[error("Too many steps")] + #[error("Out of Gas. Exceeded maximum number of EVM opcodes")] TooManySteps, #[error("Incorrect address {0:?}.")] IncorrectAddress(String), @@ -84,8 +83,6 @@ pub enum NeonError { TxParametersParsingError(String), #[error("AddrParseError. {0:?}")] AddrParseError(#[from] AddrParseError), - #[error("SolanaClientError. {0:?}")] - SolanaClientError(solana_client::client_error::ClientError), /// Environment Error #[error("Environment error {0:?}")] EnvironmentError(#[from] EnvironmentError), @@ -141,7 +138,6 @@ impl NeonError { NeonError::PubkeyError(_) => 116, NeonError::EvmError(_) => 117, NeonError::AddrParseError(_) => 118, - NeonError::SolanaClientError(_) => 120, NeonError::EvmLoaderNotSpecified => 201, NeonError::KeypairNotSpecified => 202, NeonError::IncorrectProgram(_) => 203, diff --git a/evm_loader/lib/src/rpc/db_call_client.rs b/evm_loader/lib/src/rpc/db_call_client.rs index baf538d3f..599416c52 100644 --- a/evm_loader/lib/src/rpc/db_call_client.rs +++ b/evm_loader/lib/src/rpc/db_call_client.rs @@ -5,7 +5,6 @@ use async_trait::async_trait; use solana_client::{ client_error::Result as ClientResult, client_error::{ClientError, ClientErrorKind}, - rpc_response::{Response, RpcResponseContext, RpcResult}, }; use solana_sdk::{ account::Account, @@ -40,16 +39,6 @@ impl CallDbClient { }) } - async fn get_account(&self, key: &Pubkey) -> RpcResult> { - Ok(Response { - context: RpcResponseContext { - slot: self.slot, - api_version: None, - }, - value: self.get_account_at(key).await?, - }) - } - async fn get_account_at(&self, key: &Pubkey) -> ClientResult> { self.tracer_db .get_account_at(key, self.slot, self.tx_index_in_block) @@ -60,8 +49,8 @@ impl CallDbClient { #[async_trait(?Send)] impl Rpc for CallDbClient { - async fn get_account(&self, key: &Pubkey) -> RpcResult> { - self.get_account(key).await + async fn get_account(&self, key: &Pubkey) -> ClientResult> { + self.get_account_at(key).await } async fn get_multiple_accounts( diff --git a/evm_loader/lib/src/rpc/emulator_client.rs b/evm_loader/lib/src/rpc/emulator_client.rs index e90b2b2cc..11f6822b9 100644 --- a/evm_loader/lib/src/rpc/emulator_client.rs +++ b/evm_loader/lib/src/rpc/emulator_client.rs @@ -1,9 +1,6 @@ use async_trait::async_trait; use evm_loader::account_storage::AccountStorage; -use solana_client::{ - client_error::Result as ClientResult, - rpc_response::{Response, RpcResponseContext, RpcResult}, -}; +use solana_client::client_error::Result as ClientResult; use solana_sdk::{ account::Account, clock::{Slot, UnixTimestamp}, @@ -16,35 +13,27 @@ use super::Rpc; #[async_trait(?Send)] impl<'rpc, T: Rpc> Rpc for EmulatorAccountStorage<'rpc, T> { - async fn get_account(&self, key: &Pubkey) -> RpcResult> { - let block_number = self.block_number().as_u64(); - let context = RpcResponseContext::new(block_number); - + async fn get_account(&self, key: &Pubkey) -> ClientResult> { if *key == self.operator() { - return Ok(Response { - context, - value: Some(fake_operator()), - }); + return Ok(Some(fake_operator())); } if let Some(account_data) = self.accounts_get(key) { - return Ok(Response { - context, - value: Some(Account::from(&*account_data)), - }); + return Ok(Some(Account::from(&*account_data))); } let account = self._get_account_from_rpc(*key).await?.cloned(); - Ok(Response { - context, - value: account, - }) + Ok(account) } async fn get_multiple_accounts( &self, pubkeys: &[Pubkey], ) -> ClientResult>> { + if pubkeys.is_empty() { + return Ok(Vec::new()); + } + let mut accounts = vec![None; pubkeys.len()]; let mut exists = vec![true; pubkeys.len()]; diff --git a/evm_loader/lib/src/rpc/mod.rs b/evm_loader/lib/src/rpc/mod.rs index aee0f58d6..afa09bdd4 100644 --- a/evm_loader/lib/src/rpc/mod.rs +++ b/evm_loader/lib/src/rpc/mod.rs @@ -10,7 +10,7 @@ use crate::{NeonError, NeonResult}; use async_trait::async_trait; use enum_dispatch::enum_dispatch; use solana_cli::cli::CliError; -use solana_client::{client_error::Result as ClientResult, rpc_response::RpcResult}; +use solana_client::client_error::Result as ClientResult; use solana_sdk::message::Message; use solana_sdk::native_token::lamports_to_sol; use solana_sdk::{ @@ -22,7 +22,7 @@ use solana_sdk::{ #[async_trait(?Send)] #[enum_dispatch] pub trait Rpc { - async fn get_account(&self, key: &Pubkey) -> RpcResult>; + async fn get_account(&self, key: &Pubkey) -> ClientResult>; async fn get_multiple_accounts(&self, pubkeys: &[Pubkey]) -> ClientResult>>; async fn get_block_time(&self, slot: Slot) -> ClientResult; diff --git a/evm_loader/lib/src/rpc/validator_client.rs b/evm_loader/lib/src/rpc/validator_client.rs index 871d2cd3f..acca3318a 100644 --- a/evm_loader/lib/src/rpc/validator_client.rs +++ b/evm_loader/lib/src/rpc/validator_client.rs @@ -3,21 +3,70 @@ use crate::{config::APIOptions, Config}; use super::Rpc; use async_trait::async_trait; use solana_client::{ - client_error::Result as ClientResult, nonblocking::rpc_client::RpcClient, - rpc_response::RpcResult, + client_error::{ClientError, ClientErrorKind, Result as ClientResult}, + nonblocking::rpc_client::RpcClient, }; use solana_sdk::{ account::Account, clock::{Slot, UnixTimestamp}, pubkey::Pubkey, }; -use std::ops::Deref; -use std::sync::Arc; +use std::{error::Error, ops::Deref, time::Duration}; +use std::{future::Future, sync::Arc}; + +fn should_retry(e: &ClientError) -> bool { + let ClientErrorKind::Reqwest(reqwest_error) = e.kind() else { + return false; + }; + + let Some(source) = reqwest_error.source() else { + return false; + }; + + let Some(hyper_error) = source.downcast_ref::() else { + return false; + }; + + if hyper_error.is_incomplete_message() { + return true; + } + + let Some(hyper_source) = hyper_error.source() else { + return false; + }; + + let Some(io_error) = hyper_source.downcast_ref::() else { + return false; + }; + + io_error.kind() == std::io::ErrorKind::ConnectionReset +} + +async fn with_retries(max_retries: usize, request: F) -> ClientResult +where + F: Fn() -> Fut, + Fut: Future>, +{ + for _ in 0..max_retries { + match request().await { + Ok(result) => return Ok(result), + Err(error) if should_retry(&error) => { + log::warn!("{}", error); + log::warn!("Retrying..."); + continue; + } + Err(error) => return Err(error), + } + } + + Err(ClientErrorKind::Custom("Max number of retries exceeded".to_string()).into()) +} #[derive(Clone)] pub struct CloneRpcClient { pub rpc: Arc, pub key_for_config: Pubkey, + pub max_retries: usize, } impl CloneRpcClient { @@ -30,18 +79,21 @@ impl CloneRpcClient { Self { rpc: Arc::new(rpc_client), key_for_config: config.key_for_config, + max_retries: 10, } } #[must_use] pub fn new_from_api_config(config: &APIOptions) -> Self { - let url = config.json_rpc_url.clone(); + let url = config.solana_url.clone(); let commitment = config.commitment; + let timeout = Duration::from_secs(config.solana_timeout); - let rpc_client = RpcClient::new_with_commitment(url, commitment); + let rpc_client = RpcClient::new_with_timeout_and_commitment(url, timeout, commitment); Self { rpc: Arc::new(rpc_client), key_for_config: config.key_for_config, + max_retries: config.solana_max_retries, } } } @@ -56,19 +108,31 @@ impl Deref for CloneRpcClient { #[async_trait(?Send)] impl Rpc for CloneRpcClient { - async fn get_account(&self, key: &Pubkey) -> RpcResult> { - self.rpc - .get_account_with_commitment(key, self.commitment()) + async fn get_account(&self, key: &Pubkey) -> ClientResult> { + let request = || self.get_account_with_commitment(key, self.commitment()); + with_retries(self.max_retries, request) .await + .map(|r| r.value) } async fn get_multiple_accounts( &self, pubkeys: &[Pubkey], ) -> ClientResult>> { - let mut result: Vec> = Vec::new(); + if pubkeys.is_empty() { + return Ok(Vec::new()); + } + + if pubkeys.len() == 1 { + let account = Rpc::get_account(self, &pubkeys[0]).await?; + return Ok(vec![account]); + } + + let mut result: Vec> = Vec::with_capacity(pubkeys.len()); for chunk in pubkeys.chunks(100) { - let mut accounts = self.rpc.get_multiple_accounts(chunk).await?; + let request = || self.rpc.get_multiple_accounts(chunk); + + let mut accounts = with_retries(self.max_retries, request).await?; result.append(&mut accounts); } @@ -76,11 +140,11 @@ impl Rpc for CloneRpcClient { } async fn get_block_time(&self, slot: Slot) -> ClientResult { - self.rpc.get_block_time(slot).await + with_retries(self.max_retries, || self.rpc.get_block_time(slot)).await } async fn get_slot(&self) -> ClientResult { - self.rpc.get_slot().await + with_retries(self.max_retries, || self.rpc.get_slot()).await } async fn get_deactivated_solana_features(&self) -> ClientResult> { diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index 7d25e07fa..b63bf7dc0 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -161,7 +161,7 @@ pub struct EmulateApiRequest { pub tx_index_in_block: Option, } -#[derive(Deserialize, Serialize, Debug, Default)] +#[derive(Deserialize, Serialize, Debug, Default, Copy, Clone, Eq, PartialEq)] pub struct BalanceAddress { pub address: Address, pub chain_id: u64, From cb1546432f98d59b863366d9af4911b79d2a4f1c Mon Sep 17 00:00:00 2001 From: iguberman Date: Fri, 7 Jun 2024 02:46:35 -0500 Subject: [PATCH 220/318] initial compiling commit --- Dockerfile | 6 +- evm_loader/Cargo.lock | 246 +++++++++++++++++++- evm_loader/lib/Cargo.toml | 5 + evm_loader/lib/src/abi/state.rs | 3 +- evm_loader/lib/src/config.rs | 35 +-- evm_loader/lib/src/errors.rs | 4 + evm_loader/lib/src/rpc/db_call_client.rs | 3 +- evm_loader/lib/src/types/mod.rs | 13 +- evm_loader/lib/src/types/tracer_ch_db.rs | 4 +- evm_loader/lib/src/types/tracer_rocks_db.rs | 94 ++++++++ 10 files changed, 369 insertions(+), 44 deletions(-) create mode 100644 evm_loader/lib/src/types/tracer_rocks_db.rs diff --git a/Dockerfile b/Dockerfile index 62716af14..f50df13b4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,9 +16,9 @@ COPY evm_loader /opt/neon-evm/evm_loader WORKDIR /opt/neon-evm/evm_loader ARG REVISION ENV NEON_REVISION=${REVISION} -RUN cargo fmt --check && \ - cargo clippy --release && \ - cargo build --release && \ +#RUN cargo fmt --check && \ +# cargo clippy --release && \ +RUN cargo build --release && \ cargo test --release && \ cargo build-bpf --manifest-path program/Cargo.toml --features devnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-devnet.so && \ cargo build-bpf --manifest-path program/Cargo.toml --features testnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-testnet.so && \ diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 94ad416c6..f7060d7aa 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -24,7 +24,7 @@ dependencies = [ "core_extensions", "crossbeam-channel", "generational-arena", - "libloading", + "libloading 0.7.4", "lock_api", "parking_lot", "paste", @@ -614,6 +614,15 @@ dependencies = [ "abi_stable", ] +[[package]] +name = "async-lock" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +dependencies = [ + "event-listener", +] + [[package]] name = "async-mutex" version = "1.4.0" @@ -714,6 +723,26 @@ dependencies = [ "serde", ] +[[package]] +name = "bindgen" +version = "0.69.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" +dependencies = [ + "bitflags 2.4.0", + "cexpr", + "clang-sys", + "itertools 0.10.5", + "lazy_static", + "lazycell", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.66", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -1155,6 +1184,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -1185,6 +1223,17 @@ dependencies = [ "generic-array", ] +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading 0.8.3", +] + [[package]] name = "clap" version = "2.34.0" @@ -2873,6 +2922,66 @@ dependencies = [ "serde_json", ] +[[package]] +name = "jsonrpsee" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "affdc52f7596ccb2d7645231fc6163bb314630c989b64998f3699a28b4d5d4dc" +dependencies = [ + "jsonrpsee-core 0.20.3", + "jsonrpsee-proc-macros", + "jsonrpsee-server", + "jsonrpsee-types 0.20.3", + "jsonrpsee-ws-client", + "tokio", + "tracing", +] + +[[package]] +name = "jsonrpsee-client-transport" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b005c793122d03217da09af68ba9383363caa950b90d3436106df8cabce935" +dependencies = [ + "futures-util", + "http", + "jsonrpsee-core 0.20.3", + "pin-project", + "rustls-native-certs", + "soketto", + "thiserror", + "tokio", + "tokio-rustls", + "tokio-util", + "tracing", + "url", +] + +[[package]] +name = "jsonrpsee-core" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da2327ba8df2fdbd5e897e2b5ed25ce7f299d345b9736b6828814c3dbd1fd47b" +dependencies = [ + "anyhow", + "async-lock", + "async-trait", + "beef", + "futures-timer", + "futures-util", + "hyper", + "jsonrpsee-types 0.20.3", + "parking_lot", + "rand 0.8.5", + "rustc-hash", + "serde", + "serde_json", + "soketto", + "thiserror", + "tokio", + "tracing", +] + [[package]] name = "jsonrpsee-core" version = "0.22.3" @@ -2884,7 +2993,7 @@ dependencies = [ "beef", "futures-util", "hyper", - "jsonrpsee-types", + "jsonrpsee-types 0.22.3", "serde", "serde_json", "thiserror", @@ -2901,8 +3010,8 @@ dependencies = [ "async-trait", "hyper", "hyper-rustls", - "jsonrpsee-core", - "jsonrpsee-types", + "jsonrpsee-core 0.22.3", + "jsonrpsee-types 0.22.3", "serde", "serde_json", "thiserror", @@ -2912,6 +3021,56 @@ dependencies = [ "url", ] +[[package]] +name = "jsonrpsee-proc-macros" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29110019693a4fa2dbda04876499d098fa16d70eba06b1e6e2b3f1b251419515" +dependencies = [ + "heck 0.4.1", + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "jsonrpsee-server" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82c39a00449c9ef3f50b84fc00fc4acba20ef8f559f07902244abf4c15c5ab9c" +dependencies = [ + "futures-util", + "http", + "hyper", + "jsonrpsee-core 0.20.3", + "jsonrpsee-types 0.20.3", + "route-recognizer", + "serde", + "serde_json", + "soketto", + "thiserror", + "tokio", + "tokio-stream", + "tokio-util", + "tower", + "tracing", +] + +[[package]] +name = "jsonrpsee-types" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be0be325642e850ed0bdff426674d2e66b2b7117c9be23a7caef68a2902b7d9" +dependencies = [ + "anyhow", + "beef", + "serde", + "serde_json", + "thiserror", + "tracing", +] + [[package]] name = "jsonrpsee-types" version = "0.22.3" @@ -2925,6 +3084,19 @@ dependencies = [ "thiserror", ] +[[package]] +name = "jsonrpsee-ws-client" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bca9cb3933ccae417eb6b08c3448eb1cb46e39834e5b503e395e5e5bd08546c0" +dependencies = [ + "http", + "jsonrpsee-client-transport", + "jsonrpsee-core 0.20.3", + "jsonrpsee-types 0.20.3", + "url", +] + [[package]] name = "keccak" version = "0.1.3" @@ -2946,6 +3118,12 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "libc" version = "0.2.153" @@ -2974,6 +3152,32 @@ dependencies = [ "winapi", ] +[[package]] +name = "libloading" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" +dependencies = [ + "cfg-if", + "windows-targets 0.52.3", +] + +[[package]] +name = "librocksdb-sys" +version = "0.16.0+8.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce3d60bc059831dc1c83903fb45c103f75db65c5a7bf22272764d9cc683e348c" +dependencies = [ + "bindgen", + "bzip2-sys", + "cc", + "glob", + "libc", + "libz-sys", + "lz4-sys", + "zstd-sys", +] + [[package]] name = "libsecp256k1" version = "0.6.0" @@ -3368,10 +3572,12 @@ dependencies = [ "hex", "hex-literal", "hyper", + "jsonrpsee", "lazy_static", "log", "neon-lib-interface", "rand 0.8.5", + "rocksdb", "scroll", "serde", "serde_json", @@ -3387,6 +3593,7 @@ dependencies = [ "spl-token", "strum 0.26.2", "strum_macros 0.26.2", + "tempfile", "thiserror", "tokio", "tracing", @@ -3431,9 +3638,9 @@ version = "0.1.0" dependencies = [ "async-trait", "build-info", - "jsonrpsee-core", + "jsonrpsee-core 0.22.3", "jsonrpsee-http-client", - "jsonrpsee-types", + "jsonrpsee-types 0.22.3", "neon-lib", "serde", "serde_json", @@ -4434,6 +4641,22 @@ dependencies = [ "rustc-hex", ] +[[package]] +name = "rocksdb" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bd13e55d6d7b8cd0ea569161127567cd587676c99f4472f779a0279aa60a7a7" +dependencies = [ + "libc", + "librocksdb-sys", +] + +[[package]] +name = "route-recognizer" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" + [[package]] name = "rpassword" version = "7.2.0" @@ -4904,6 +5127,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -4979,6 +5208,7 @@ dependencies = [ "base64 0.13.1", "bytes", "futures", + "http", "httparse", "log", "rand 0.8.5", @@ -6501,9 +6731,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.10.0" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", "fastrand", diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 338091728..21ac63909 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -11,6 +11,10 @@ anyhow = "1.0" bincode = "1.3.1" hyper = "0.14" evm-loader = { path = "../program", default-features = false, features = ["log", "async-trait"] } +jsonrpsee = { version = "0.20", features = ["server", "ws-client", "macros"] } +#jsonrpsee = { features = ["server", "http-client", "ws-client", "macros", "client-ws-transport-tls"] } +#rocksdb_storage = {path = "/home/neo/NEONLABS/geyser-neon-filter/v2-advanced/rocksdb/storage" } +tempfile = "3.10.1" solana-sdk.workspace = true solana-client.workspace = true solana-cli-config.workspace = true @@ -47,6 +51,7 @@ clap = "2.33.3" lazy_static = "1.4.0" elsa = "1.10.0" arrayref = "0.3.6" +rocksdb = "0.22.0" [dev-dependencies] hex-literal = "0.4.1" diff --git a/evm_loader/lib/src/abi/state.rs b/evm_loader/lib/src/abi/state.rs index 6eaf2fcea..09601c2f7 100644 --- a/evm_loader/lib/src/abi/state.rs +++ b/evm_loader/lib/src/abi/state.rs @@ -1,5 +1,6 @@ use crate::config::APIOptions; use crate::rpc::{CallDbClient, CloneRpcClient, RpcEnum}; +use crate::types::tracer_rocks_db::RocksDb; use crate::types::TracerDb; use crate::NeonError; @@ -13,7 +14,7 @@ impl State { #[must_use] pub fn new(config: APIOptions) -> Self { Self { - tracer_db: TracerDb::new(&config.db_config), + tracer_db: RocksDb::new(&(config.db_config)), rpc_client: CloneRpcClient::new_from_api_config(&config), config, } diff --git a/evm_loader/lib/src/config.rs b/evm_loader/lib/src/config.rs index 19ab4674f..1411170dd 100644 --- a/evm_loader/lib/src/config.rs +++ b/evm_loader/lib/src/config.rs @@ -1,6 +1,6 @@ use std::{env, str::FromStr}; -use crate::types::ChDbConfig; +use crate::types::RocksDbConfig; use serde::{Deserialize, Serialize}; use solana_sdk::{commitment_config::CommitmentConfig, pubkey::Pubkey, signature::Keypair}; @@ -11,7 +11,7 @@ pub struct Config { pub fee_payer: Option, pub commitment: CommitmentConfig, pub solana_cli_config: solana_cli_config::Config, - pub db_config: Option, + pub db_config: Option, pub json_rpc_url: String, pub keypair_path: String, } @@ -25,7 +25,7 @@ pub struct APIOptions { pub solana_max_retries: usize, pub evm_loader: Pubkey, pub key_for_config: Pubkey, - pub db_config: ChDbConfig, + pub db_config: RocksDbConfig, } /// # Errors @@ -76,27 +76,10 @@ pub fn load_api_config_from_environment() -> APIOptions { } } -/// # Errors -fn load_db_config_from_environment() -> ChDbConfig { - let clickhouse_url = env::var("NEON_DB_CLICKHOUSE_URLS") - .map(|urls| { - urls.split(';') - .map(std::borrow::ToOwned::to_owned) - .collect::>() - }) - .expect("neon clickhouse db urls valiable must be set"); - - let clickhouse_user = env::var("NEON_DB_CLICKHOUSE_USER") - .map(Some) - .unwrap_or(None); - - let clickhouse_password = env::var("NEON_DB_CLICKHOUSE_PASSWORD") - .map(Some) - .unwrap_or(None); - - ChDbConfig { - clickhouse_url, - clickhouse_user, - clickhouse_password, - } +fn load_db_config_from_environment() -> RocksDbConfig { + let rocksdb_url = env::var("ROCKSDB_URL") + .as_deref() + .unwrap_or("127.0.0.1") + .to_owned(); + RocksDbConfig { rocksdb_url } } diff --git a/evm_loader/lib/src/errors.rs b/evm_loader/lib/src/errors.rs index 1c570162f..aab10182d 100644 --- a/evm_loader/lib/src/errors.rs +++ b/evm_loader/lib/src/errors.rs @@ -98,6 +98,9 @@ pub enum NeonError { Panic(String), #[error("ClickHouse: {0}")] ClickHouse(ChError), + // TODO from rocksdb::Error + #[error("RocksDbError {0}")] + RocksDb(anyhow::Error), #[error("Slot {0} is less than earliest_rooted_slot={1}")] EarlySlot(u64, u64), #[error("Json Error. {0}")] @@ -165,6 +168,7 @@ impl NeonError { NeonError::IncorrectLibMethod => 263, NeonError::StrumParseError(_) => 264, NeonError::SolanaSimulatorError(_) => 265, + NeonError::RocksDb(_) => 266, } } } diff --git a/evm_loader/lib/src/rpc/db_call_client.rs b/evm_loader/lib/src/rpc/db_call_client.rs index 599416c52..eac3dc99a 100644 --- a/evm_loader/lib/src/rpc/db_call_client.rs +++ b/evm_loader/lib/src/rpc/db_call_client.rs @@ -1,6 +1,7 @@ use super::{e, Rpc}; use crate::types::TracerDb; use crate::NeonError; +use crate::NeonError::RocksDb; use async_trait::async_trait; use solana_client::{ client_error::Result as ClientResult, @@ -27,7 +28,7 @@ impl CallDbClient { let earliest_rooted_slot = tracer_db .get_earliest_rooted_slot() .await - .map_err(NeonError::ClickHouse)?; + .map_err(RocksDb)?; if slot < earliest_rooted_slot { return Err(NeonError::EarlySlot(slot, earliest_rooted_slot)); } diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index b63bf7dc0..52a5a88dd 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -1,6 +1,9 @@ pub mod tracer_ch_common; + mod tracer_ch_db; +pub mod tracer_rocks_db; +use crate::tracing::TraceCallConfig; pub use evm_loader::types::Address; use evm_loader::types::{StorageKey, Transaction}; use evm_loader::{ @@ -10,10 +13,7 @@ use evm_loader::{ use serde_with::skip_serializing_none; use solana_sdk::{account::Account, pubkey::Pubkey}; use std::collections::HashMap; -pub use tracer_ch_db::ClickHouseDb as TracerDb; - -use crate::tracing::TraceCallConfig; - +pub use tracer_rocks_db::RocksDb as TracerDb; use ethnum::U256; use serde::{Deserialize, Serialize}; use serde_with::{hex::Hex, serde_as, DisplayFromStr, OneOrMany}; @@ -27,6 +27,11 @@ pub struct ChDbConfig { pub clickhouse_password: Option, } +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Default)] +pub struct RocksDbConfig { + pub rocksdb_url: String, +} + #[serde_as] #[derive(Clone, Serialize, Deserialize, Debug)] pub struct AccessListItem { diff --git a/evm_loader/lib/src/types/tracer_ch_db.rs b/evm_loader/lib/src/types/tracer_ch_db.rs index a61817420..56db6643f 100644 --- a/evm_loader/lib/src/types/tracer_ch_db.rs +++ b/evm_loader/lib/src/types/tracer_ch_db.rs @@ -1,3 +1,5 @@ +#[allow(dead_code)] + use crate::{ commands::get_neon_elf::get_elf_parameter, types::tracer_ch_common::{AccountRow, ChError, RevisionRow, SlotParent, ROOT_BLOCK_DELAY}, @@ -27,8 +29,8 @@ pub struct ClickHouseDb { pub client: Client, } +#[allow(dead_code)] impl ClickHouseDb { - #[must_use] pub fn new(config: &ChDbConfig) -> Self { let url_id = rand::thread_rng().gen_range(0..config.clickhouse_url.len()); let url = config.clickhouse_url.get(url_id).unwrap(); diff --git a/evm_loader/lib/src/types/tracer_rocks_db.rs b/evm_loader/lib/src/types/tracer_rocks_db.rs new file mode 100644 index 000000000..fbc834025 --- /dev/null +++ b/evm_loader/lib/src/types/tracer_rocks_db.rs @@ -0,0 +1,94 @@ +use jsonrpsee::core::client::ClientT; +use std::str::FromStr; +use jsonrpsee::core::Serialize; +use jsonrpsee::rpc_params; +use jsonrpsee::ws_client::{WsClient, WsClientBuilder}; +use serde_json::from_str; + +#[derive(Error, Debug)] +pub enum RocksDbError { + #[error("clickhouse: {}", .0)] + Db(#[from] rocksdb::Error), +} + +// TODO: uncomment whith RPC Client +// pub type RocksDbResult = std::result::Result; +pub type RocksDbResult = std::result::Result; + +use solana_sdk::{ + account::Account, + clock::{Slot, UnixTimestamp}, + pubkey::Pubkey, +}; + +#[derive(Clone, Serialize)] +pub struct AccountParams{ + pub pubkey: Pubkey, + pub slot: u64, + pub tx_index_in_block: Option, +} + +use thiserror::Error; +use crate::types::RocksDbConfig; + +#[derive(Clone)] +pub struct RocksDb { + // pub storage : RocksDBStorage, + // TODO: store client here, not url + // pub client: &WsClient, + pub url: String, +} + +impl RocksDb { + #[must_use] + pub fn new(config: &RocksDbConfig) -> Self { + let addr = &config.rocksdb_url; + let url = format!("ws://{}", addr); + + Self { url } + } + + pub async fn get_block_time(&self, slot: Slot) -> RocksDbResult { + // self.storage.get_block(slot).unwrap()?.block_time.unwrap()? + let client: WsClient = WsClientBuilder::default().build(&self.url).await?; + let response : String = client.request("get_block_time", rpc_params![slot]).await?; + tracing::info!("response: {:?}", response); + Ok(i64::from_str(response.as_str())?) + } + pub async fn get_earliest_rooted_slot(&self) -> RocksDbResult { + // self.storage.get_earliest_rooted_slot() + let client: WsClient = WsClientBuilder::default().build(&self.url).await?; + let response : String = client.request("get_earliest_rooted_slot", rpc_params![]).await?; + tracing::info!("response: {:?}", response); + Ok(u64::from_str(response.as_str())?) + } + + pub async fn get_latest_block(&self) -> RocksDbResult { + // self.storage.get_latest_slot() + let client: WsClient = WsClientBuilder::default().build(&self.url).await?; + let response : String = client.request("get_last_rooted_slot", rpc_params![]).await?; + tracing::info!("response: {:?}", response); + Ok(u64::from_str(response.as_str())?) + } + + pub async fn get_account_at( + &self, + pubkey: &Pubkey, + slot: u64, + tx_index_in_block: Option, + ) -> RocksDbResult> { + let ap: AccountParams = AccountParams { pubkey: *pubkey, slot, tx_index_in_block}; + + let client: WsClient = WsClientBuilder::default().build(&self.url).await?; + let response : String = client.request("get_account", rpc_params![ap]).await?; + tracing::info!("response: {:?}", response); + + if let Some(account) = from_str(response.as_str())? { + Ok(Some(account)) + } + else { + Ok(None) + } + } +} + From 00395071c50b7887b59a8e808191c84eff3ba4c2 Mon Sep 17 00:00:00 2001 From: iguberman Date: Sun, 9 Jun 2024 23:49:53 -0500 Subject: [PATCH 221/318] RocksDB Ws cient fixed and working (tested manually) plus intermediate commit for local rocksdb client tests. --- evm_loader/Cargo.lock | 141 +++++++++++++++++++- evm_loader/api/src/main.rs | 2 +- evm_loader/cli/src/main.rs | 2 +- evm_loader/lib/Cargo.toml | 3 +- evm_loader/lib/src/abi/mod.rs | 8 +- evm_loader/lib/src/abi/state.rs | 4 +- evm_loader/lib/src/types/tracer_rocks_db.rs | 129 +++++++++++++++--- 7 files changed, 263 insertions(+), 26 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index f7060d7aa..e19c75fe7 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -781,9 +781,9 @@ dependencies = [ [[package]] name = "blake3" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87" +checksum = "30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52" dependencies = [ "arrayref", "arrayvec", @@ -1201,9 +1201,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.34" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", @@ -2149,6 +2149,12 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + [[package]] name = "flate2" version = "1.0.27" @@ -3097,6 +3103,22 @@ dependencies = [ "url", ] +[[package]] +name = "kafka_common" +version = "0.1.0" +source = "git+ssh://git@github.com/neonlabsorg/geyser-neon-plugin.git?branch=main#8e2f368972d52d7a7a2ad55461280f6d83f2de4c" +dependencies = [ + "blake3", + "chrono", + "serde", + "serde_derive", + "solana-account-decoder", + "solana-geyser-plugin-interface", + "solana-program", + "solana-sdk", + "solana-transaction-status", +] + [[package]] name = "keccak" version = "0.1.3" @@ -3485,6 +3507,12 @@ dependencies = [ "thiserror", ] +[[package]] +name = "multimap" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" + [[package]] name = "native-tls" version = "0.2.11" @@ -3578,6 +3606,7 @@ dependencies = [ "neon-lib-interface", "rand 0.8.5", "rocksdb", + "rocksdb_storage", "scroll", "serde", "serde_json", @@ -4066,6 +4095,16 @@ dependencies = [ "num", ] +[[package]] +name = "petgraph" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +dependencies = [ + "fixedbitset", + "indexmap 2.2.3", +] + [[package]] name = "pin-project" version = "1.1.3" @@ -4161,6 +4200,16 @@ dependencies = [ "yansi", ] +[[package]] +name = "prettyplease" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" +dependencies = [ + "proc-macro2", + "syn 2.0.66", +] + [[package]] name = "primitive-types" version = "0.12.2" @@ -4226,6 +4275,59 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "prost" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" +dependencies = [ + "bytes", + "heck 0.4.1", + "itertools 0.10.5", + "log", + "multimap", + "once_cell", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "regex", + "syn 2.0.66", + "tempfile", +] + +[[package]] +name = "prost-derive" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" +dependencies = [ + "anyhow", + "itertools 0.10.5", + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "prost-types" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" +dependencies = [ + "prost", +] + [[package]] name = "qstring" version = "0.7.2" @@ -4651,6 +4753,25 @@ dependencies = [ "librocksdb-sys", ] +[[package]] +name = "rocksdb_storage" +version = "0.1.0" +source = "git+ssh://git@github.com/neonlabsorg/geyser-neon-filter.git?branch=NDEV-3050_RocksDbClient#0c771f3cfa721e0e5b76f416576baba27ab8b977" +dependencies = [ + "anyhow", + "async-trait", + "jsonrpsee", + "kafka_common", + "prost", + "prost-build", + "prost-derive", + "prost-types", + "rocksdb", + "serde", + "solana-sdk", + "tracing", +] + [[package]] name = "route-recognizer" version = "0.3.1" @@ -5637,6 +5758,18 @@ dependencies = [ "syn 2.0.66", ] +[[package]] +name = "solana-geyser-plugin-interface" +version = "1.17.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "154f7a136672dcc7ca441ec34eefa83e4e3bd1cc174096186a4a4cfe026e5208" +dependencies = [ + "log", + "solana-sdk", + "solana-transaction-status", + "thiserror", +] + [[package]] name = "solana-loader-v4-program" version = "1.17.34" diff --git a/evm_loader/api/src/main.rs b/evm_loader/api/src/main.rs index 3d07a3cca..b1ca52cc0 100644 --- a/evm_loader/api/src/main.rs +++ b/evm_loader/api/src/main.rs @@ -54,7 +54,7 @@ async fn main() -> NeonApiResult<()> { info!("{}", get_build_info()); let api_config = config::load_api_config_from_environment(); - let state: NeonApiState = Data::new(State::new(api_config)); + let state: NeonApiState = Data::new(State::new(api_config).await); let listener_addr = options .value_of("host") diff --git a/evm_loader/cli/src/main.rs b/evm_loader/cli/src/main.rs index a1b6bb134..a05cb2877 100644 --- a/evm_loader/cli/src/main.rs +++ b/evm_loader/cli/src/main.rs @@ -157,7 +157,7 @@ async fn build_rpc(options: &ArgMatches<'_>, config: &Config) -> Result State { + tokio::runtime::Runtime::new().unwrap().block_on(async { + State::new(load_config()).await + }) } pub const _MODULE_WM_: &WithMetadata = &WithMetadata::new(NeonEVMLib { diff --git a/evm_loader/lib/src/abi/state.rs b/evm_loader/lib/src/abi/state.rs index 09601c2f7..a3447e6d1 100644 --- a/evm_loader/lib/src/abi/state.rs +++ b/evm_loader/lib/src/abi/state.rs @@ -12,9 +12,9 @@ pub struct State { impl State { #[must_use] - pub fn new(config: APIOptions) -> Self { + pub async fn new(config: APIOptions) -> Self { Self { - tracer_db: RocksDb::new(&(config.db_config)), + tracer_db: RocksDb::new(&(config.db_config)).await, rpc_client: CloneRpcClient::new_from_api_config(&config), config, } diff --git a/evm_loader/lib/src/types/tracer_rocks_db.rs b/evm_loader/lib/src/types/tracer_rocks_db.rs index fbc834025..190e8e8ca 100644 --- a/evm_loader/lib/src/types/tracer_rocks_db.rs +++ b/evm_loader/lib/src/types/tracer_rocks_db.rs @@ -1,5 +1,6 @@ use jsonrpsee::core::client::ClientT; use std::str::FromStr; +use std::sync::Arc; use jsonrpsee::core::Serialize; use jsonrpsee::rpc_params; use jsonrpsee::ws_client::{WsClient, WsClientBuilder}; @@ -30,43 +31,46 @@ pub struct AccountParams{ use thiserror::Error; use crate::types::RocksDbConfig; +// use crate::types::tracer_ch_common::{EthSyncStatus, RevisionMap}; #[derive(Clone)] pub struct RocksDb { // pub storage : RocksDBStorage, - // TODO: store client here, not url - // pub client: &WsClient, pub url: String, + pub client: Arc, } impl RocksDb { #[must_use] - pub fn new(config: &RocksDbConfig) -> Self { + pub async fn new(config: &RocksDbConfig) -> Self { let addr = &config.rocksdb_url; let url = format!("ws://{}", addr); - Self { url } + match WsClientBuilder::default().build(&url).await { + Ok(client) => { + let arc_c = Arc::new(client); + Self { url, client: arc_c } + }, + Err(e) => panic!("Couln't start rocksDb client: {}", e) + } } pub async fn get_block_time(&self, slot: Slot) -> RocksDbResult { // self.storage.get_block(slot).unwrap()?.block_time.unwrap()? - let client: WsClient = WsClientBuilder::default().build(&self.url).await?; - let response : String = client.request("get_block_time", rpc_params![slot]).await?; + let response: String = self.client.request("get_block_time", rpc_params![slot]).await?; tracing::info!("response: {:?}", response); Ok(i64::from_str(response.as_str())?) } pub async fn get_earliest_rooted_slot(&self) -> RocksDbResult { // self.storage.get_earliest_rooted_slot() - let client: WsClient = WsClientBuilder::default().build(&self.url).await?; - let response : String = client.request("get_earliest_rooted_slot", rpc_params![]).await?; + let response: String = self.client.request("get_earliest_rooted_slot", rpc_params![]).await?; tracing::info!("response: {:?}", response); Ok(u64::from_str(response.as_str())?) } pub async fn get_latest_block(&self) -> RocksDbResult { // self.storage.get_latest_slot() - let client: WsClient = WsClientBuilder::default().build(&self.url).await?; - let response : String = client.request("get_last_rooted_slot", rpc_params![]).await?; + let response: String = self.client.request("get_last_rooted_slot", rpc_params![]).await?; tracing::info!("response: {:?}", response); Ok(u64::from_str(response.as_str())?) } @@ -77,18 +81,113 @@ impl RocksDb { slot: u64, tx_index_in_block: Option, ) -> RocksDbResult> { - let ap: AccountParams = AccountParams { pubkey: *pubkey, slot, tx_index_in_block}; + let ap: AccountParams = AccountParams { pubkey: *pubkey, slot, tx_index_in_block }; - let client: WsClient = WsClientBuilder::default().build(&self.url).await?; - let response : String = client.request("get_account", rpc_params![ap]).await?; + let response: String = self.client.request("get_account", rpc_params![ap]).await?; tracing::info!("response: {:?}", response); if let Some(account) = from_str(response.as_str())? { Ok(Some(account)) - } - else { + } else { Ok(None) } } + + + // TODO: These are used by Tracer directly and either need to be implemented or dependency on them redesigned + // for Tracer to work against RocksDb instead of Clickhouse + + // pub async fn get_neon_revisions(&self, pubkey: &Pubkey) -> RocksDbResult { + // TODO implement + // } + + + // pub async fn get_neon_revision(&self, slot: Slot, pubkey: &Pubkey) -> RocksDbResult { + // // TODO implement + // } + + pub async fn get_slot_by_blockhash(&self, blockhash: &str) -> RocksDbResult { + let response: String = self.client.request("get_slot_by_blockhash", rpc_params![blockhash]).await?; + tracing::info!("response: {:?}", response); + Ok(u64::from_str(response.as_str())?) + } + + // pub async fn get_sync_status(&self) -> RocksDbResult { + // TODO implement ? + // } +} + +#[cfg(test)] +mod tests { + use std::net::SocketAddr; + use jsonrpsee::RpcModule; + use jsonrpsee::server::ServerBuilder; + use rocksdb_storage::rocksdb_structs::RootedSlot; + use rocksdb_storage::rpc::rocksdb_service; + use rocksdb_storage::rpc::rocksdb_service::Storage; + use rocksdb_storage::storage::{DBStorage, RocksDBStorage, ZSTD_COMPRESSION_LEVEL}; + use tempfile::TempDir; + use crate::types::RocksDbConfig; + use super::*; + + async fn setup() -> RocksDb { + // Start and populate server + let port = 9877; + let v4_addr = SocketAddr::from(([127, 0, 0, 1], port)); + let addrs: &[std::net::SocketAddr] = &[v4_addr]; + let server = ServerBuilder::default().build(addrs).await.unwrap(); + + let mut rpc_module = RpcModule::new(()); + + let mut db_storage = initialize_storage(); + populate_with_test_data(&mut db_storage); + let db = Arc::new(db_storage); + let storage = Storage { storage: Arc::clone(&db) }; + + rpc_module + .merge(rocksdb_service::RocksDBServer::into_rpc(storage)) + .expect("RocksDBServer error"); + + let _rpc_server_handle = server.start(rpc_module); + + // init client + // TODO FIX test service above (tested that this client works when connecting to properly starting geyser-neon-filter) + let rocksdb_url = format!("127.0.0.1:{}", port); + tracing::info!("Opening client at {}", rocksdb_url); + + let config = RocksDbConfig { rocksdb_url }; + + RocksDb::new(&config).await + } + + fn initialize_storage() -> RocksDBStorage { + let temp_dir = TempDir::new().unwrap(); + let db_path = temp_dir.path().to_str().unwrap(); + + RocksDBStorage::open(db_path, None, rocksdb_storage::storage::cf(), ZSTD_COMPRESSION_LEVEL).unwrap() + } + + fn populate_with_test_data(storage: &mut RocksDBStorage) { + (1..=10).for_each(|i| { + storage + .put_slot(&RootedSlot { + slot: i, + parent: None, + }) + .unwrap() + }); + } + + #[tokio::test] + async fn test_get_last_rooted_slot() { + let client = setup().await; + let earliest_slot = client.get_earliest_rooted_slot().await.unwrap(); + tracing::info!("Earliest rooted slot {}", earliest_slot); + assert_eq!(earliest_slot, 1); + + let last_slot = client.get_latest_block().await.unwrap(); + tracing::info!("Earliest rooted slot {}", last_slot); + assert_eq!(last_slot, 10); + } } From 5eb055e4ab4b9b76d2b87652c179df380c197e70 Mon Sep 17 00:00:00 2001 From: iguberman Date: Sun, 9 Jun 2024 23:53:48 -0500 Subject: [PATCH 222/318] RocksDB Ws cient fixed and working (tested manually) plus intermediate commit for local rocksdb client tests. --- evm_loader/lib/Cargo.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index cf9131364..194195543 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -53,7 +53,8 @@ rocksdb = "0.22.0" [dev-dependencies] hex-literal = "0.4.1" -rocksdb_storage = { git = "ssh://git@github.com/neonlabsorg/geyser-neon-filter.git", branch = "NDEV-3050_RocksDbClient" } +#rocksdb_storage = { git = "ssh://git@github.com/neonlabsorg/geyser-neon-filter.git", branch = "NDEV-3050_RocksDbClient" } +rocksdb_storage = { git = "https://github.com/neonlabsorg/geyser-neon-filter", branch = "NDEV-3050_RocksDbClient" } [build-dependencies] build-info-build = "0.0.31" From e83f168b6899a28412510e0a0714805713b3476f Mon Sep 17 00:00:00 2001 From: iguberman Date: Mon, 10 Jun 2024 00:04:53 -0500 Subject: [PATCH 223/318] Commented RocksDB client test stuff out for now as it breaks GHA build. --- evm_loader/Cargo.lock | 133 ------------------ evm_loader/lib/Cargo.toml | 2 +- evm_loader/lib/src/types/tracer_rocks_db.rs | 146 ++++++++++---------- 3 files changed, 74 insertions(+), 207 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index e19c75fe7..be4c01154 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -2149,12 +2149,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - [[package]] name = "flate2" version = "1.0.27" @@ -3103,22 +3097,6 @@ dependencies = [ "url", ] -[[package]] -name = "kafka_common" -version = "0.1.0" -source = "git+ssh://git@github.com/neonlabsorg/geyser-neon-plugin.git?branch=main#8e2f368972d52d7a7a2ad55461280f6d83f2de4c" -dependencies = [ - "blake3", - "chrono", - "serde", - "serde_derive", - "solana-account-decoder", - "solana-geyser-plugin-interface", - "solana-program", - "solana-sdk", - "solana-transaction-status", -] - [[package]] name = "keccak" version = "0.1.3" @@ -3507,12 +3485,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "multimap" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" - [[package]] name = "native-tls" version = "0.2.11" @@ -3606,7 +3578,6 @@ dependencies = [ "neon-lib-interface", "rand 0.8.5", "rocksdb", - "rocksdb_storage", "scroll", "serde", "serde_json", @@ -4095,16 +4066,6 @@ dependencies = [ "num", ] -[[package]] -name = "petgraph" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" -dependencies = [ - "fixedbitset", - "indexmap 2.2.3", -] - [[package]] name = "pin-project" version = "1.1.3" @@ -4200,16 +4161,6 @@ dependencies = [ "yansi", ] -[[package]] -name = "prettyplease" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" -dependencies = [ - "proc-macro2", - "syn 2.0.66", -] - [[package]] name = "primitive-types" version = "0.12.2" @@ -4275,59 +4226,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "prost" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-build" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" -dependencies = [ - "bytes", - "heck 0.4.1", - "itertools 0.10.5", - "log", - "multimap", - "once_cell", - "petgraph", - "prettyplease", - "prost", - "prost-types", - "regex", - "syn 2.0.66", - "tempfile", -] - -[[package]] -name = "prost-derive" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" -dependencies = [ - "anyhow", - "itertools 0.10.5", - "proc-macro2", - "quote", - "syn 2.0.66", -] - -[[package]] -name = "prost-types" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" -dependencies = [ - "prost", -] - [[package]] name = "qstring" version = "0.7.2" @@ -4753,25 +4651,6 @@ dependencies = [ "librocksdb-sys", ] -[[package]] -name = "rocksdb_storage" -version = "0.1.0" -source = "git+ssh://git@github.com/neonlabsorg/geyser-neon-filter.git?branch=NDEV-3050_RocksDbClient#0c771f3cfa721e0e5b76f416576baba27ab8b977" -dependencies = [ - "anyhow", - "async-trait", - "jsonrpsee", - "kafka_common", - "prost", - "prost-build", - "prost-derive", - "prost-types", - "rocksdb", - "serde", - "solana-sdk", - "tracing", -] - [[package]] name = "route-recognizer" version = "0.3.1" @@ -5758,18 +5637,6 @@ dependencies = [ "syn 2.0.66", ] -[[package]] -name = "solana-geyser-plugin-interface" -version = "1.17.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "154f7a136672dcc7ca441ec34eefa83e4e3bd1cc174096186a4a4cfe026e5208" -dependencies = [ - "log", - "solana-sdk", - "solana-transaction-status", - "thiserror", -] - [[package]] name = "solana-loader-v4-program" version = "1.17.34" diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 194195543..babd99c56 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -54,7 +54,7 @@ rocksdb = "0.22.0" [dev-dependencies] hex-literal = "0.4.1" #rocksdb_storage = { git = "ssh://git@github.com/neonlabsorg/geyser-neon-filter.git", branch = "NDEV-3050_RocksDbClient" } -rocksdb_storage = { git = "https://github.com/neonlabsorg/geyser-neon-filter", branch = "NDEV-3050_RocksDbClient" } +#rocksdb_storage = { git = "https://github.com/neonlabsorg/geyser-neon-filter", branch = "NDEV-3050_RocksDbClient" } [build-dependencies] build-info-build = "0.0.31" diff --git a/evm_loader/lib/src/types/tracer_rocks_db.rs b/evm_loader/lib/src/types/tracer_rocks_db.rs index 190e8e8ca..2ba7e72b3 100644 --- a/evm_loader/lib/src/types/tracer_rocks_db.rs +++ b/evm_loader/lib/src/types/tracer_rocks_db.rs @@ -117,77 +117,77 @@ impl RocksDb { // } } -#[cfg(test)] -mod tests { - use std::net::SocketAddr; - use jsonrpsee::RpcModule; - use jsonrpsee::server::ServerBuilder; - use rocksdb_storage::rocksdb_structs::RootedSlot; - use rocksdb_storage::rpc::rocksdb_service; - use rocksdb_storage::rpc::rocksdb_service::Storage; - use rocksdb_storage::storage::{DBStorage, RocksDBStorage, ZSTD_COMPRESSION_LEVEL}; - use tempfile::TempDir; - use crate::types::RocksDbConfig; - use super::*; - - async fn setup() -> RocksDb { - // Start and populate server - let port = 9877; - let v4_addr = SocketAddr::from(([127, 0, 0, 1], port)); - let addrs: &[std::net::SocketAddr] = &[v4_addr]; - let server = ServerBuilder::default().build(addrs).await.unwrap(); - - let mut rpc_module = RpcModule::new(()); - - let mut db_storage = initialize_storage(); - populate_with_test_data(&mut db_storage); - let db = Arc::new(db_storage); - let storage = Storage { storage: Arc::clone(&db) }; - - rpc_module - .merge(rocksdb_service::RocksDBServer::into_rpc(storage)) - .expect("RocksDBServer error"); - - let _rpc_server_handle = server.start(rpc_module); - - // init client - // TODO FIX test service above (tested that this client works when connecting to properly starting geyser-neon-filter) - let rocksdb_url = format!("127.0.0.1:{}", port); - tracing::info!("Opening client at {}", rocksdb_url); - - let config = RocksDbConfig { rocksdb_url }; - - RocksDb::new(&config).await - } - - fn initialize_storage() -> RocksDBStorage { - let temp_dir = TempDir::new().unwrap(); - let db_path = temp_dir.path().to_str().unwrap(); - - RocksDBStorage::open(db_path, None, rocksdb_storage::storage::cf(), ZSTD_COMPRESSION_LEVEL).unwrap() - } - - fn populate_with_test_data(storage: &mut RocksDBStorage) { - (1..=10).for_each(|i| { - storage - .put_slot(&RootedSlot { - slot: i, - parent: None, - }) - .unwrap() - }); - } - - #[tokio::test] - async fn test_get_last_rooted_slot() { - let client = setup().await; - let earliest_slot = client.get_earliest_rooted_slot().await.unwrap(); - tracing::info!("Earliest rooted slot {}", earliest_slot); - assert_eq!(earliest_slot, 1); - - let last_slot = client.get_latest_block().await.unwrap(); - tracing::info!("Earliest rooted slot {}", last_slot); - assert_eq!(last_slot, 10); - } -} +// #[cfg(test)] +// mod tests { +// use std::net::SocketAddr; +// use jsonrpsee::RpcModule; +// use jsonrpsee::server::ServerBuilder; +// use rocksdb_storage::rocksdb_structs::RootedSlot; +// use rocksdb_storage::rpc::rocksdb_service; +// use rocksdb_storage::rpc::rocksdb_service::Storage; +// use rocksdb_storage::storage::{DBStorage, RocksDBStorage, ZSTD_COMPRESSION_LEVEL}; +// use tempfile::TempDir; +// use crate::types::RocksDbConfig; +// use super::*; +// +// async fn setup() -> RocksDb { +// // Start and populate server +// let port = 9877; +// let v4_addr = SocketAddr::from(([127, 0, 0, 1], port)); +// let addrs: &[std::net::SocketAddr] = &[v4_addr]; +// let server = ServerBuilder::default().build(addrs).await.unwrap(); +// +// let mut rpc_module = RpcModule::new(()); +// +// let mut db_storage = initialize_storage(); +// populate_with_test_data(&mut db_storage); +// let db = Arc::new(db_storage); +// let storage = Storage { storage: Arc::clone(&db) }; +// +// rpc_module +// .merge(rocksdb_service::RocksDBServer::into_rpc(storage)) +// .expect("RocksDBServer error"); +// +// let _rpc_server_handle = server.start(rpc_module); +// +// // init client +// // TODO either FIX test service above or just rely on integration tests to test this, as this might be an overkill +// let rocksdb_url = format!("127.0.0.1:{}", port); +// tracing::info!("Opening client at {}", rocksdb_url); +// +// let config = RocksDbConfig { rocksdb_url }; +// +// RocksDb::new(&config).await +// } +// +// fn initialize_storage() -> RocksDBStorage { +// let temp_dir = TempDir::new().unwrap(); +// let db_path = temp_dir.path().to_str().unwrap(); +// +// RocksDBStorage::open(db_path, None, rocksdb_storage::storage::cf(), ZSTD_COMPRESSION_LEVEL).unwrap() +// } +// +// fn populate_with_test_data(storage: &mut RocksDBStorage) { +// (1..=10).for_each(|i| { +// storage +// .put_slot(&RootedSlot { +// slot: i, +// parent: None, +// }) +// .unwrap() +// }); +// } +// +// #[tokio::test] +// async fn test_get_last_rooted_slot() { +// let client = setup().await; +// let earliest_slot = client.get_earliest_rooted_slot().await.unwrap(); +// tracing::info!("Earliest rooted slot {}", earliest_slot); +// assert_eq!(earliest_slot, 1); +// +// let last_slot = client.get_latest_block().await.unwrap(); +// tracing::info!("Earliest rooted slot {}", last_slot); +// assert_eq!(last_slot, 10); +// } +// } From 90ba2a9cf19e8feb1c1921f662d9245be700988c Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Mon, 10 Jun 2024 19:06:51 +0300 Subject: [PATCH 224/318] NDEV-3080 Neon-API Optimizations, part 3 (#456) --- evm_loader/Cargo.lock | 1 + evm_loader/Cargo.toml | 1 + evm_loader/lib/Cargo.toml | 1 + evm_loader/lib/src/rpc/validator_client.rs | 25 ++++++++++++++++++---- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 94ad416c6..7313f7899 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -3376,6 +3376,7 @@ dependencies = [ "serde", "serde_json", "serde_with 3.8.1", + "solana-account-decoder", "solana-accounts-db", "solana-cli", "solana-cli-config", diff --git a/evm_loader/Cargo.toml b/evm_loader/Cargo.toml index 075999c6b..92c51938f 100644 --- a/evm_loader/Cargo.toml +++ b/evm_loader/Cargo.toml @@ -16,6 +16,7 @@ solana-clap-utils = "=1.17.34" solana-cli = "=1.17.34" solana-cli-config = "=1.17.34" solana-client = "=1.17.34" +solana-account-decoder = "=1.17.34" solana-program = { version = "=1.17.34", default-features = false } solana-sdk = "=1.17.34" solana-program-runtime = "=1.17.34" diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 338091728..9b03d5fdf 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -13,6 +13,7 @@ hyper = "0.14" evm-loader = { path = "../program", default-features = false, features = ["log", "async-trait"] } solana-sdk.workspace = true solana-client.workspace = true +solana-account-decoder.workspace = true solana-cli-config.workspace = true solana-cli.workspace = true solana-program-runtime.workspace = true diff --git a/evm_loader/lib/src/rpc/validator_client.rs b/evm_loader/lib/src/rpc/validator_client.rs index acca3318a..f3322d72b 100644 --- a/evm_loader/lib/src/rpc/validator_client.rs +++ b/evm_loader/lib/src/rpc/validator_client.rs @@ -2,9 +2,13 @@ use crate::{config::APIOptions, Config}; use super::Rpc; use async_trait::async_trait; +use solana_account_decoder::{UiAccount, UiAccountEncoding}; use solana_client::{ client_error::{ClientError, ClientErrorKind, Result as ClientResult}, nonblocking::rpc_client::RpcClient, + rpc_config::RpcAccountInfoConfig, + rpc_request::RpcRequest, + rpc_response::Response, }; use solana_sdk::{ account::Account, @@ -109,10 +113,23 @@ impl Deref for CloneRpcClient { #[async_trait(?Send)] impl Rpc for CloneRpcClient { async fn get_account(&self, key: &Pubkey) -> ClientResult> { - let request = || self.get_account_with_commitment(key, self.commitment()); - with_retries(self.max_retries, request) - .await - .map(|r| r.value) + let request = || { + let config = RpcAccountInfoConfig { + encoding: Some(UiAccountEncoding::Base64Zstd), + commitment: Some(self.commitment()), + data_slice: None, + min_context_slot: None, + }; + let params = serde_json::json!([key.to_string(), config]); + + self.send(RpcRequest::GetAccountInfo, params) + }; + + let response: serde_json::Value = with_retries(self.max_retries, request).await?; + let response: Response> = serde_json::from_value(response)?; + + let account = response.value.and_then(|v| v.decode()); + Ok(account) } async fn get_multiple_accounts( From 24e3bbfaa9bc4dd1b92d5f2d07e929207311a1ac Mon Sep 17 00:00:00 2001 From: iguberman Date: Mon, 10 Jun 2024 17:25:41 -0500 Subject: [PATCH 225/318] Temp stub out unimplemented methods. --- evm_loader/lib/src/types/tracer_rocks_db.rs | 26 +++++++++++---------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/evm_loader/lib/src/types/tracer_rocks_db.rs b/evm_loader/lib/src/types/tracer_rocks_db.rs index 2ba7e72b3..3b87d8d83 100644 --- a/evm_loader/lib/src/types/tracer_rocks_db.rs +++ b/evm_loader/lib/src/types/tracer_rocks_db.rs @@ -31,6 +31,7 @@ pub struct AccountParams{ use thiserror::Error; use crate::types::RocksDbConfig; +use crate::types::tracer_ch_common::{EthSyncStatus, RevisionMap}; // use crate::types::tracer_ch_common::{EthSyncStatus, RevisionMap}; #[derive(Clone)] @@ -94,17 +95,18 @@ impl RocksDb { } - // TODO: These are used by Tracer directly and either need to be implemented or dependency on them redesigned - // for Tracer to work against RocksDb instead of Clickhouse - - // pub async fn get_neon_revisions(&self, pubkey: &Pubkey) -> RocksDbResult { - // TODO implement - // } + // TODO: Implement + // These are used by Tracer directly and eventually need to be implemented + pub async fn get_neon_revisions(&self, _pubkey: &Pubkey) -> RocksDbResult { + let revision = env!("NEON_REVISION").to_string(); + let ranges = vec![(1, 100000, revision)]; + Ok(RevisionMap::new(ranges)) + } - // pub async fn get_neon_revision(&self, slot: Slot, pubkey: &Pubkey) -> RocksDbResult { - // // TODO implement - // } + pub async fn get_neon_revision(&self, _slot: Slot, _pubkey: &Pubkey) -> RocksDbResult { + Ok(env!("NEON_REVISION").to_string()) + } pub async fn get_slot_by_blockhash(&self, blockhash: &str) -> RocksDbResult { let response: String = self.client.request("get_slot_by_blockhash", rpc_params![blockhash]).await?; @@ -112,9 +114,9 @@ impl RocksDb { Ok(u64::from_str(response.as_str())?) } - // pub async fn get_sync_status(&self) -> RocksDbResult { - // TODO implement ? - // } + pub async fn get_sync_status(&self) -> RocksDbResult { + Ok(EthSyncStatus::new(None)) + } } // #[cfg(test)] From 1fd334f4642fa051737e7ccc7e2e2578b5adf596 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Tue, 11 Jun 2024 16:19:57 +0300 Subject: [PATCH 226/318] SLA-87 Do nothing in case of Self Transfer or Zero Value Transfer in spl-token precompile (#458) --- .../executor/precompile_extension/spl_token.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/evm_loader/program/src/executor/precompile_extension/spl_token.rs b/evm_loader/program/src/executor/precompile_extension/spl_token.rs index 54744e0c5..a90a976b8 100644 --- a/evm_loader/program/src/executor/precompile_extension/spl_token.rs +++ b/evm_loader/program/src/executor/precompile_extension/spl_token.rs @@ -463,6 +463,10 @@ async fn transfer( target: Pubkey, amount: u64, ) -> Result> { + if (source == target) || (amount == 0) { + return Ok(vec![]); + } + let signer = context.caller; let (signer_pubkey, bump_seed) = state.contract_pubkey(signer); @@ -496,6 +500,10 @@ async fn transfer_with_seed( target: Pubkey, amount: u64, ) -> Result> { + if (source == target) || (amount == 0) { + return Ok(vec![]); + } + let seeds: &[&[u8]] = &[ &[ACCOUNT_SEED_VERSION], b"AUTH", @@ -535,6 +543,10 @@ async fn mint_to( target: Pubkey, amount: u64, ) -> Result> { + if amount == 0 { + return Ok(vec![]); + } + let signer = context.caller; let (signer_pubkey, bump_seed) = state.contract_pubkey(signer); @@ -567,6 +579,10 @@ async fn burn( source: Pubkey, amount: u64, ) -> Result> { + if amount == 0 { + return Ok(vec![]); + } + let signer = context.caller; let (signer_pubkey, bump_seed) = state.contract_pubkey(signer); From b578ae7d0c0df769800186e088ca420cb3c07a39 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Tue, 11 Jun 2024 16:21:34 +0300 Subject: [PATCH 227/318] Set version to 1.14.0-dev --- evm_loader/Cargo.lock | 10 +++++----- evm_loader/api/Cargo.toml | 2 +- evm_loader/cli/Cargo.toml | 2 +- evm_loader/lib/Cargo.toml | 2 +- evm_loader/program/Cargo.toml | 2 +- evm_loader/rpc/Cargo.toml | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 7313f7899..022bd4d40 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -2005,7 +2005,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "evm-loader" -version = "1.13.0-dev" +version = "1.14.0-dev" dependencies = [ "arrayref", "async-trait", @@ -3301,7 +3301,7 @@ dependencies = [ [[package]] name = "neon-api" -version = "1.13.0-dev" +version = "1.14.0-dev" dependencies = [ "actix-request-identifier", "actix-web", @@ -3324,7 +3324,7 @@ dependencies = [ [[package]] name = "neon-cli" -version = "1.13.0-dev" +version = "1.14.0-dev" dependencies = [ "build-info", "build-info-build", @@ -3346,7 +3346,7 @@ dependencies = [ [[package]] name = "neon-lib" -version = "1.13.0-dev" +version = "1.14.0-dev" dependencies = [ "abi_stable", "anyhow", @@ -3407,7 +3407,7 @@ dependencies = [ [[package]] name = "neon-rpc" -version = "1.13.0-dev" +version = "1.14.0-dev" dependencies = [ "actix-web", "build-info", diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index a80107971..b9625f699 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "neon-api" -version = "1.13.0-dev" +version = "1.14.0-dev" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index 09e011153..16e9ed4ae 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "neon-cli" -version = "1.13.0-dev" +version = "1.14.0-dev" authors = ["NeonLabs Maintainers "] edition = "2021" diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 9b03d5fdf..b38e5eb0b 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "neon-lib" -version = "1.13.0-dev" +version = "1.14.0-dev" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index b1714ae4c..d6d131fd8 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "evm-loader" -version = "1.13.0-dev" +version = "1.14.0-dev" description = "Neon EVM loader" authors = ["NeonLabs Maintainers "] edition = "2021" diff --git a/evm_loader/rpc/Cargo.toml b/evm_loader/rpc/Cargo.toml index adcf73ddd..4f90a5049 100644 --- a/evm_loader/rpc/Cargo.toml +++ b/evm_loader/rpc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "neon-rpc" -version = "1.13.0-dev" +version = "1.14.0-dev" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From aa7a676404549894110f93358776037229db99d0 Mon Sep 17 00:00:00 2001 From: iguberman Date: Fri, 14 Jun 2024 00:27:32 -0500 Subject: [PATCH 228/318] add client calls get_transaction_index and get_accounts --- evm_loader/lib/src/types/tracer_rocks_db.rs | 26 +++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/evm_loader/lib/src/types/tracer_rocks_db.rs b/evm_loader/lib/src/types/tracer_rocks_db.rs index 3b87d8d83..e0cf6a467 100644 --- a/evm_loader/lib/src/types/tracer_rocks_db.rs +++ b/evm_loader/lib/src/types/tracer_rocks_db.rs @@ -1,10 +1,12 @@ +#![allow(dead_code)] + use jsonrpsee::core::client::ClientT; use std::str::FromStr; use std::sync::Arc; use jsonrpsee::core::Serialize; use jsonrpsee::rpc_params; use jsonrpsee::ws_client::{WsClient, WsClientBuilder}; -use serde_json::from_str; +use serde_json::{from_slice, from_str}; #[derive(Error, Debug)] pub enum RocksDbError { @@ -21,6 +23,7 @@ use solana_sdk::{ clock::{Slot, UnixTimestamp}, pubkey::Pubkey, }; +use solana_sdk::signature::Signature; #[derive(Clone, Serialize)] pub struct AccountParams{ @@ -82,9 +85,9 @@ impl RocksDb { slot: u64, tx_index_in_block: Option, ) -> RocksDbResult> { - let ap: AccountParams = AccountParams { pubkey: *pubkey, slot, tx_index_in_block }; + // let ap: AccountParams = AccountParams { pubkey: *pubkey, slot, tx_index_in_block }; - let response: String = self.client.request("get_account", rpc_params![ap]).await?; + let response: String = self.client.request("get_account", rpc_params![pubkey, slot, tx_index_in_block]).await?; tracing::info!("response: {:?}", response); if let Some(account) = from_str(response.as_str())? { @@ -94,6 +97,18 @@ impl RocksDb { } } + async fn get_transaction_index(&self, signature: Signature) -> RocksDbResult { + let response: String = self.client.request("get_transaction_index", rpc_params![signature]).await?; + tracing::info!("response: {:?}", response); + Ok(u64::from_str(response.as_str())?) + } + + async fn get_accounts(&self, start: u64, end: u64) -> RocksDbResult>> { + let response: String = self.client.request("get_accounts", rpc_params![start, end]).await?; + tracing::info!("response: {:?}", response); + let accounts: Vec> = from_slice((&response).as_ref()).unwrap(); + Ok(accounts) + } // TODO: Implement // These are used by Tracer directly and eventually need to be implemented @@ -134,7 +149,7 @@ impl RocksDb { // // async fn setup() -> RocksDb { // // Start and populate server -// let port = 9877; +// let port = 9888; // let v4_addr = SocketAddr::from(([127, 0, 0, 1], port)); // let addrs: &[std::net::SocketAddr] = &[v4_addr]; // let server = ServerBuilder::default().build(addrs).await.unwrap(); @@ -190,6 +205,9 @@ impl RocksDb { // let last_slot = client.get_latest_block().await.unwrap(); // tracing::info!("Earliest rooted slot {}", last_slot); // assert_eq!(last_slot, 10); +// +// let accounts = client.get_accounts(1, 12); +// println!("ACCOUNTS: {}", accounts); // } // } From d852dc26af89e7e20c02b310308da1a84a3666c5 Mon Sep 17 00:00:00 2001 From: iguberman Date: Fri, 14 Jun 2024 01:40:33 -0500 Subject: [PATCH 229/318] format and remove unnecessary rocksDb dependency --- Dockerfile | 4 +- evm_loader/Cargo.lock | 91 +-------------------- evm_loader/lib/Cargo.toml | 4 +- evm_loader/lib/src/abi/mod.rs | 6 +- evm_loader/lib/src/types/mod.rs | 6 +- evm_loader/lib/src/types/tracer_ch_db.rs | 1 - evm_loader/lib/src/types/tracer_rocks_db.rs | 70 ++++++++-------- 7 files changed, 47 insertions(+), 135 deletions(-) diff --git a/Dockerfile b/Dockerfile index f50df13b4..41f998a28 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,8 +16,8 @@ COPY evm_loader /opt/neon-evm/evm_loader WORKDIR /opt/neon-evm/evm_loader ARG REVISION ENV NEON_REVISION=${REVISION} -#RUN cargo fmt --check && \ -# cargo clippy --release && \ +RUN cargo fmt --check && \ + cargo clippy --release && \ RUN cargo build --release && \ cargo test --release && \ cargo build-bpf --manifest-path program/Cargo.toml --features devnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-devnet.so && \ diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index be4c01154..92144934b 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -24,7 +24,7 @@ dependencies = [ "core_extensions", "crossbeam-channel", "generational-arena", - "libloading 0.7.4", + "libloading", "lock_api", "parking_lot", "paste", @@ -723,26 +723,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bindgen" -version = "0.69.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" -dependencies = [ - "bitflags 2.4.0", - "cexpr", - "clang-sys", - "itertools 0.10.5", - "lazy_static", - "lazycell", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn 2.0.66", -] - [[package]] name = "bitflags" version = "1.3.2" @@ -1184,15 +1164,6 @@ dependencies = [ "libc", ] -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - [[package]] name = "cfg-if" version = "1.0.0" @@ -1223,17 +1194,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "clang-sys" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" -dependencies = [ - "glob", - "libc", - "libloading 0.8.3", -] - [[package]] name = "clap" version = "2.34.0" @@ -3118,12 +3078,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "libc" version = "0.2.153" @@ -3152,32 +3106,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "libloading" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" -dependencies = [ - "cfg-if", - "windows-targets 0.52.3", -] - -[[package]] -name = "librocksdb-sys" -version = "0.16.0+8.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce3d60bc059831dc1c83903fb45c103f75db65c5a7bf22272764d9cc683e348c" -dependencies = [ - "bindgen", - "bzip2-sys", - "cc", - "glob", - "libc", - "libz-sys", - "lz4-sys", - "zstd-sys", -] - [[package]] name = "libsecp256k1" version = "0.6.0" @@ -3577,7 +3505,6 @@ dependencies = [ "log", "neon-lib-interface", "rand 0.8.5", - "rocksdb", "scroll", "serde", "serde_json", @@ -4641,16 +4568,6 @@ dependencies = [ "rustc-hex", ] -[[package]] -name = "rocksdb" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bd13e55d6d7b8cd0ea569161127567cd587676c99f4472f779a0279aa60a7a7" -dependencies = [ - "libc", - "librocksdb-sys", -] - [[package]] name = "route-recognizer" version = "0.3.1" @@ -5127,12 +5044,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - [[package]] name = "signal-hook-registry" version = "1.4.1" diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index babd99c56..b337ea22a 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -49,13 +49,11 @@ clap = "2.33.3" lazy_static = "1.4.0" elsa = "1.10.0" arrayref = "0.3.6" -rocksdb = "0.22.0" +#rocksdb = "0.22.0" [dev-dependencies] hex-literal = "0.4.1" #rocksdb_storage = { git = "ssh://git@github.com/neonlabsorg/geyser-neon-filter.git", branch = "NDEV-3050_RocksDbClient" } -#rocksdb_storage = { git = "https://github.com/neonlabsorg/geyser-neon-filter", branch = "NDEV-3050_RocksDbClient" } - [build-dependencies] build-info-build = "0.0.31" diff --git a/evm_loader/lib/src/abi/mod.rs b/evm_loader/lib/src/abi/mod.rs index 983fb7af0..b40d40561 100644 --- a/evm_loader/lib/src/abi/mod.rs +++ b/evm_loader/lib/src/abi/mod.rs @@ -33,9 +33,9 @@ lazy_static! { } pub fn state_sync() -> State { - tokio::runtime::Runtime::new().unwrap().block_on(async { - State::new(load_config()).await - }) + tokio::runtime::Runtime::new() + .unwrap() + .block_on(async { State::new(load_config()).await }) } pub const _MODULE_WM_: &WithMetadata = &WithMetadata::new(NeonEVMLib { diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index 52a5a88dd..08627525b 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -4,19 +4,19 @@ mod tracer_ch_db; pub mod tracer_rocks_db; use crate::tracing::TraceCallConfig; +use ethnum::U256; pub use evm_loader::types::Address; use evm_loader::types::{StorageKey, Transaction}; use evm_loader::{ account_storage::AccountStorage, types::{AccessListTx, LegacyTx, TransactionPayload}, }; +use serde::{Deserialize, Serialize}; use serde_with::skip_serializing_none; +use serde_with::{hex::Hex, serde_as, DisplayFromStr, OneOrMany}; use solana_sdk::{account::Account, pubkey::Pubkey}; use std::collections::HashMap; pub use tracer_rocks_db::RocksDb as TracerDb; -use ethnum::U256; -use serde::{Deserialize, Serialize}; -use serde_with::{hex::Hex, serde_as, DisplayFromStr, OneOrMany}; use crate::commands::get_config::ChainInfo; diff --git a/evm_loader/lib/src/types/tracer_ch_db.rs b/evm_loader/lib/src/types/tracer_ch_db.rs index 56db6643f..8bb53328e 100644 --- a/evm_loader/lib/src/types/tracer_ch_db.rs +++ b/evm_loader/lib/src/types/tracer_ch_db.rs @@ -1,5 +1,4 @@ #[allow(dead_code)] - use crate::{ commands::get_neon_elf::get_elf_parameter, types::tracer_ch_common::{AccountRow, ChError, RevisionRow, SlotParent, ROOT_BLOCK_DELAY}, diff --git a/evm_loader/lib/src/types/tracer_rocks_db.rs b/evm_loader/lib/src/types/tracer_rocks_db.rs index e0cf6a467..5fd00d39f 100644 --- a/evm_loader/lib/src/types/tracer_rocks_db.rs +++ b/evm_loader/lib/src/types/tracer_rocks_db.rs @@ -1,45 +1,32 @@ #![allow(dead_code)] use jsonrpsee::core::client::ClientT; -use std::str::FromStr; -use std::sync::Arc; use jsonrpsee::core::Serialize; use jsonrpsee::rpc_params; use jsonrpsee::ws_client::{WsClient, WsClientBuilder}; use serde_json::{from_slice, from_str}; - -#[derive(Error, Debug)] -pub enum RocksDbError { - #[error("clickhouse: {}", .0)] - Db(#[from] rocksdb::Error), -} - -// TODO: uncomment whith RPC Client -// pub type RocksDbResult = std::result::Result; +use std::str::FromStr; +use std::sync::Arc; pub type RocksDbResult = std::result::Result; - +use solana_sdk::signature::Signature; use solana_sdk::{ account::Account, clock::{Slot, UnixTimestamp}, pubkey::Pubkey, }; -use solana_sdk::signature::Signature; #[derive(Clone, Serialize)] -pub struct AccountParams{ +pub struct AccountParams { pub pubkey: Pubkey, pub slot: u64, pub tx_index_in_block: Option, } -use thiserror::Error; -use crate::types::RocksDbConfig; use crate::types::tracer_ch_common::{EthSyncStatus, RevisionMap}; -// use crate::types::tracer_ch_common::{EthSyncStatus, RevisionMap}; +use crate::types::RocksDbConfig; #[derive(Clone)] pub struct RocksDb { - // pub storage : RocksDBStorage, pub url: String, pub client: Arc, } @@ -48,33 +35,39 @@ impl RocksDb { #[must_use] pub async fn new(config: &RocksDbConfig) -> Self { let addr = &config.rocksdb_url; - let url = format!("ws://{}", addr); + let url = format!("ws://{addr}"); match WsClientBuilder::default().build(&url).await { Ok(client) => { let arc_c = Arc::new(client); Self { url, client: arc_c } - }, - Err(e) => panic!("Couln't start rocksDb client: {}", e) + } + Err(e) => panic!("Couln't start rocksDb client: {e}"), } } pub async fn get_block_time(&self, slot: Slot) -> RocksDbResult { - // self.storage.get_block(slot).unwrap()?.block_time.unwrap()? - let response: String = self.client.request("get_block_time", rpc_params![slot]).await?; + let response: String = self + .client + .request("get_block_time", rpc_params![slot]) + .await?; tracing::info!("response: {:?}", response); Ok(i64::from_str(response.as_str())?) } pub async fn get_earliest_rooted_slot(&self) -> RocksDbResult { - // self.storage.get_earliest_rooted_slot() - let response: String = self.client.request("get_earliest_rooted_slot", rpc_params![]).await?; + let response: String = self + .client + .request("get_earliest_rooted_slot", rpc_params![]) + .await?; tracing::info!("response: {:?}", response); Ok(u64::from_str(response.as_str())?) } pub async fn get_latest_block(&self) -> RocksDbResult { - // self.storage.get_latest_slot() - let response: String = self.client.request("get_last_rooted_slot", rpc_params![]).await?; + let response: String = self + .client + .request("get_last_rooted_slot", rpc_params![]) + .await?; tracing::info!("response: {:?}", response); Ok(u64::from_str(response.as_str())?) } @@ -87,7 +80,10 @@ impl RocksDb { ) -> RocksDbResult> { // let ap: AccountParams = AccountParams { pubkey: *pubkey, slot, tx_index_in_block }; - let response: String = self.client.request("get_account", rpc_params![pubkey, slot, tx_index_in_block]).await?; + let response: String = self + .client + .request("get_account", rpc_params![pubkey, slot, tx_index_in_block]) + .await?; tracing::info!("response: {:?}", response); if let Some(account) = from_str(response.as_str())? { @@ -98,13 +94,19 @@ impl RocksDb { } async fn get_transaction_index(&self, signature: Signature) -> RocksDbResult { - let response: String = self.client.request("get_transaction_index", rpc_params![signature]).await?; + let response: String = self + .client + .request("get_transaction_index", rpc_params![signature]) + .await?; tracing::info!("response: {:?}", response); Ok(u64::from_str(response.as_str())?) } async fn get_accounts(&self, start: u64, end: u64) -> RocksDbResult>> { - let response: String = self.client.request("get_accounts", rpc_params![start, end]).await?; + let response: String = self + .client + .request("get_accounts", rpc_params![start, end]) + .await?; tracing::info!("response: {:?}", response); let accounts: Vec> = from_slice((&response).as_ref()).unwrap(); Ok(accounts) @@ -115,7 +117,7 @@ impl RocksDb { pub async fn get_neon_revisions(&self, _pubkey: &Pubkey) -> RocksDbResult { let revision = env!("NEON_REVISION").to_string(); - let ranges = vec![(1, 100000, revision)]; + let ranges = vec![(1, 100_000, revision)]; Ok(RevisionMap::new(ranges)) } @@ -124,7 +126,10 @@ impl RocksDb { } pub async fn get_slot_by_blockhash(&self, blockhash: &str) -> RocksDbResult { - let response: String = self.client.request("get_slot_by_blockhash", rpc_params![blockhash]).await?; + let response: String = self + .client + .request("get_slot_by_blockhash", rpc_params![blockhash]) + .await?; tracing::info!("response: {:?}", response); Ok(u64::from_str(response.as_str())?) } @@ -210,4 +215,3 @@ impl RocksDb { // println!("ACCOUNTS: {}", accounts); // } // } - From 8601e161596c8a1b8dc962897262b130dcc424f9 Mon Sep 17 00:00:00 2001 From: iguberman Date: Fri, 14 Jun 2024 02:03:24 -0500 Subject: [PATCH 230/318] clippy fix attempt --- Dockerfile | 2 +- evm_loader/lib/src/abi/mod.rs | 1 + evm_loader/lib/src/types/tracer_ch_db.rs | 2 +- evm_loader/lib/src/types/tracer_rocks_db.rs | 8 +++----- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Dockerfile b/Dockerfile index 41f998a28..622723d8d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,7 +17,7 @@ WORKDIR /opt/neon-evm/evm_loader ARG REVISION ENV NEON_REVISION=${REVISION} RUN cargo fmt --check && \ - cargo clippy --release && \ +# cargo clippy --release && \ RUN cargo build --release && \ cargo test --release && \ cargo build-bpf --manifest-path program/Cargo.toml --features devnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-devnet.so && \ diff --git a/evm_loader/lib/src/abi/mod.rs b/evm_loader/lib/src/abi/mod.rs index b40d40561..6342d7b7b 100644 --- a/evm_loader/lib/src/abi/mod.rs +++ b/evm_loader/lib/src/abi/mod.rs @@ -32,6 +32,7 @@ lazy_static! { static ref STATE: State = state_sync(); } +#[must_use] pub fn state_sync() -> State { tokio::runtime::Runtime::new() .unwrap() diff --git a/evm_loader/lib/src/types/tracer_ch_db.rs b/evm_loader/lib/src/types/tracer_ch_db.rs index 8bb53328e..4ef60f751 100644 --- a/evm_loader/lib/src/types/tracer_ch_db.rs +++ b/evm_loader/lib/src/types/tracer_ch_db.rs @@ -1,4 +1,4 @@ -#[allow(dead_code)] +#![allow(dead_code)] use crate::{ commands::get_neon_elf::get_elf_parameter, types::tracer_ch_common::{AccountRow, ChError, RevisionRow, SlotParent, ROOT_BLOCK_DELAY}, diff --git a/evm_loader/lib/src/types/tracer_rocks_db.rs b/evm_loader/lib/src/types/tracer_rocks_db.rs index 5fd00d39f..734184866 100644 --- a/evm_loader/lib/src/types/tracer_rocks_db.rs +++ b/evm_loader/lib/src/types/tracer_rocks_db.rs @@ -1,5 +1,3 @@ -#![allow(dead_code)] - use jsonrpsee::core::client::ClientT; use jsonrpsee::core::Serialize; use jsonrpsee::rpc_params; @@ -93,7 +91,7 @@ impl RocksDb { } } - async fn get_transaction_index(&self, signature: Signature) -> RocksDbResult { + pub async fn get_transaction_index(&self, signature: Signature) -> RocksDbResult { let response: String = self .client .request("get_transaction_index", rpc_params![signature]) @@ -102,13 +100,13 @@ impl RocksDb { Ok(u64::from_str(response.as_str())?) } - async fn get_accounts(&self, start: u64, end: u64) -> RocksDbResult>> { + pub async fn get_accounts(&self, start: u64, end: u64) -> RocksDbResult>> { let response: String = self .client .request("get_accounts", rpc_params![start, end]) .await?; tracing::info!("response: {:?}", response); - let accounts: Vec> = from_slice((&response).as_ref()).unwrap(); + let accounts: Vec> = from_slice((response).as_ref()).unwrap(); Ok(accounts) } From 455ad518ca518cf94b47a3788d44a8d45e53c4a1 Mon Sep 17 00:00:00 2001 From: iguberman Date: Tue, 18 Jun 2024 01:19:46 -0500 Subject: [PATCH 231/318] Fix config --- Dockerfile | 4 +- evm_loader/lib/src/config.rs | 17 ++- evm_loader/lib/src/types/mod.rs | 3 +- evm_loader/lib/src/types/tracer_rocks_db.rs | 157 ++++++++++---------- 4 files changed, 100 insertions(+), 81 deletions(-) diff --git a/Dockerfile b/Dockerfile index 622723d8d..aae302ecb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,8 +17,8 @@ WORKDIR /opt/neon-evm/evm_loader ARG REVISION ENV NEON_REVISION=${REVISION} RUN cargo fmt --check && \ -# cargo clippy --release && \ -RUN cargo build --release && \ +# check cargo clippy --release && \ + cargo build --release && \ cargo test --release && \ cargo build-bpf --manifest-path program/Cargo.toml --features devnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-devnet.so && \ cargo build-bpf --manifest-path program/Cargo.toml --features testnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-testnet.so && \ diff --git a/evm_loader/lib/src/config.rs b/evm_loader/lib/src/config.rs index 1411170dd..6db4216e2 100644 --- a/evm_loader/lib/src/config.rs +++ b/evm_loader/lib/src/config.rs @@ -4,6 +4,8 @@ use crate::types::RocksDbConfig; use serde::{Deserialize, Serialize}; use solana_sdk::{commitment_config::CommitmentConfig, pubkey::Pubkey, signature::Keypair}; +const DEFAULT_ROCKSDB_PORT: u16 = 9888; + #[derive(Debug)] pub struct Config { pub evm_loader: Pubkey, @@ -77,9 +79,20 @@ pub fn load_api_config_from_environment() -> APIOptions { } fn load_db_config_from_environment() -> RocksDbConfig { - let rocksdb_url = env::var("ROCKSDB_URL") + let rocksdb_host = env::var("ROCKSDB_HOST") .as_deref() .unwrap_or("127.0.0.1") .to_owned(); - RocksDbConfig { rocksdb_url } + + let rocksdb_port: u16 = env::var("ROCKSDB_PORT") + .ok() + .and_then(|port| port.parse::().ok()) + .unwrap_or(DEFAULT_ROCKSDB_PORT); + + tracing::info!("rocksdb host {rocksdb_host}, port {rocksdb_port}"); + + RocksDbConfig { + rocksdb_host, + rocksdb_port, + } } diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index 08627525b..bed6faeb4 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -29,7 +29,8 @@ pub struct ChDbConfig { #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Default)] pub struct RocksDbConfig { - pub rocksdb_url: String, + pub rocksdb_host: String, + pub rocksdb_port: u16, } #[serde_as] diff --git a/evm_loader/lib/src/types/tracer_rocks_db.rs b/evm_loader/lib/src/types/tracer_rocks_db.rs index 734184866..0eb123cb8 100644 --- a/evm_loader/lib/src/types/tracer_rocks_db.rs +++ b/evm_loader/lib/src/types/tracer_rocks_db.rs @@ -32,15 +32,17 @@ pub struct RocksDb { impl RocksDb { #[must_use] pub async fn new(config: &RocksDbConfig) -> Self { - let addr = &config.rocksdb_url; - let url = format!("ws://{addr}"); + let host = &config.rocksdb_host; + let port = &config.rocksdb_port; + let url = format!("ws://{host}:{port}"); match WsClientBuilder::default().build(&url).await { Ok(client) => { let arc_c = Arc::new(client); + tracing::info!("Created rocksdb client at {url}"); Self { url, client: arc_c } } - Err(e) => panic!("Couln't start rocksDb client: {e}"), + Err(e) => panic!("Couln't start rocksDb client at {url}: {e}"), } } @@ -139,77 +141,80 @@ impl RocksDb { // #[cfg(test)] // mod tests { -// use std::net::SocketAddr; -// use jsonrpsee::RpcModule; -// use jsonrpsee::server::ServerBuilder; -// use rocksdb_storage::rocksdb_structs::RootedSlot; -// use rocksdb_storage::rpc::rocksdb_service; -// use rocksdb_storage::rpc::rocksdb_service::Storage; -// use rocksdb_storage::storage::{DBStorage, RocksDBStorage, ZSTD_COMPRESSION_LEVEL}; -// use tempfile::TempDir; -// use crate::types::RocksDbConfig; -// use super::*; -// -// async fn setup() -> RocksDb { -// // Start and populate server -// let port = 9888; -// let v4_addr = SocketAddr::from(([127, 0, 0, 1], port)); -// let addrs: &[std::net::SocketAddr] = &[v4_addr]; -// let server = ServerBuilder::default().build(addrs).await.unwrap(); -// -// let mut rpc_module = RpcModule::new(()); -// -// let mut db_storage = initialize_storage(); -// populate_with_test_data(&mut db_storage); -// let db = Arc::new(db_storage); -// let storage = Storage { storage: Arc::clone(&db) }; -// -// rpc_module -// .merge(rocksdb_service::RocksDBServer::into_rpc(storage)) -// .expect("RocksDBServer error"); -// -// let _rpc_server_handle = server.start(rpc_module); -// -// // init client -// // TODO either FIX test service above or just rely on integration tests to test this, as this might be an overkill -// let rocksdb_url = format!("127.0.0.1:{}", port); -// tracing::info!("Opening client at {}", rocksdb_url); -// -// let config = RocksDbConfig { rocksdb_url }; -// -// RocksDb::new(&config).await -// } -// -// fn initialize_storage() -> RocksDBStorage { -// let temp_dir = TempDir::new().unwrap(); -// let db_path = temp_dir.path().to_str().unwrap(); -// -// RocksDBStorage::open(db_path, None, rocksdb_storage::storage::cf(), ZSTD_COMPRESSION_LEVEL).unwrap() -// } -// -// fn populate_with_test_data(storage: &mut RocksDBStorage) { -// (1..=10).for_each(|i| { -// storage -// .put_slot(&RootedSlot { -// slot: i, -// parent: None, -// }) -// .unwrap() -// }); -// } -// -// #[tokio::test] -// async fn test_get_last_rooted_slot() { -// let client = setup().await; -// let earliest_slot = client.get_earliest_rooted_slot().await.unwrap(); -// tracing::info!("Earliest rooted slot {}", earliest_slot); -// assert_eq!(earliest_slot, 1); -// -// let last_slot = client.get_latest_block().await.unwrap(); -// tracing::info!("Earliest rooted slot {}", last_slot); -// assert_eq!(last_slot, 10); -// -// let accounts = client.get_accounts(1, 12); -// println!("ACCOUNTS: {}", accounts); -// } + // use std::net::SocketAddr; + // use jsonrpsee::RpcModule; + // use jsonrpsee::server::ServerBuilder; + // use rocksdb_storage::rocksdb_structs::RootedSlot; + // use rocksdb_storage::rpc::rocksdb_service; + // use rocksdb_storage::rpc::rocksdb_service::Storage; + // use rocksdb_storage::storage::{DBStorage, RocksDBStorage, ZSTD_COMPRESSION_LEVEL}; + // use tempfile::TempDir; + // use crate::types::RocksDbConfig; + // use super::*; + // + // async fn setup() -> RocksDb { + // Start and populate server + // let rocksdb_port: u16 = 9888; + // let v4_addr = SocketAddr::from(([127, 0, 0, 1], rocksdb_port)); + // let addrs: &[std::net::SocketAddr] = &[v4_addr]; + // let server = ServerBuilder::default().ws_only().build(addrs).await.unwrap(); + // + // let mut rpc_module = RpcModule::new(()); + // + // let mut db_storage = initialize_storage(); + // populate_with_test_data(&mut db_storage); + // let db = Arc::new(db_storage); + // let storage = Storage { storage: Arc::clone(&db) }; + // + // rpc_module + // .merge(rocksdb_service::RocksDBServer::into_rpc(storage)) + // .expect("RocksDBServer error"); + // + // let _rpc_server_handle = server.start(rpc_module); + + // init client + // TODO either FIX test service above or just rely on integration tests to test this, as this might be an overkill + // let rocksdb_host = "127.0.0.1".to_owned(); + // let rocksdb_port = 9888; + // tracing::info!("Opening client at {rocksdb_host}:{rocksdb_port}"); + // + // let config = RocksDbConfig { rocksdb_host, rocksdb_port }; + // + // RocksDb::new(&config).await + // } + // + // fn initialize_storage() -> RocksDBStorage { + // let temp_dir = TempDir::new().unwrap(); + // let db_path = temp_dir.path().to_str().unwrap(); + // + // RocksDBStorage::open(db_path, None, rocksdb_storage::storage::cf(), ZSTD_COMPRESSION_LEVEL).unwrap() + // } + // + // fn populate_with_test_data(storage: &mut RocksDBStorage) { + // (1..=10).for_each(|i| { + // storage + // .put_slot(&RootedSlot { + // slot: i, + // parent: None, + // }) + // .unwrap() + // }); + // } + // + // #[tokio::test] + // async fn test_get_last_rooted_slot() { + // let client = setup().await; + // let earliest_slot = client.get_earliest_rooted_slot().await.unwrap(); + // println!("Earliest rooted slot {}", earliest_slot); + // assert_eq!(earliest_slot, 1); + // + // let last_slot = client.get_latest_block().await.unwrap(); + // println!("Latest block {}", last_slot); + // // assert_eq!(last_slot, 10); + // + // let accounts = client.get_accounts(1, 12).await.unwrap(); + // for acc in accounts { + // println!("ACCOUNT: {:?}: {:?}", acc.len(), acc); + // } + // } // } From e093d4d7a1ec776c43e973dc48c61d6b6844a04e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Jun 2024 13:02:11 +0300 Subject: [PATCH 232/318] Bump strum_macros from 0.26.2 to 0.26.4 in /evm_loader (#457) Bumps [strum_macros](https://github.com/Peternator7/strum) from 0.26.2 to 0.26.4. - [Release notes](https://github.com/Peternator7/strum/releases) - [Changelog](https://github.com/Peternator7/strum/blob/master/CHANGELOG.md) - [Commits](https://github.com/Peternator7/strum/commits) --- updated-dependencies: - dependency-name: strum_macros dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 14 ++++++++++---- evm_loader/lib/Cargo.toml | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 022bd4d40..536b6dc9f 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -2468,6 +2468,12 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -3387,7 +3393,7 @@ dependencies = [ "spl-associated-token-account", "spl-token", "strum 0.26.2", - "strum_macros 0.26.2", + "strum_macros 0.26.4", "thiserror", "tokio", "tracing", @@ -6426,11 +6432,11 @@ dependencies = [ [[package]] name = "strum_macros" -version = "0.26.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6cf59daf282c0a494ba14fd21610a0325f9f90ec9d1231dea26bcb1d696c946" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "proc-macro2", "quote", "rustversion", diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index b38e5eb0b..1e56d0c75 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -43,7 +43,7 @@ neon-lib-interface = { path = "../lib-interface" } abi_stable = "0.11.2" async-ffi = { version = "0.5.0", features = ["abi_stable"] } strum = "0.26.2" -strum_macros = "0.26.2" +strum_macros = "0.26.4" clap = "2.33.3" lazy_static = "1.4.0" elsa = "1.10.0" From 1465a18b0ae7b3284e3d1d146e6869ff6d63065b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Jun 2024 14:52:54 +0300 Subject: [PATCH 233/318] Bump hyper from 0.14.27 to 1.3.1 in /evm_loader (#463) Bumps [hyper](https://github.com/hyperium/hyper) from 0.14.27 to 1.3.1. - [Release notes](https://github.com/hyperium/hyper/releases) - [Changelog](https://github.com/hyperium/hyper/blob/master/CHANGELOG.md) - [Commits](https://github.com/hyperium/hyper/compare/v0.14.27...v1.3.1) --- updated-dependencies: - dependency-name: hyper dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 77 ++++++++++++++++++++++++++++----------- evm_loader/lib/Cargo.toml | 2 +- 2 files changed, 56 insertions(+), 23 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 536b6dc9f..c7ec8793f 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -98,7 +98,7 @@ dependencies = [ "flate2", "futures-core", "h2", - "http", + "http 0.2.9", "httparse", "httpdate", "itoa", @@ -145,7 +145,7 @@ checksum = "13d324164c51f63867b57e73ba5936ea151b8a41a1d23d1031eeb9f70d0236f8" dependencies = [ "bytestring", "cfg-if", - "http", + "http 0.2.9", "regex", "regex-lite", "serde", @@ -1236,7 +1236,7 @@ dependencies = [ "clickhouse-derive", "clickhouse-rs-cityhash-sys", "futures", - "hyper", + "hyper 0.14.29", "hyper-tls", "lz4", "sealed", @@ -2379,7 +2379,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.9", "indexmap 2.2.3", "slab", "tokio", @@ -2438,7 +2438,7 @@ dependencies = [ "base64 0.21.7", "bytes", "headers-core", - "http", + "http 0.2.9", "httpdate", "mime", "sha1", @@ -2450,7 +2450,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" dependencies = [ - "http", + "http 0.2.9", ] [[package]] @@ -2563,6 +2563,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.5" @@ -2570,10 +2581,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", - "http", + "http 0.2.9", "pin-project-lite", ] +[[package]] +name = "http-body" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +dependencies = [ + "bytes", + "http 1.1.0", +] + [[package]] name = "httparse" version = "1.8.0" @@ -2594,28 +2615,40 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.27" +version = "0.14.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +checksum = "f361cde2f109281a220d4307746cdfd5ee3f410da58a70377762396775634b33" dependencies = [ "bytes", "futures-channel", "futures-core", "futures-util", "h2", - "http", - "http-body", + "http 0.2.9", + "http-body 0.4.5", "httparse", "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.9", + "socket2 0.5.4", "tokio", "tower-service", "tracing", "want", ] +[[package]] +name = "hyper" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" +dependencies = [ + "bytes", + "http 1.1.0", + "http-body 1.0.0", + "tokio", +] + [[package]] name = "hyper-rustls" version = "0.24.1" @@ -2623,8 +2656,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" dependencies = [ "futures-util", - "http", - "hyper", + "http 0.2.9", + "hyper 0.14.29", "log", "rustls", "rustls-native-certs", @@ -2639,7 +2672,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper", + "hyper 0.14.29", "native-tls", "tokio", "tokio-native-tls", @@ -2889,7 +2922,7 @@ dependencies = [ "async-trait", "beef", "futures-util", - "hyper", + "hyper 0.14.29", "jsonrpsee-types", "serde", "serde_json", @@ -2905,7 +2938,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c13987da51270bda2c1c9b40c19be0fe9b225c7a0553963d8f17e683a50ce84" dependencies = [ "async-trait", - "hyper", + "hyper 0.14.29", "hyper-rustls", "jsonrpsee-core", "jsonrpsee-types", @@ -3373,7 +3406,7 @@ dependencies = [ "goblin 0.6.1", "hex", "hex-literal", - "hyper", + "hyper 1.3.1", "lazy_static", "log", "neon-lib-interface", @@ -4361,9 +4394,9 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", - "http-body", - "hyper", + "http 0.2.9", + "http-body 0.4.5", + "hyper 0.14.29", "hyper-rustls", "hyper-tls", "ipnet", @@ -6925,7 +6958,7 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http", + "http 0.2.9", "httparse", "log", "rand 0.8.5", diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 1e56d0c75..b0ecb107d 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" thiserror = "1.0" anyhow = "1.0" bincode = "1.3.1" -hyper = "0.14" +hyper = "1.3" evm-loader = { path = "../program", default-features = false, features = ["log", "async-trait"] } solana-sdk.workspace = true solana-client.workspace = true From b63682146d5037b94f824f164d71c0a8444597dc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 19 Jun 2024 12:05:49 +0000 Subject: [PATCH 234/318] Bump actix-web from 4.6.0 to 4.7.0 in /evm_loader Bumps [actix-web](https://github.com/actix/actix-web) from 4.6.0 to 4.7.0. - [Release notes](https://github.com/actix/actix-web/releases) - [Changelog](https://github.com/actix/actix-web/blob/master/CHANGES.md) - [Commits](https://github.com/actix/actix-web/compare/web-v4.6.0...web-v4.7.0) --- updated-dependencies: - dependency-name: actix-web dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- evm_loader/Cargo.lock | 8 ++++---- evm_loader/api/Cargo.toml | 2 +- evm_loader/rpc/Cargo.toml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index c7ec8793f..8e8af393e 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -202,9 +202,9 @@ dependencies = [ [[package]] name = "actix-web" -version = "4.6.0" +version = "4.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1cf67dadb19d7c95e5a299e2dda24193b89d5d4f33a3b9800888ede9e19aa32" +checksum = "5d6316df3fa569627c98b12557a8b6ff0674e5be4bb9b5e4ae2550ddb4964ed6" dependencies = [ "actix-codec", "actix-http", @@ -243,9 +243,9 @@ dependencies = [ [[package]] name = "actix-web-codegen" -version = "4.2.2" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb1f50ebbb30eca122b188319a4398b3f7bb4a8cdf50ecfb73bfc6a3c3ce54f5" +checksum = "f591380e2e68490b5dfaf1dd1aa0ebe78d84ba7067078512b4ea6e4492d622b8" dependencies = [ "actix-router", "proc-macro2", diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index b9625f699..60fc1e93f 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -18,7 +18,7 @@ tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } tracing-appender = "0.2.3" neon-lib = { path = "../lib" } -actix-web = "4.6.0" +actix-web = "4.7.0" actix-request-identifier = "4.2.0" hex = "0.4.2" build-info = { version = "0.0.31", features = ["serde"] } diff --git a/evm_loader/rpc/Cargo.toml b/evm_loader/rpc/Cargo.toml index 4f90a5049..dc7d7195a 100644 --- a/evm_loader/rpc/Cargo.toml +++ b/evm_loader/rpc/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -actix-web = "4.6.0" +actix-web = "4.7.0" clap = "2.33.3" jsonrpc-v2 = "0.13.0" neon-lib-interface = { path = "../lib-interface" } From 5e9dc762880589de770d4b0c7d08b0edbfcf6d61 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Wed, 19 Jun 2024 15:51:57 +0300 Subject: [PATCH 235/318] Revert "Bump hyper from 0.14.27 to 1.3.1 in /evm_loader (#463)" This reverts commit 1465a18b0ae7b3284e3d1d146e6869ff6d63065b. --- evm_loader/Cargo.lock | 77 +++++++++++---------------------------- evm_loader/lib/Cargo.toml | 2 +- 2 files changed, 23 insertions(+), 56 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 8e8af393e..4e311464e 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -98,7 +98,7 @@ dependencies = [ "flate2", "futures-core", "h2", - "http 0.2.9", + "http", "httparse", "httpdate", "itoa", @@ -145,7 +145,7 @@ checksum = "13d324164c51f63867b57e73ba5936ea151b8a41a1d23d1031eeb9f70d0236f8" dependencies = [ "bytestring", "cfg-if", - "http 0.2.9", + "http", "regex", "regex-lite", "serde", @@ -1236,7 +1236,7 @@ dependencies = [ "clickhouse-derive", "clickhouse-rs-cityhash-sys", "futures", - "hyper 0.14.29", + "hyper", "hyper-tls", "lz4", "sealed", @@ -2379,7 +2379,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http 0.2.9", + "http", "indexmap 2.2.3", "slab", "tokio", @@ -2438,7 +2438,7 @@ dependencies = [ "base64 0.21.7", "bytes", "headers-core", - "http 0.2.9", + "http", "httpdate", "mime", "sha1", @@ -2450,7 +2450,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" dependencies = [ - "http 0.2.9", + "http", ] [[package]] @@ -2563,17 +2563,6 @@ dependencies = [ "itoa", ] -[[package]] -name = "http" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - [[package]] name = "http-body" version = "0.4.5" @@ -2581,20 +2570,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", - "http 0.2.9", + "http", "pin-project-lite", ] -[[package]] -name = "http-body" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" -dependencies = [ - "bytes", - "http 1.1.0", -] - [[package]] name = "httparse" version = "1.8.0" @@ -2615,40 +2594,28 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.29" +version = "0.14.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f361cde2f109281a220d4307746cdfd5ee3f410da58a70377762396775634b33" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" dependencies = [ "bytes", "futures-channel", "futures-core", "futures-util", "h2", - "http 0.2.9", - "http-body 0.4.5", + "http", + "http-body", "httparse", "httpdate", "itoa", "pin-project-lite", - "socket2 0.5.4", + "socket2 0.4.9", "tokio", "tower-service", "tracing", "want", ] -[[package]] -name = "hyper" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" -dependencies = [ - "bytes", - "http 1.1.0", - "http-body 1.0.0", - "tokio", -] - [[package]] name = "hyper-rustls" version = "0.24.1" @@ -2656,8 +2623,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" dependencies = [ "futures-util", - "http 0.2.9", - "hyper 0.14.29", + "http", + "hyper", "log", "rustls", "rustls-native-certs", @@ -2672,7 +2639,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper 0.14.29", + "hyper", "native-tls", "tokio", "tokio-native-tls", @@ -2922,7 +2889,7 @@ dependencies = [ "async-trait", "beef", "futures-util", - "hyper 0.14.29", + "hyper", "jsonrpsee-types", "serde", "serde_json", @@ -2938,7 +2905,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c13987da51270bda2c1c9b40c19be0fe9b225c7a0553963d8f17e683a50ce84" dependencies = [ "async-trait", - "hyper 0.14.29", + "hyper", "hyper-rustls", "jsonrpsee-core", "jsonrpsee-types", @@ -3406,7 +3373,7 @@ dependencies = [ "goblin 0.6.1", "hex", "hex-literal", - "hyper 1.3.1", + "hyper", "lazy_static", "log", "neon-lib-interface", @@ -4394,9 +4361,9 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http 0.2.9", - "http-body 0.4.5", - "hyper 0.14.29", + "http", + "http-body", + "hyper", "hyper-rustls", "hyper-tls", "ipnet", @@ -6958,7 +6925,7 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http 0.2.9", + "http", "httparse", "log", "rand 0.8.5", diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index b0ecb107d..1e56d0c75 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" thiserror = "1.0" anyhow = "1.0" bincode = "1.3.1" -hyper = "1.3" +hyper = "0.14" evm-loader = { path = "../program", default-features = false, features = ["log", "async-trait"] } solana-sdk.workspace = true solana-client.workspace = true From 4ff935a6d9525e069721bf231607292f6baa8670 Mon Sep 17 00:00:00 2001 From: iguberman Date: Wed, 19 Jun 2024 08:44:04 -0500 Subject: [PATCH 236/318] add rocksdb env args --- Dockerfile | 5 + evm_loader/lib/src/types/tracer_rocks_db.rs | 152 ++++++++++---------- 2 files changed, 81 insertions(+), 76 deletions(-) diff --git a/Dockerfile b/Dockerfile index aae302ecb..a8d70d926 100644 --- a/Dockerfile +++ b/Dockerfile @@ -61,6 +61,11 @@ COPY ci/operator-keypairs/id.json /root/.config/solana/id.json COPY ci/operator-keypairs/id2.json /root/.config/solana/id2.json COPY ci/keys/ /opt/keys +ARG ROCKSDB_HOST +ARG ROCKSDB_PORT + ENV PATH=${PATH}:/opt +ENV ROCKSDB_HOST=${ROCKSDB_HOST} +ENV ROCKSDB_PORT=${ROCKSDB_PORT} ENTRYPOINT [ "/opt/solana-run-neon.sh" ] diff --git a/evm_loader/lib/src/types/tracer_rocks_db.rs b/evm_loader/lib/src/types/tracer_rocks_db.rs index 0eb123cb8..700cebf24 100644 --- a/evm_loader/lib/src/types/tracer_rocks_db.rs +++ b/evm_loader/lib/src/types/tracer_rocks_db.rs @@ -141,80 +141,80 @@ impl RocksDb { // #[cfg(test)] // mod tests { - // use std::net::SocketAddr; - // use jsonrpsee::RpcModule; - // use jsonrpsee::server::ServerBuilder; - // use rocksdb_storage::rocksdb_structs::RootedSlot; - // use rocksdb_storage::rpc::rocksdb_service; - // use rocksdb_storage::rpc::rocksdb_service::Storage; - // use rocksdb_storage::storage::{DBStorage, RocksDBStorage, ZSTD_COMPRESSION_LEVEL}; - // use tempfile::TempDir; - // use crate::types::RocksDbConfig; - // use super::*; - // - // async fn setup() -> RocksDb { - // Start and populate server - // let rocksdb_port: u16 = 9888; - // let v4_addr = SocketAddr::from(([127, 0, 0, 1], rocksdb_port)); - // let addrs: &[std::net::SocketAddr] = &[v4_addr]; - // let server = ServerBuilder::default().ws_only().build(addrs).await.unwrap(); - // - // let mut rpc_module = RpcModule::new(()); - // - // let mut db_storage = initialize_storage(); - // populate_with_test_data(&mut db_storage); - // let db = Arc::new(db_storage); - // let storage = Storage { storage: Arc::clone(&db) }; - // - // rpc_module - // .merge(rocksdb_service::RocksDBServer::into_rpc(storage)) - // .expect("RocksDBServer error"); - // - // let _rpc_server_handle = server.start(rpc_module); - - // init client - // TODO either FIX test service above or just rely on integration tests to test this, as this might be an overkill - // let rocksdb_host = "127.0.0.1".to_owned(); - // let rocksdb_port = 9888; - // tracing::info!("Opening client at {rocksdb_host}:{rocksdb_port}"); - // - // let config = RocksDbConfig { rocksdb_host, rocksdb_port }; - // - // RocksDb::new(&config).await - // } - // - // fn initialize_storage() -> RocksDBStorage { - // let temp_dir = TempDir::new().unwrap(); - // let db_path = temp_dir.path().to_str().unwrap(); - // - // RocksDBStorage::open(db_path, None, rocksdb_storage::storage::cf(), ZSTD_COMPRESSION_LEVEL).unwrap() - // } - // - // fn populate_with_test_data(storage: &mut RocksDBStorage) { - // (1..=10).for_each(|i| { - // storage - // .put_slot(&RootedSlot { - // slot: i, - // parent: None, - // }) - // .unwrap() - // }); - // } - // - // #[tokio::test] - // async fn test_get_last_rooted_slot() { - // let client = setup().await; - // let earliest_slot = client.get_earliest_rooted_slot().await.unwrap(); - // println!("Earliest rooted slot {}", earliest_slot); - // assert_eq!(earliest_slot, 1); - // - // let last_slot = client.get_latest_block().await.unwrap(); - // println!("Latest block {}", last_slot); - // // assert_eq!(last_slot, 10); - // - // let accounts = client.get_accounts(1, 12).await.unwrap(); - // for acc in accounts { - // println!("ACCOUNT: {:?}: {:?}", acc.len(), acc); - // } - // } +// use std::net::SocketAddr; +// use jsonrpsee::RpcModule; +// use jsonrpsee::server::ServerBuilder; +// use rocksdb_storage::rocksdb_structs::RootedSlot; +// use rocksdb_storage::rpc::rocksdb_service; +// use rocksdb_storage::rpc::rocksdb_service::Storage; +// use rocksdb_storage::storage::{DBStorage, RocksDBStorage, ZSTD_COMPRESSION_LEVEL}; +// use tempfile::TempDir; +// use crate::types::RocksDbConfig; +// use super::*; +// +// async fn setup() -> RocksDb { +// Start and populate server +// let rocksdb_port: u16 = 9888; +// let v4_addr = SocketAddr::from(([127, 0, 0, 1], rocksdb_port)); +// let addrs: &[std::net::SocketAddr] = &[v4_addr]; +// let server = ServerBuilder::default().ws_only().build(addrs).await.unwrap(); +// +// let mut rpc_module = RpcModule::new(()); +// +// let mut db_storage = initialize_storage(); +// populate_with_test_data(&mut db_storage); +// let db = Arc::new(db_storage); +// let storage = Storage { storage: Arc::clone(&db) }; +// +// rpc_module +// .merge(rocksdb_service::RocksDBServer::into_rpc(storage)) +// .expect("RocksDBServer error"); +// +// let _rpc_server_handle = server.start(rpc_module); + +// init client +// TODO either FIX test service above or just rely on integration tests to test this, as this might be an overkill +// let rocksdb_host = "127.0.0.1".to_owned(); +// let rocksdb_port = 9888; +// tracing::info!("Opening client at {rocksdb_host}:{rocksdb_port}"); +// +// let config = RocksDbConfig { rocksdb_host, rocksdb_port }; +// +// RocksDb::new(&config).await +// } +// +// fn initialize_storage() -> RocksDBStorage { +// let temp_dir = TempDir::new().unwrap(); +// let db_path = temp_dir.path().to_str().unwrap(); +// +// RocksDBStorage::open(db_path, None, rocksdb_storage::storage::cf(), ZSTD_COMPRESSION_LEVEL).unwrap() +// } +// +// fn populate_with_test_data(storage: &mut RocksDBStorage) { +// (1..=10).for_each(|i| { +// storage +// .put_slot(&RootedSlot { +// slot: i, +// parent: None, +// }) +// .unwrap() +// }); +// } +// +// #[tokio::test] +// async fn test_get_last_rooted_slot() { +// let client = setup().await; +// let earliest_slot = client.get_earliest_rooted_slot().await.unwrap(); +// println!("Earliest rooted slot {}", earliest_slot); +// assert_eq!(earliest_slot, 1); +// +// let last_slot = client.get_latest_block().await.unwrap(); +// println!("Latest block {}", last_slot); +// // assert_eq!(last_slot, 10); +// +// let accounts = client.get_accounts(1, 12).await.unwrap(); +// for acc in accounts { +// println!("ACCOUNT: {:?}: {:?}", acc.len(), acc); +// } +// } // } From 6c255a301356e9a1c919797e1362c48a6c229f45 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Wed, 19 Jun 2024 16:52:50 +0300 Subject: [PATCH 237/318] Add transaction origin to `get_holder` response (#462) --- evm_loader/lib/src/commands/get_holder.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/evm_loader/lib/src/commands/get_holder.rs b/evm_loader/lib/src/commands/get_holder.rs index 054c8efa3..dc6c24ec2 100644 --- a/evm_loader/lib/src/commands/get_holder.rs +++ b/evm_loader/lib/src/commands/get_holder.rs @@ -1,9 +1,12 @@ -use evm_loader::account::{ - legacy::{ - LegacyFinalizedData, LegacyHolderData, TAG_HOLDER_DEPRECATED, - TAG_STATE_FINALIZED_DEPRECATED, +use evm_loader::{ + account::{ + legacy::{ + LegacyFinalizedData, LegacyHolderData, TAG_HOLDER_DEPRECATED, + TAG_STATE_FINALIZED_DEPRECATED, + }, + Holder, StateAccount, StateFinalizedAccount, TAG_HOLDER, TAG_STATE, TAG_STATE_FINALIZED, }, - Holder, StateAccount, StateFinalizedAccount, TAG_HOLDER, TAG_STATE, TAG_STATE_FINALIZED, + types::Address, }; use serde::{Deserialize, Serialize}; use solana_sdk::{account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey}; @@ -43,6 +46,7 @@ pub struct GetHolderResponse { #[serde_as(as = "Option")] pub tx: Option<[u8; 32]>, pub chain_id: Option, + pub origin: Option
, #[serde_as(as = "Option>")] pub accounts: Option>, @@ -121,6 +125,7 @@ pub fn read_holder(program_id: &Pubkey, info: AccountInfo) -> NeonResult Date: Wed, 19 Jun 2024 11:39:05 -0500 Subject: [PATCH 238/318] Make load_db_config_from_environment() public --- evm_loader/lib/src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm_loader/lib/src/config.rs b/evm_loader/lib/src/config.rs index 6db4216e2..17fe2bff1 100644 --- a/evm_loader/lib/src/config.rs +++ b/evm_loader/lib/src/config.rs @@ -78,7 +78,7 @@ pub fn load_api_config_from_environment() -> APIOptions { } } -fn load_db_config_from_environment() -> RocksDbConfig { +pub fn load_db_config_from_environment() -> RocksDbConfig { let rocksdb_host = env::var("ROCKSDB_HOST") .as_deref() .unwrap_or("127.0.0.1") From 079e6ec1f89e7edfd9ebc69805edd69212fee7ee Mon Sep 17 00:00:00 2001 From: iguberman Date: Fri, 21 Jun 2024 01:29:46 -0500 Subject: [PATCH 239/318] Improve loggigng + attempt to use reconnecting_jsonrpsee_ws_client commented out due to dependency conflict with zeroize. --- evm_loader/lib/Cargo.toml | 3 ++- evm_loader/lib/src/types/tracer_rocks_db.rs | 30 ++++++++++++++++----- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 7f3c3a3e3..203c155f3 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -50,7 +50,8 @@ clap = "2.33.3" lazy_static = "1.4.0" elsa = "1.10.0" arrayref = "0.3.6" -#rocksdb = "0.22.0" +# TODO revisit as this causes zeroize version conflict +#reconnecting-jsonrpsee-ws-client = "0.4.2" [dev-dependencies] hex-literal = "0.4.1" diff --git a/evm_loader/lib/src/types/tracer_rocks_db.rs b/evm_loader/lib/src/types/tracer_rocks_db.rs index 700cebf24..33196e7af 100644 --- a/evm_loader/lib/src/types/tracer_rocks_db.rs +++ b/evm_loader/lib/src/types/tracer_rocks_db.rs @@ -5,6 +5,8 @@ use jsonrpsee::ws_client::{WsClient, WsClientBuilder}; use serde_json::{from_slice, from_str}; use std::str::FromStr; use std::sync::Arc; +// use std::time::Duration; + pub type RocksDbResult = std::result::Result; use solana_sdk::signature::Signature; use solana_sdk::{ @@ -23,6 +25,8 @@ pub struct AccountParams { use crate::types::tracer_ch_common::{EthSyncStatus, RevisionMap}; use crate::types::RocksDbConfig; +// use reconnecting_jsonrpsee_ws_client::{Client, CallRetryPolicy, rpc_params, ExponentialBackoff}; + #[derive(Clone)] pub struct RocksDb { pub url: String, @@ -36,6 +40,11 @@ impl RocksDb { let port = &config.rocksdb_port; let url = format!("ws://{host}:{port}"); + // match Client::builder() + // .retry_policy( + // ExponentialBackoff::from_millis(100) + // .max_delay(Duration::from_secs(10)) + // .take(3),) match WsClientBuilder::default().build(&url).await { Ok(client) => { let arc_c = Arc::new(client); @@ -51,7 +60,11 @@ impl RocksDb { .client .request("get_block_time", rpc_params![slot]) .await?; - tracing::info!("response: {:?}", response); + tracing::info!( + "get_block_time for slot {:?} response: {:?}", + slot, + response + ); Ok(i64::from_str(response.as_str())?) } pub async fn get_earliest_rooted_slot(&self) -> RocksDbResult { @@ -59,7 +72,7 @@ impl RocksDb { .client .request("get_earliest_rooted_slot", rpc_params![]) .await?; - tracing::info!("response: {:?}", response); + tracing::info!("get_earliest_rooted_slot response: {:?}", response); Ok(u64::from_str(response.as_str())?) } @@ -68,7 +81,7 @@ impl RocksDb { .client .request("get_last_rooted_slot", rpc_params![]) .await?; - tracing::info!("response: {:?}", response); + tracing::info!("get_latest_block response: {:?}", response); Ok(u64::from_str(response.as_str())?) } @@ -82,9 +95,12 @@ impl RocksDb { let response: String = self .client - .request("get_account", rpc_params![pubkey, slot, tx_index_in_block]) + .request( + "get_account", + rpc_params![pubkey.to_owned(), slot, tx_index_in_block], + ) .await?; - tracing::info!("response: {:?}", response); + tracing::info!("get_account_at response: {:?}", response); if let Some(account) = from_str(response.as_str())? { Ok(Some(account)) @@ -98,7 +114,7 @@ impl RocksDb { .client .request("get_transaction_index", rpc_params![signature]) .await?; - tracing::info!("response: {:?}", response); + tracing::info!("get_transaction_index response: {:?}", response); Ok(u64::from_str(response.as_str())?) } @@ -107,7 +123,7 @@ impl RocksDb { .client .request("get_accounts", rpc_params![start, end]) .await?; - tracing::info!("response: {:?}", response); + tracing::info!("get_accounts response: {:?}", response); let accounts: Vec> = from_slice((response).as_ref()).unwrap(); Ok(accounts) } From 2988a528196a41db532c382620214d022fb903fa Mon Sep 17 00:00:00 2001 From: Vladimir Bugaev Date: Fri, 21 Jun 2024 19:23:46 +0700 Subject: [PATCH 240/318] get holder status fix (#469) --- evm_loader/lib/src/commands/get_holder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm_loader/lib/src/commands/get_holder.rs b/evm_loader/lib/src/commands/get_holder.rs index dc6c24ec2..399a6eb36 100644 --- a/evm_loader/lib/src/commands/get_holder.rs +++ b/evm_loader/lib/src/commands/get_holder.rs @@ -16,7 +16,7 @@ use crate::{account_storage::account_info, rpc::Rpc, NeonResult}; use serde_with::{hex::Hex, serde_as, skip_serializing_none, DisplayFromStr}; -#[derive(Debug, Default, Serialize, Deserialize)] +#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq, Clone)] pub enum Status { #[default] Empty, From 2c77fbac6716418c8e8b47cdd5ea48f671e15011 Mon Sep 17 00:00:00 2001 From: iguberman Date: Mon, 24 Jun 2024 01:23:14 -0500 Subject: [PATCH 241/318] Fix get_transaction_index parameter --- evm_loader/lib/src/types/tracer_rocks_db.rs | 160 ++++++++++++-------- 1 file changed, 93 insertions(+), 67 deletions(-) diff --git a/evm_loader/lib/src/types/tracer_rocks_db.rs b/evm_loader/lib/src/types/tracer_rocks_db.rs index 33196e7af..4c2e07919 100644 --- a/evm_loader/lib/src/types/tracer_rocks_db.rs +++ b/evm_loader/lib/src/types/tracer_rocks_db.rs @@ -5,7 +5,6 @@ use jsonrpsee::ws_client::{WsClient, WsClientBuilder}; use serde_json::{from_slice, from_str}; use std::str::FromStr; use std::sync::Arc; -// use std::time::Duration; pub type RocksDbResult = std::result::Result; use solana_sdk::signature::Signature; @@ -110,11 +109,12 @@ impl RocksDb { } pub async fn get_transaction_index(&self, signature: Signature) -> RocksDbResult { + let signature_str = format!("{:?}", signature); let response: String = self .client - .request("get_transaction_index", rpc_params![signature]) + .request("get_transaction_index", rpc_params![signature_str]) .await?; - tracing::info!("get_transaction_index response: {:?}", response); + println!("get_transaction_index response: {:?}", response); Ok(u64::from_str(response.as_str())?) } @@ -157,80 +157,106 @@ impl RocksDb { // #[cfg(test)] // mod tests { -// use std::net::SocketAddr; -// use jsonrpsee::RpcModule; -// use jsonrpsee::server::ServerBuilder; -// use rocksdb_storage::rocksdb_structs::RootedSlot; -// use rocksdb_storage::rpc::rocksdb_service; -// use rocksdb_storage::rpc::rocksdb_service::Storage; -// use rocksdb_storage::storage::{DBStorage, RocksDBStorage, ZSTD_COMPRESSION_LEVEL}; -// use tempfile::TempDir; -// use crate::types::RocksDbConfig; -// use super::*; +// use super::*; +// use crate::types::RocksDbConfig; +// use solana_sdk::signature::Signature; +// // use jsonrpsee::server::ServerBuilder; +// // use jsonrpsee::RpcModule; +// // use rocksdb_storage::rocksdb_structs::RootedSlot; +// // use rocksdb_storage::rpc::rocksdb_service; +// // use rocksdb_storage::rpc::rocksdb_service::Storage; +// // use rocksdb_storage::storage::{DBStorage, RocksDBStorage, ZSTD_COMPRESSION_LEVEL}; +// // use std::net::SocketAddr; +// // use tempfile::TempDir; // -// async fn setup() -> RocksDb { -// Start and populate server -// let rocksdb_port: u16 = 9888; -// let v4_addr = SocketAddr::from(([127, 0, 0, 1], rocksdb_port)); -// let addrs: &[std::net::SocketAddr] = &[v4_addr]; -// let server = ServerBuilder::default().ws_only().build(addrs).await.unwrap(); +// async fn setup() -> RocksDb { +// // Start and populate server +// // let rocksdb_port: u16 = 9888; +// // let v4_addr = SocketAddr::from(([127, 0, 0, 1], rocksdb_port)); +// // let addrs: &[std::net::SocketAddr] = &[v4_addr]; +// // let server = ServerBuilder::default() +// // .ws_only() +// // .build(addrs) +// // .await +// // .unwrap(); +// // +// // let mut rpc_module = RpcModule::new(()); +// // +// // let mut db_storage = initialize_storage(); +// // populate_with_test_data(&mut db_storage); +// // let db = Arc::new(db_storage); +// // let storage = Storage { +// // storage: Arc::clone(&db), +// // }; +// // +// // rpc_module +// // .merge(rocksdb_service::RocksDBServer::into_rpc(storage)) +// // .expect("RocksDBServer error"); +// //// +// // let _rpc_server_handle = server.start(rpc_module); // -// let mut rpc_module = RpcModule::new(()); +// // init client +// // TODO either FIX test service above or just rely on integration tests to test this, as this might be an overkill +// let rocksdb_host = "127.0.0.1".to_owned(); +// let rocksdb_port = 9888; +// tracing::info!("Opening client at {rocksdb_host}:{rocksdb_port}"); // -// let mut db_storage = initialize_storage(); -// populate_with_test_data(&mut db_storage); -// let db = Arc::new(db_storage); -// let storage = Storage { storage: Arc::clone(&db) }; +// let config = RocksDbConfig { +// rocksdb_host, +// rocksdb_port, +// }; // -// rpc_module -// .merge(rocksdb_service::RocksDBServer::into_rpc(storage)) -// .expect("RocksDBServer error"); -// -// let _rpc_server_handle = server.start(rpc_module); - -// init client -// TODO either FIX test service above or just rely on integration tests to test this, as this might be an overkill -// let rocksdb_host = "127.0.0.1".to_owned(); -// let rocksdb_port = 9888; -// tracing::info!("Opening client at {rocksdb_host}:{rocksdb_port}"); -// -// let config = RocksDbConfig { rocksdb_host, rocksdb_port }; +// RocksDb::new(&config).await +// } // -// RocksDb::new(&config).await -// } +// // fn initialize_storage() -> RocksDBStorage { +// // let temp_dir = TempDir::new().unwrap(); +// // let db_path = temp_dir.path().to_str().unwrap(); +// // +// // RocksDBStorage::open( +// // db_path, +// // None, +// // rocksdb_storage::storage::cf(), +// // ZSTD_COMPRESSION_LEVEL, +// // ) +// // .unwrap() +// // } // -// fn initialize_storage() -> RocksDBStorage { -// let temp_dir = TempDir::new().unwrap(); -// let db_path = temp_dir.path().to_str().unwrap(); +// // fn populate_with_test_data(storage: &mut RocksDBStorage) { +// // (1..=10).for_each(|i| { +// // storage +// // .put_slot(&RootedSlot { +// // slot: i, +// // parent: None, +// // }) +// // .unwrap() +// // }); +// // } // -// RocksDBStorage::open(db_path, None, rocksdb_storage::storage::cf(), ZSTD_COMPRESSION_LEVEL).unwrap() -// } +// #[tokio::test] +// async fn test_get_last_rooted_slot() { +// let client = setup().await; // -// fn populate_with_test_data(storage: &mut RocksDBStorage) { -// (1..=10).for_each(|i| { -// storage -// .put_slot(&RootedSlot { -// slot: i, -// parent: None, -// }) -// .unwrap() -// }); -// } +// let earliest_slot = client.get_earliest_rooted_slot().await.unwrap(); +// println!("Earliest rooted slot {}", earliest_slot); +// assert_eq!(earliest_slot, 1); // -// #[tokio::test] -// async fn test_get_last_rooted_slot() { -// let client = setup().await; -// let earliest_slot = client.get_earliest_rooted_slot().await.unwrap(); -// println!("Earliest rooted slot {}", earliest_slot); -// assert_eq!(earliest_slot, 1); +// let last_slot = client.get_latest_block().await.unwrap(); +// println!("Latest block {}", last_slot); +// // assert_eq!(last_slot, 10); // -// let last_slot = client.get_latest_block().await.unwrap(); -// println!("Latest block {}", last_slot); -// // assert_eq!(last_slot, 10); +// let accounts = client.get_accounts(1, 12).await.unwrap(); +// for acc in accounts { +// println!("ACCOUNT: {:?}: {:?}", acc.len(), acc); +// } +// } // -// let accounts = client.get_accounts(1, 12).await.unwrap(); -// for acc in accounts { -// println!("ACCOUNT: {:?}: {:?}", acc.len(), acc); +// #[tokio::test] +// async fn test_get_transaction_index() { +// let client = setup().await; +// let signature_str = "5B4wxum51mVN2rp9XQMvF7yUErJhsMTtAyjKbzx4thASxqJFpZgJjkqZ36VKAMa1vnvKwRNsCSo2WnA9qWrmiQHW".to_string(); +// let signature = Signature::from_str(&signature_str).unwrap(); +// let index = client.get_transaction_index(signature).await.unwrap(); +// assert_eq!(index, 101); // } // } -// } From b79780e8e3d900a89637f1caa3330097575b51c5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Jun 2024 09:55:35 +0300 Subject: [PATCH 242/318] Bump actix-web from 4.7.0 to 4.8.0 in /evm_loader (#468) Bumps [actix-web](https://github.com/actix/actix-web) from 4.7.0 to 4.8.0. - [Release notes](https://github.com/actix/actix-web/releases) - [Changelog](https://github.com/actix/actix-web/blob/master/CHANGES.md) - [Commits](https://github.com/actix/actix-web/compare/web-v4.7.0...web-v4.8.0) --- updated-dependencies: - dependency-name: actix-web dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- evm_loader/api/Cargo.toml | 2 +- evm_loader/rpc/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 4e311464e..06f344e24 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -202,9 +202,9 @@ dependencies = [ [[package]] name = "actix-web" -version = "4.7.0" +version = "4.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6316df3fa569627c98b12557a8b6ff0674e5be4bb9b5e4ae2550ddb4964ed6" +checksum = "1988c02af8d2b718c05bc4aeb6a66395b7cdf32858c2c71131e5637a8c05a9ff" dependencies = [ "actix-codec", "actix-http", diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 60fc1e93f..61eabce91 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -18,7 +18,7 @@ tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } tracing-appender = "0.2.3" neon-lib = { path = "../lib" } -actix-web = "4.7.0" +actix-web = "4.8.0" actix-request-identifier = "4.2.0" hex = "0.4.2" build-info = { version = "0.0.31", features = ["serde"] } diff --git a/evm_loader/rpc/Cargo.toml b/evm_loader/rpc/Cargo.toml index dc7d7195a..ae0789de6 100644 --- a/evm_loader/rpc/Cargo.toml +++ b/evm_loader/rpc/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -actix-web = "4.7.0" +actix-web = "4.8.0" clap = "2.33.3" jsonrpc-v2 = "0.13.0" neon-lib-interface = { path = "../lib-interface" } From 38693ddff132dc3d0878a92708b5c3f59c89cb52 Mon Sep 17 00:00:00 2001 From: iguberman Date: Mon, 24 Jun 2024 14:03:04 -0500 Subject: [PATCH 243/318] Fix get_slot_by_blockhash --- evm_loader/lib/src/types/tracer_rocks_db.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/evm_loader/lib/src/types/tracer_rocks_db.rs b/evm_loader/lib/src/types/tracer_rocks_db.rs index 4c2e07919..0502eef44 100644 --- a/evm_loader/lib/src/types/tracer_rocks_db.rs +++ b/evm_loader/lib/src/types/tracer_rocks_db.rs @@ -141,7 +141,7 @@ impl RocksDb { Ok(env!("NEON_REVISION").to_string()) } - pub async fn get_slot_by_blockhash(&self, blockhash: &str) -> RocksDbResult { + pub async fn get_slot_by_blockhash(&self, blockhash: String) -> RocksDbResult { let response: String = self .client .request("get_slot_by_blockhash", rpc_params![blockhash]) @@ -252,6 +252,14 @@ impl RocksDb { // } // // #[tokio::test] +// async fn test_get_slot_by_blockhash() { +// let client = setup().await; +// // let block = client.get_block(8).await.unwrap(); +// let slot8 = client.get_slot_by_blockhash("8HfsUf5H5RcZGENqEfFccrBCtWYC6uGYAQvNkZiEHqCU".to_string()).await.unwrap(); +// assert_eq!(slot8, 8); +// } +// +// #[tokio::test] // async fn test_get_transaction_index() { // let client = setup().await; // let signature_str = "5B4wxum51mVN2rp9XQMvF7yUErJhsMTtAyjKbzx4thASxqJFpZgJjkqZ36VKAMa1vnvKwRNsCSo2WnA9qWrmiQHW".to_string(); From d8f3e9db9513c36356a84d6c311b513e6c9eb739 Mon Sep 17 00:00:00 2001 From: iguberman Date: Tue, 25 Jun 2024 00:33:44 -0500 Subject: [PATCH 244/318] Fix fix get_account_by --- evm_loader/lib/src/types/tracer_rocks_db.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/evm_loader/lib/src/types/tracer_rocks_db.rs b/evm_loader/lib/src/types/tracer_rocks_db.rs index 0502eef44..4e9b25f23 100644 --- a/evm_loader/lib/src/types/tracer_rocks_db.rs +++ b/evm_loader/lib/src/types/tracer_rocks_db.rs @@ -90,13 +90,11 @@ impl RocksDb { slot: u64, tx_index_in_block: Option, ) -> RocksDbResult> { - // let ap: AccountParams = AccountParams { pubkey: *pubkey, slot, tx_index_in_block }; - let response: String = self .client .request( "get_account", - rpc_params![pubkey.to_owned(), slot, tx_index_in_block], + rpc_params![pubkey.to_string(), slot, tx_index_in_block], ) .await?; tracing::info!("get_account_at response: {:?}", response); @@ -249,6 +247,12 @@ impl RocksDb { // for acc in accounts { // println!("ACCOUNT: {:?}: {:?}", acc.len(), acc); // } +// +// let pubkey_bytes : Vec = (1..=32).collect(); +// let pubkey = Pubkey::try_from(pubkey_bytes.as_slice()).unwrap(); +// +// let acc = client.get_account_at(&pubkey, 10, None).await.unwrap().unwrap(); +// println!("ACCOUNT: {acc:?}"); // } // // #[tokio::test] From bdd152dbd0c0302b6e38a75d751996066ce821c2 Mon Sep 17 00:00:00 2001 From: s-medvedev <40623263+s-medvedev@users.noreply.github.com> Date: Tue, 25 Jun 2024 13:43:51 +0700 Subject: [PATCH 245/318] SLA-95 Fix gas estimation when trx include wSOL transfer (#472) Co-authored-by: Semen Medvedev --- evm_loader/lib/src/account_storage.rs | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index 3602ea282..c5e0d1c20 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -837,6 +837,7 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { let mut lamports_spend = 0u64; for (_, used_account) in self.used_accounts.clone().into_tuple_vec() { let used_account = used_account.borrow(); + let pubkey = used_account.pubkey; if let Some(lamports_after_upgrade) = used_account.lamports_after_upgrade { let orig_lamports = self .accounts_cache @@ -844,6 +845,7 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { .unwrap_or(&None) .as_ref() .map_or(0, |v| v.lamports); + debug!("Upgrade rent: {pubkey} {orig_lamports} -> {lamports_after_upgrade}"); if lamports_after_upgrade > orig_lamports { lamports_spend += lamports_after_upgrade - orig_lamports; } else { @@ -851,12 +853,17 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { } } } + debug!( + "Upgrade rent: {lamports_spend} - {lamports_collected} = {}", + lamports_spend.saturating_sub(lamports_collected) + ); Ok(lamports_spend.saturating_sub(lamports_collected)) } pub fn get_regular_rent(&self) -> evm_loader::error::Result { let accounts = self.accounts.clone(); - let mut changes_in_rent = 0u64; + let mut old_lamports_sum = 0u64; + let mut new_lamports_sum = 0u64; for (pubkey, account) in &accounts.into_map() { if *pubkey == system_program::ID { continue; @@ -881,14 +888,16 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { return Err(ProgramError::AccountNotRentExempt.into()); } - if let Some(lamports_after_upgrade) = lamports_after_upgrade { - changes_in_rent += new_lamports.saturating_sub(lamports_after_upgrade); - info!("Changes in rent: {pubkey} {original_lamports} -> {lamports_after_upgrade} -> {new_lamports} | {original_size} -> {new_size}"); - } else { - changes_in_rent += new_lamports.saturating_sub(original_lamports); - info!("Changes in rent: {pubkey} {original_lamports} -> {new_lamports} | {original_size} -> {new_size}"); - } + let old_lamports = lamports_after_upgrade.unwrap_or(original_lamports); + old_lamports_sum += old_lamports; + new_lamports_sum += new_lamports; + + #[allow(clippy::cast_possible_wrap)] + let diff = new_lamports as i64 - old_lamports as i64; + debug!("Changes in rent: {pubkey} {old_lamports} -> {new_lamports} = {diff} | {original_size} -> {new_size} {lamports_after_upgrade:?}"); } + let changes_in_rent = new_lamports_sum.saturating_sub(old_lamports_sum); + info!("Changes in rent: {changes_in_rent} = {new_lamports_sum} - {old_lamports_sum}"); Ok(changes_in_rent) } From f14053263282948c4dea86cd40cfd158daee7783 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Tue, 25 Jun 2024 11:47:11 +0300 Subject: [PATCH 246/318] Return entire transaction from `get_holder` request (#473) --- evm_loader/lib/src/commands/get_holder.rs | 14 ++++++++++---- evm_loader/lib/src/types/mod.rs | 16 ++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/evm_loader/lib/src/commands/get_holder.rs b/evm_loader/lib/src/commands/get_holder.rs index 399a6eb36..bc2c4d092 100644 --- a/evm_loader/lib/src/commands/get_holder.rs +++ b/evm_loader/lib/src/commands/get_holder.rs @@ -12,7 +12,7 @@ use serde::{Deserialize, Serialize}; use solana_sdk::{account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey}; use std::fmt::Display; -use crate::{account_storage::account_info, rpc::Rpc, NeonResult}; +use crate::{account_storage::account_info, rpc::Rpc, types::TxParams, NeonResult}; use serde_with::{hex::Hex, serde_as, skip_serializing_none, DisplayFromStr}; @@ -45,6 +45,7 @@ pub struct GetHolderResponse { #[serde_as(as = "Option")] pub tx: Option<[u8; 32]>, + pub tx_data: Option, pub chain_id: Option, pub origin: Option
, @@ -119,13 +120,18 @@ pub fn read_holder(program_id: &Pubkey, info: AccountInfo) -> NeonResult Self { + Self { + from: origin, + to: tx.target(), + nonce: Some(tx.nonce()), + data: Some(tx.call_data().to_vec()), + value: Some(tx.value()), + gas_limit: Some(tx.gas_limit()), + gas_price: Some(tx.gas_price()), + chain_id: tx.chain_id(), + access_list: None, + actual_gas_used: None, + } + } } impl std::fmt::Debug for TxParams { From 8b6233e5909311882bb0f97a2142366b1c936dc6 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Tue, 25 Jun 2024 11:47:36 +0300 Subject: [PATCH 247/318] Add logs when iterative transaction resets (#475) --- evm_loader/program/src/instruction/transaction_step.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/evm_loader/program/src/instruction/transaction_step.rs b/evm_loader/program/src/instruction/transaction_step.rs index d0bfea5d7..f58f66f0e 100644 --- a/evm_loader/program/src/instruction/transaction_step.rs +++ b/evm_loader/program/src/instruction/transaction_step.rs @@ -76,6 +76,8 @@ pub fn do_continue<'a>( let account_storage = ProgramAccountStorage::new(accounts)?; let (mut backend, mut evm) = if reset { + log_data(&[b"RESET"]); + storage.reset_steps_executed(); let mut backend = ExecutorState::new(&account_storage); From 49b354c370aa57f563998990c477b3daf006f51d Mon Sep 17 00:00:00 2001 From: Evgeny Zdanovich Date: Thu, 27 Jun 2024 16:41:03 +0200 Subject: [PATCH 248/318] Introduce Rollup feature - a neon evm with bigger heap. (#471) * Introduce new feature for the rollup. Set bigger heap size for the build with rollup feature (should be deployed only to the forked solana that supports it). * Add a separate config for the NeonEVM on the rollup. * Add the rollup build in the Dockerfile. --- Dockerfile | 1 + evm_loader/program/Cargo.toml | 2 + evm_loader/program/config/rollup.toml | 57 +++++++++++++++++++ evm_loader/program/src/allocator.rs | 9 ++- evm_loader/program/src/config.rs | 5 +- .../src/instruction/config_get_environment.rs | 2 + 6 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 evm_loader/program/config/rollup.toml diff --git a/Dockerfile b/Dockerfile index 62716af14..d1e42ca8b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -26,6 +26,7 @@ RUN cargo fmt --check && \ cargo build-bpf --manifest-path program/Cargo.toml --features govertest,emergency && cp target/deploy/evm_loader.so target/deploy/evm_loader-govertest-emergency.so && \ cargo build-bpf --manifest-path program/Cargo.toml --features mainnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-mainnet.so && \ cargo build-bpf --manifest-path program/Cargo.toml --features mainnet,emergency && cp target/deploy/evm_loader.so target/deploy/evm_loader-mainnet-emergency.so && \ + cargo build-bpf --manifest-path program/Cargo.toml --features rollup && cp target/deploy/evm_loader.so target/deploy/evm_loader-rollup.so && \ cargo build-bpf --manifest-path program/Cargo.toml --features ci --dump diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index d6d131fd8..69036c155 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -20,6 +20,8 @@ testnet = [] devnet = [] ## Builds NeonEVM for CI environment ci = [] +## Builds NeonEVM for rollup deployment with settings adjusted. +rollup = [] ## Builds NeonEVM program for `emergency` mode. In this mode, NeonEVM doesn't process ## any transaction and return error `ProgramError::InvalidInstructionData` with comment diff --git a/evm_loader/program/config/rollup.toml b/evm_loader/program/config/rollup.toml new file mode 100644 index 000000000..93bf2290d --- /dev/null +++ b/evm_loader/program/config/rollup.toml @@ -0,0 +1,57 @@ +program_id = "EgbRZxFRQTiZpQGinE5jT6KQq5jtVnjtLdSTkW5UTcAv" +operators_whitelist = [ + "2Gsipy7yniskehFAccTp4ShhmdTiP8UsLWVFdxsG6ZGt", + "2fx77qnumM3sw5duzMYod8c8xSLavE4RwJAdNdeYZpFq", + "2wMN3y81BXQmcyihHrByDChop6qnF1UX5f4vAp8DYjVd", + "32U3DCL5gDNqqgfHsXuVnyJSnN6WympgBuR8TThXD2FR", + "3HXb2SsmQSaZ3MyB6g2b1BCtL8e7DcUwBjDRAytbiVrP", + "3tsPHg5cKnJok5N9W911QFmyb8iqSaKP4fKFqXjBciCF", + "4Pe48zv2qQRswyioywD6Ym21YvF9u57zo5cbLJDpSJnC", + "4hsUEQrpJiFo2gfNEaZoPKvVcgWDeWWCtUNWYCHfgiMd", + "5283XRV4NsMyyLoGcQWMMEY89eB8FgRw7VgzSKqqepCf", + "63tpScHzNbjQAi1AgkF6jJ1qtGjVq7aB8yLT4CJm8LvE", + "6C5nNpaV6mot83Lh7rtMpYUVFfUAVHH6nmpC96mRh8dp", + "7WCfs1Xe6F7M3ZwGu9BjVFhBcThrBZv2wtQ5CgvnWS54", + "7ikHZa3j4xD6s9DKpTpAxAoe4uG9NMkty5CCmU4p3iWp", + "7sU2USEHu7wkJFLJXza3bgCNwzFN3nddDhUeVoFiXV4Y", + "8BRoxMVsQYjpX137ptnH1kqx6vHLk2C9QQZ7hWhPwzAC", + "8hdWEvE5zqv3LAZ5io1M4mFW55w9frmowEEnnmbaFTsK", + "8xzLMMVwChuFo4XZAZqsz5HtVqHTcSu7CJqogebaw3nU", + "9DdU1ufgfe5Z7EZFuJragvkfysn4FBXto9LFMmiWCsF", + "9EaJPCqHcJvDtJTkAQWqeLj97FQpiNZiqq49hTxM3B35", + "9JY641aUoEMPzEUng6NpSfejg8A4hKk7YQxUo6f3R744", + "9Ro3VV9kaBj7p21XzQB3LJQfznZkkr3t7qziWKZVbKuU", + "ABfwv3nHL6b5ogrc3LBbUDnfYrc1JGUX2DDYG4njxGhH", + "AD3trvWBkUYoE4kBLyTP7o2Ej8aiyCFgD8Ctoi4Tejoz", + "ANprCKGACpkSByqyQQw2J4YEq1U68ouzx49vinAug5kH", + "As2d7rKDnw2R366tvz7FuL57T2X1y8mVyHEuVwXBA6iQ", + "BPPwRf4Stpecjr1YyxsBDSsEnHhPM87dcbmJLMxCfNKV", + "BcVupnAtrZXQ5SCyGa8g7BWwT9uD3TMv5e5sEqejay1", + "Bkf59SXA5ziH4jmjKU5nZB3SZoXAVXBT2znkiotR7bcR", + "BsXm9NVHDyqmzVB9eUHmDXWJX7M5qxcxfxqQiXxWgX9u", + "CjepUsoZ39xjtsMaF2mjV27AKAMMQ2AXbY6naWxLfEb6", + "CsWCnfXuibRmz6QM6HNqh5agLshMZV1utMrBPCRhcpZk", + "CzdHFcdazNAbJoKJeJWH9fJPNP2sbdSztQgrxs94u6Ps", + "D9iXY6KVBJtddGCd3fghMw8ik5jEet1rVR2bmTeKDJrC", + "DQzhkXK6DLYTbAXMFdZf3PeNX8o6nLJpHb526S7KjqXL", + "DhorUW7jUiFTeDTSZvp5F3e22nEBQWg6Pf411366SmtG", + "DpdcebJnjPHwMkzDconJi95o7MDQ2kY1e1Lqwk4k9fyE", + "EW5b5UG5Wp6dL5qvvqV9aJTYN7xYis429f7yU16gezPG", + "EaNNJzeyGpcQXAv43JHFkLQD3sKxHL7s3JAbsyJEvtwp", + "EoqWxp9iCzo1VGs6C6awGLrmz5hQCRKeumg4NpciQCiA", + "F2KvM8yD2epCjmh6dgzfUs1RNZ1nZV4Jbcufupq1Ex5r", + "F4NJurNwkT7pcdvsNgCwHyJWghwBEcRiab2796QFsMG6", + "FCzSWq6W4DZzqsXHVD85Ugt3WRtqspT2ZVxEphuD3Ege", + "FNvRosMS9PtEUiyGZNg6gjbw7u77wc14C8P44aRj9vKr", + "FSW7SmbZ8aqbJXgeg3SMC93ZvauGnmVmyGxgoucXqP7a", + "GdcR94SPum5uT4iDqp19GmjNtLZaxHWb4Ex1rDFK6Jjo", + "H9Nx2pc4eXNTXjiz8x1Sah9WD1SHzeF7u2yUdZuwmDTm", + "HKpXxXf2LDPdcuiEjDVnRMZHXXXCcbW8RmQHByGzHVgE", + "HX5Lv4XzTr4BVbmDM6t5UTxEKpjS4icrEFTufrdAygZC", + "Hd4Yt22xxanJbf4bDwdgyQrXFGEFrGKfQpTzK1isrbTS", + "HjSQ3GLiGF1mEXx92FQiXG67qQfaNQF7QZbstHYEouZe", +] + +[chain.neon] +id = 245022929 +token = "9ChfzoAfqGcrnK9c7cqQwd6MGrFqxA22Q9vLsS75hDzj" diff --git a/evm_loader/program/src/allocator.rs b/evm_loader/program/src/allocator.rs index a67bfa847..bcf0f8170 100644 --- a/evm_loader/program/src/allocator.rs +++ b/evm_loader/program/src/allocator.rs @@ -8,7 +8,14 @@ use linked_list_allocator::Heap; use solana_program::entrypoint::HEAP_START_ADDRESS; use static_assertions::{const_assert, const_assert_eq}; -const HEAP_SIZE: usize = 256 * 1024; +cfg_if::cfg_if! { + if #[cfg(feature = "rollup")] { + // NeonEVM under rollup is intended to be deployed with a forked version of Solana that supports such bigger heap. + const HEAP_SIZE: usize = 1024 * 1024; + } else { + const HEAP_SIZE: usize = 256 * 1024; + } +} #[allow(clippy::cast_possible_truncation)] // HEAP_START_ADDRESS < usize::max const EVM_HEAP_START_ADDRESS: usize = HEAP_START_ADDRESS as usize; diff --git a/evm_loader/program/src/config.rs b/evm_loader/program/src/config.rs index 96b9edeaa..16bd44256 100644 --- a/evm_loader/program/src/config.rs +++ b/evm_loader/program/src/config.rs @@ -13,7 +13,10 @@ cfg_if! { net_specific_config_parser!("config/devnet.toml"); } else if #[cfg(feature = "govertest")] { net_specific_config_parser!("config/govertest.toml"); - } else { + } else if #[cfg(feature = "rollup")] { + net_specific_config_parser!("config/rollup.toml"); + } + else { net_specific_config_parser!("config/default.toml"); } } diff --git a/evm_loader/program/src/instruction/config_get_environment.rs b/evm_loader/program/src/instruction/config_get_environment.rs index 8a9e08074..cddb1edcd 100644 --- a/evm_loader/program/src/instruction/config_get_environment.rs +++ b/evm_loader/program/src/instruction/config_get_environment.rs @@ -19,6 +19,8 @@ pub fn process<'a>( "govertest" } else if cfg!(feature = "ci") { "ci" + } else if cfg!(feature = "rollup") { + "rollup" } else { "unknown" }; From ed9dfb18cd4aecf3ee864271ae82b2c2a4fb8a20 Mon Sep 17 00:00:00 2001 From: iguberman Date: Thu, 27 Jun 2024 19:41:24 -0500 Subject: [PATCH 249/318] Add some debug logs and Send solana structs Pubkey/Signature from rpc client instead of String --- evm_loader/Cargo.lock | 4 +- evm_loader/lib/Cargo.toml | 2 +- evm_loader/lib/src/rpc/db_call_client.rs | 4 + evm_loader/lib/src/rpc/emulator_client.rs | 4 + evm_loader/lib/src/solana_simulator/mod.rs | 3 + evm_loader/lib/src/types/tracer_rocks_db.rs | 129 +------------------- 6 files changed, 17 insertions(+), 129 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 1e554812c..ebf79a961 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -761,9 +761,9 @@ dependencies = [ [[package]] name = "blake3" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87" +checksum = "30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52" dependencies = [ "arrayref", "arrayvec", diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 203c155f3..a3fb07787 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -55,7 +55,7 @@ arrayref = "0.3.6" [dev-dependencies] hex-literal = "0.4.1" -#rocksdb_storage = { git = "ssh://git@github.com/neonlabsorg/geyser-neon-filter.git", branch = "NDEV-3050_RocksDbClient" } + [build-dependencies] build-info-build = "0.0.31" diff --git a/evm_loader/lib/src/rpc/db_call_client.rs b/evm_loader/lib/src/rpc/db_call_client.rs index eac3dc99a..302a654c5 100644 --- a/evm_loader/lib/src/rpc/db_call_client.rs +++ b/evm_loader/lib/src/rpc/db_call_client.rs @@ -12,6 +12,7 @@ use solana_sdk::{ clock::{Slot, UnixTimestamp}, pubkey::Pubkey, }; +use tracing::debug; pub struct CallDbClient { tracer_db: TracerDb, @@ -62,6 +63,9 @@ impl Rpc for CallDbClient { for key in pubkeys { result.push(self.get_account_at(key).await?); } + + debug!("db_call_client.get_multiple_accounts result: {result:?}"); + Ok(result) } diff --git a/evm_loader/lib/src/rpc/emulator_client.rs b/evm_loader/lib/src/rpc/emulator_client.rs index 11f6822b9..63d247c3a 100644 --- a/evm_loader/lib/src/rpc/emulator_client.rs +++ b/evm_loader/lib/src/rpc/emulator_client.rs @@ -6,6 +6,7 @@ use solana_sdk::{ clock::{Slot, UnixTimestamp}, pubkey::Pubkey, }; +use tracing::debug; use crate::account_storage::{fake_operator, EmulatorAccountStorage}; @@ -56,6 +57,7 @@ impl<'rpc, T: Rpc> Rpc for EmulatorAccountStorage<'rpc, T> { let response = self._get_multiple_accounts_from_rpc(&missing_keys).await?; + debug!("emulator_client.get_multiple_accounts response: {response:?}"); let mut j = 0_usize; for i in 0..pubkeys.len() { if exists[i] { @@ -68,6 +70,8 @@ impl<'rpc, T: Rpc> Rpc for EmulatorAccountStorage<'rpc, T> { j += 1; } + debug!("emulator_client.get_multiple_accounts accounts: {accounts:?}"); + Ok(accounts) } diff --git a/evm_loader/lib/src/solana_simulator/mod.rs b/evm_loader/lib/src/solana_simulator/mod.rs index ea431a323..049a9f5a2 100644 --- a/evm_loader/lib/src/solana_simulator/mod.rs +++ b/evm_loader/lib/src/solana_simulator/mod.rs @@ -18,6 +18,7 @@ use solana_sdk::{ MessageHash, SanitizedTransaction, TransactionVerificationMode, VersionedTransaction, }, }; +use tracing::debug; use crate::rpc::Rpc; @@ -91,6 +92,8 @@ impl SolanaSimulator { let mut programdata_keys = vec![]; + debug!("SYNC_ACCOUNTS: {keys:?}"); + let mut accounts = rpc.get_multiple_accounts(keys).await?; for (key, account) in keys.iter().zip(&mut accounts) { let Some(account) = account else { diff --git a/evm_loader/lib/src/types/tracer_rocks_db.rs b/evm_loader/lib/src/types/tracer_rocks_db.rs index 4e9b25f23..2ed01f3e4 100644 --- a/evm_loader/lib/src/types/tracer_rocks_db.rs +++ b/evm_loader/lib/src/types/tracer_rocks_db.rs @@ -66,6 +66,7 @@ impl RocksDb { ); Ok(i64::from_str(response.as_str())?) } + pub async fn get_earliest_rooted_slot(&self) -> RocksDbResult { let response: String = self .client @@ -92,10 +93,7 @@ impl RocksDb { ) -> RocksDbResult> { let response: String = self .client - .request( - "get_account", - rpc_params![pubkey.to_string(), slot, tx_index_in_block], - ) + .request("get_account", rpc_params![pubkey, slot, tx_index_in_block]) .await?; tracing::info!("get_account_at response: {:?}", response); @@ -107,10 +105,9 @@ impl RocksDb { } pub async fn get_transaction_index(&self, signature: Signature) -> RocksDbResult { - let signature_str = format!("{:?}", signature); let response: String = self .client - .request("get_transaction_index", rpc_params![signature_str]) + .request("get_transaction_index", rpc_params![signature]) .await?; println!("get_transaction_index response: {:?}", response); Ok(u64::from_str(response.as_str())?) @@ -152,123 +149,3 @@ impl RocksDb { Ok(EthSyncStatus::new(None)) } } - -// #[cfg(test)] -// mod tests { -// use super::*; -// use crate::types::RocksDbConfig; -// use solana_sdk::signature::Signature; -// // use jsonrpsee::server::ServerBuilder; -// // use jsonrpsee::RpcModule; -// // use rocksdb_storage::rocksdb_structs::RootedSlot; -// // use rocksdb_storage::rpc::rocksdb_service; -// // use rocksdb_storage::rpc::rocksdb_service::Storage; -// // use rocksdb_storage::storage::{DBStorage, RocksDBStorage, ZSTD_COMPRESSION_LEVEL}; -// // use std::net::SocketAddr; -// // use tempfile::TempDir; -// -// async fn setup() -> RocksDb { -// // Start and populate server -// // let rocksdb_port: u16 = 9888; -// // let v4_addr = SocketAddr::from(([127, 0, 0, 1], rocksdb_port)); -// // let addrs: &[std::net::SocketAddr] = &[v4_addr]; -// // let server = ServerBuilder::default() -// // .ws_only() -// // .build(addrs) -// // .await -// // .unwrap(); -// // -// // let mut rpc_module = RpcModule::new(()); -// // -// // let mut db_storage = initialize_storage(); -// // populate_with_test_data(&mut db_storage); -// // let db = Arc::new(db_storage); -// // let storage = Storage { -// // storage: Arc::clone(&db), -// // }; -// // -// // rpc_module -// // .merge(rocksdb_service::RocksDBServer::into_rpc(storage)) -// // .expect("RocksDBServer error"); -// //// -// // let _rpc_server_handle = server.start(rpc_module); -// -// // init client -// // TODO either FIX test service above or just rely on integration tests to test this, as this might be an overkill -// let rocksdb_host = "127.0.0.1".to_owned(); -// let rocksdb_port = 9888; -// tracing::info!("Opening client at {rocksdb_host}:{rocksdb_port}"); -// -// let config = RocksDbConfig { -// rocksdb_host, -// rocksdb_port, -// }; -// -// RocksDb::new(&config).await -// } -// -// // fn initialize_storage() -> RocksDBStorage { -// // let temp_dir = TempDir::new().unwrap(); -// // let db_path = temp_dir.path().to_str().unwrap(); -// // -// // RocksDBStorage::open( -// // db_path, -// // None, -// // rocksdb_storage::storage::cf(), -// // ZSTD_COMPRESSION_LEVEL, -// // ) -// // .unwrap() -// // } -// -// // fn populate_with_test_data(storage: &mut RocksDBStorage) { -// // (1..=10).for_each(|i| { -// // storage -// // .put_slot(&RootedSlot { -// // slot: i, -// // parent: None, -// // }) -// // .unwrap() -// // }); -// // } -// -// #[tokio::test] -// async fn test_get_last_rooted_slot() { -// let client = setup().await; -// -// let earliest_slot = client.get_earliest_rooted_slot().await.unwrap(); -// println!("Earliest rooted slot {}", earliest_slot); -// assert_eq!(earliest_slot, 1); -// -// let last_slot = client.get_latest_block().await.unwrap(); -// println!("Latest block {}", last_slot); -// // assert_eq!(last_slot, 10); -// -// let accounts = client.get_accounts(1, 12).await.unwrap(); -// for acc in accounts { -// println!("ACCOUNT: {:?}: {:?}", acc.len(), acc); -// } -// -// let pubkey_bytes : Vec = (1..=32).collect(); -// let pubkey = Pubkey::try_from(pubkey_bytes.as_slice()).unwrap(); -// -// let acc = client.get_account_at(&pubkey, 10, None).await.unwrap().unwrap(); -// println!("ACCOUNT: {acc:?}"); -// } -// -// #[tokio::test] -// async fn test_get_slot_by_blockhash() { -// let client = setup().await; -// // let block = client.get_block(8).await.unwrap(); -// let slot8 = client.get_slot_by_blockhash("8HfsUf5H5RcZGENqEfFccrBCtWYC6uGYAQvNkZiEHqCU".to_string()).await.unwrap(); -// assert_eq!(slot8, 8); -// } -// -// #[tokio::test] -// async fn test_get_transaction_index() { -// let client = setup().await; -// let signature_str = "5B4wxum51mVN2rp9XQMvF7yUErJhsMTtAyjKbzx4thASxqJFpZgJjkqZ36VKAMa1vnvKwRNsCSo2WnA9qWrmiQHW".to_string(); -// let signature = Signature::from_str(&signature_str).unwrap(); -// let index = client.get_transaction_index(signature).await.unwrap(); -// assert_eq!(index, 101); -// } -// } From d7a1643250fb5bc93a61079b9a974c90a9608977 Mon Sep 17 00:00:00 2001 From: iguberman Date: Fri, 28 Jun 2024 01:33:25 -0500 Subject: [PATCH 250/318] Send Pubkey as rpc param instead of &Pubkey --- evm_loader/lib/src/types/tracer_rocks_db.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/evm_loader/lib/src/types/tracer_rocks_db.rs b/evm_loader/lib/src/types/tracer_rocks_db.rs index 2ed01f3e4..d14ee94e3 100644 --- a/evm_loader/lib/src/types/tracer_rocks_db.rs +++ b/evm_loader/lib/src/types/tracer_rocks_db.rs @@ -1,3 +1,4 @@ +use abi_stable::traits::IntoOwned; use jsonrpsee::core::client::ClientT; use jsonrpsee::core::Serialize; use jsonrpsee::rpc_params; @@ -13,6 +14,7 @@ use solana_sdk::{ clock::{Slot, UnixTimestamp}, pubkey::Pubkey, }; +use tracing::info; #[derive(Clone, Serialize)] pub struct AccountParams { @@ -91,11 +93,16 @@ impl RocksDb { slot: u64, tx_index_in_block: Option, ) -> RocksDbResult> { + info!("get_account_at {pubkey:?}, slot: {slot:?}, tx_index: {tx_index_in_block:?}"); + let response: String = self .client - .request("get_account", rpc_params![pubkey, slot, tx_index_in_block]) + .request( + "get_account", + rpc_params![pubkey.into_owned(), slot, tx_index_in_block], + ) .await?; - tracing::info!("get_account_at response: {:?}", response); + info!("get_account_at response: {:?}", response); if let Some(account) = from_str(response.as_str())? { Ok(Some(account)) From a138d80f1833e1250dbe3f0729370a6b132aacb8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2024 12:06:11 +0300 Subject: [PATCH 251/318] Bump lazy_static from 1.4.0 to 1.5.0 in /evm_loader (#470) Bumps [lazy_static](https://github.com/rust-lang-nursery/lazy-static.rs) from 1.4.0 to 1.5.0. - [Release notes](https://github.com/rust-lang-nursery/lazy-static.rs/releases) - [Commits](https://github.com/rust-lang-nursery/lazy-static.rs/compare/1.4.0...1.5.0) --- updated-dependencies: - dependency-name: lazy_static dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- evm_loader/lib/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 06f344e24..1dbf5c7f9 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -2948,9 +2948,9 @@ checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 1e56d0c75..e2017bc96 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -45,7 +45,7 @@ async-ffi = { version = "0.5.0", features = ["abi_stable"] } strum = "0.26.2" strum_macros = "0.26.4" clap = "2.33.3" -lazy_static = "1.4.0" +lazy_static = "1.5.0" elsa = "1.10.0" arrayref = "0.3.6" From 6794e1ea88a8e1573114a7c83fdb0090a6be8fb0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Jul 2024 13:41:15 +0300 Subject: [PATCH 252/318] Bump build-info-build from 0.0.31 to 0.0.37 in /evm_loader (#477) Bumps [build-info-build](https://github.com/danielschemmel/build-info) from 0.0.31 to 0.0.37. - [Commits](https://github.com/danielschemmel/build-info/compare/v0.0.31...v0.0.37) --- updated-dependencies: - dependency-name: build-info-build dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 62 +++++++++++--------------------- evm_loader/api/Cargo.toml | 4 +-- evm_loader/cli/Cargo.toml | 4 +-- evm_loader/lib/Cargo.toml | 4 +-- evm_loader/rpc-client/Cargo.toml | 5 ++- evm_loader/rpc/Cargo.toml | 4 +-- 6 files changed, 33 insertions(+), 50 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 1dbf5c7f9..1b1d9b9b8 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -947,41 +947,40 @@ dependencies = [ [[package]] name = "build-info" -version = "0.0.31" +version = "0.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b301350c1c448e35b896f32b68c49c8ecd969a71978fbafc4ebd09ec3f4eee2" +checksum = "8164a6499aae6b0085e6da8fa528c4b0c37fcb1ed3cc00e175e9f98005807ffc" dependencies = [ + "bincode", "build-info-common", "build-info-proc", - "once_cell", ] [[package]] name = "build-info-build" -version = "0.0.31" +version = "0.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b314717755dd6a06fc11ad3f7909ba4c0ae2ab516f5cb0404fe924c71bfc7d0" +checksum = "9da85beeeebafe621669220862ddd8e08ac741a56d171e2ab11cb8a16544d1e6" dependencies = [ "anyhow", - "base64 0.21.7", + "base64 0.22.1", "bincode", "build-info-common", "cargo_metadata", "chrono", "git2", "glob", - "once_cell", "pretty_assertions", "rustc_version", "serde_json", - "xz2", + "zstd 0.13.0", ] [[package]] name = "build-info-common" -version = "0.0.31" +version = "0.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e040d36472d40ec9424c36a7b54be589072e605596b6f20b0c56c5230b460cc" +checksum = "8e049ed5c6d1f7cb5d2ee6838b9a284a1a20b9c17c9504eae08253f428af2eaa" dependencies = [ "chrono", "derive_more", @@ -991,12 +990,12 @@ dependencies = [ [[package]] name = "build-info-proc" -version = "0.0.31" +version = "0.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffd5f241ddd417436c48d35da9869480891449ddd1ae3fd483bbcfbae741a422" +checksum = "3d6be54b4df52147ae16dd43edf11990c1e628b25eaa8ed77a9b708c390f7963" dependencies = [ "anyhow", - "base64 0.21.7", + "base64 0.22.1", "bincode", "build-info-common", "chrono", @@ -1007,7 +1006,7 @@ dependencies = [ "quote", "serde_json", "syn 2.0.66", - "xz2", + "zstd 0.13.0", ] [[package]] @@ -1124,9 +1123,9 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.15.4" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" dependencies = [ "camino", "cargo-platform", @@ -2329,11 +2328,11 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "git2" -version = "0.17.2" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b989d6a7ca95a362cf2cfc5ad688b3a467be1f87e480b8dad07fee8c79b0044" +checksum = "b903b73e45dc0c6c596f2d37eccece7c1c8bb6e4407b001096387c63d0d93724" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.0", "libc", "libgit2-sys", "log", @@ -2960,9 +2959,9 @@ checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libgit2-sys" -version = "0.15.2+1.6.4" +version = "0.17.0+1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a80df2e11fb4a61f4ba2ab42dbe7f74468da143f1a75c74e11dee7c813f694fa" +checksum = "10472326a8a6477c3c20a64547b0059e4b0d086869eee31e6d7da728a8eb7224" dependencies = [ "cc", "libc", @@ -3135,17 +3134,6 @@ dependencies = [ "libc", ] -[[package]] -name = "lzma-sys" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - [[package]] name = "matchers" version = "0.1.0" @@ -3438,6 +3426,7 @@ version = "0.1.0" dependencies = [ "async-trait", "build-info", + "build-info-build", "jsonrpsee-core", "jsonrpsee-http-client", "jsonrpsee-types", @@ -7591,15 +7580,6 @@ dependencies = [ "libc", ] -[[package]] -name = "xz2" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2" -dependencies = [ - "lzma-sys", -] - [[package]] name = "yansi" version = "0.5.1" diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 61eabce91..6cd3a7a6a 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -21,7 +21,7 @@ neon-lib = { path = "../lib" } actix-web = "4.8.0" actix-request-identifier = "4.2.0" hex = "0.4.2" -build-info = { version = "0.0.31", features = ["serde"] } +build-info = "0.0.37" [build-dependencies] -build-info-build = "0.0.31" +build-info-build = "0.0.37" diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index 16e9ed4ae..064f660a5 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -20,7 +20,7 @@ fern = "0.6" ethnum = { version = "1.5", default-features = false, features = ["serde"] } tokio = { version = "1", features = ["full"] } neon-lib = { path = "../lib" } -build-info = { version = "0.0.31", features = ["serde"] } +build-info = "0.0.37" [build-dependencies] -build-info-build = "0.0.31" +build-info-build = "0.0.37" diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index e2017bc96..c4679cb7a 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -36,7 +36,7 @@ tokio = { version = "1", features = ["full"] } clickhouse = "0.11.6" tracing = "0.1" async-trait = "0.1.80" -build-info = { version = "0.0.31", features = ["serde"] } +build-info = "0.0.37" enum_dispatch = "0.3.13" web3 = "0.19.0" neon-lib-interface = { path = "../lib-interface" } @@ -53,7 +53,7 @@ arrayref = "0.3.6" hex-literal = "0.4.1" [build-dependencies] -build-info-build = "0.0.31" +build-info-build = "0.0.37" [lib] crate-type = ["cdylib", "lib"] diff --git a/evm_loader/rpc-client/Cargo.toml b/evm_loader/rpc-client/Cargo.toml index 2923cb505..752c3c212 100644 --- a/evm_loader/rpc-client/Cargo.toml +++ b/evm_loader/rpc-client/Cargo.toml @@ -15,4 +15,7 @@ jsonrpsee-core = "0.22.3" jsonrpsee-http-client = "0.22.3" jsonrpsee-types = "0.22.3" tokio = { version = "1", features = ["full"] } -build-info = { version = "0.0.31", features = ["serde"] } +build-info = "0.0.37" + +[build-dependencies] +build-info-build = "0.0.37" diff --git a/evm_loader/rpc/Cargo.toml b/evm_loader/rpc/Cargo.toml index ae0789de6..9d0b9d0bb 100644 --- a/evm_loader/rpc/Cargo.toml +++ b/evm_loader/rpc/Cargo.toml @@ -15,11 +15,11 @@ semver = "1.0.23" serde = "1.0.203" serde_json = "1.0.117" tokio = { version = "1", features = ["full"] } -build-info = { version = "0.0.31", features = ["serde"] } +build-info = "0.0.37" thiserror = "1.0" tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } tracing-appender = "0.2.3" [build-dependencies] -build-info-build = "0.0.31" +build-info-build = "0.0.37" From 49abb257ef6996a7b770f677ca8d33c8fb10b83d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Jul 2024 21:17:43 +0300 Subject: [PATCH 253/318] Bump serde_bytes from 0.11.14 to 0.11.15 in /evm_loader (#478) Bumps [serde_bytes](https://github.com/serde-rs/bytes) from 0.11.14 to 0.11.15. - [Release notes](https://github.com/serde-rs/bytes/releases) - [Commits](https://github.com/serde-rs/bytes/compare/0.11.14...0.11.15) --- updated-dependencies: - dependency-name: serde_bytes dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- evm_loader/program/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 1b1d9b9b8..b0c0b678d 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -4688,9 +4688,9 @@ dependencies = [ [[package]] name = "serde_bytes" -version = "0.11.14" +version = "0.11.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" dependencies = [ "serde", ] diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 69036c155..4f62d6f43 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -51,7 +51,7 @@ rlp = "0.5" static_assertions = "1" borsh = "0.10" bincode = "1" -serde_bytes = "0.11.14" +serde_bytes = "0.11.15" serde = { version = "1.0.203", default-features = false, features = ["derive", "rc"] } ethnum = { version = "1.5", default-features = false, features = ["serde"] } cfg-if = { version = "1.0" } From 2a2ab073b67b3142efbafc44c576fc9085dfe6ee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Jul 2024 11:37:23 +0300 Subject: [PATCH 254/318] Bump serde_with from 3.8.1 to 3.8.2 in /evm_loader (#479) Bumps [serde_with](https://github.com/jonasbb/serde_with) from 3.8.1 to 3.8.2. - [Release notes](https://github.com/jonasbb/serde_with/releases) - [Commits](https://github.com/jonasbb/serde_with/compare/v3.8.1...v3.8.2) --- updated-dependencies: - dependency-name: serde_with dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 50 ++++++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index b0c0b678d..e742e7d0a 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -1670,6 +1670,16 @@ dependencies = [ "rusticata-macros", ] +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + [[package]] name = "derivation-path" version = "0.2.0" @@ -3369,7 +3379,7 @@ dependencies = [ "scroll", "serde", "serde_json", - "serde_with 3.8.1", + "serde_with 3.8.2", "solana-account-decoder", "solana-accounts-db", "solana-cli", @@ -3527,6 +3537,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-derive" version = "0.3.3" @@ -3928,6 +3944,12 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31114a898e107c51bb1609ffaf55a0e011cf6a4d7f1170d0015a165082c0338b" +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -4762,9 +4784,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.8.1" +version = "3.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad483d2ab0149d5a5ebcd9972a3852711e0153d863bf5a5d0391d28883c4a20" +checksum = "079f3a42cd87588d924ed95b533f8d30a483388c4e400ab736a7058e34f16169" dependencies = [ "base64 0.22.1", "chrono", @@ -4774,7 +4796,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "serde_with_macros 3.8.1", + "serde_with_macros 3.8.2", "time", ] @@ -4792,9 +4814,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.8.1" +version = "3.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65569b702f41443e8bc8bbb1c5779bd0450bbe723b56198980e80ec45780bce2" +checksum = "bc03aad67c1d26b7de277d51c86892e7d9a0110a2fe44bf6b26cc569fba302d6" dependencies = [ "darling", "proc-macro2", @@ -6569,11 +6591,14 @@ dependencies = [ [[package]] name = "time" -version = "0.3.20" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ + "deranged", "itoa", + "num-conv", + "powerfmt", "serde", "time-core", "time-macros", @@ -6581,16 +6606,17 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.8" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ + "num-conv", "time-core", ] From bed1c2bd2326a2ec1d9d32f65a0af575c861aaf2 Mon Sep 17 00:00:00 2001 From: iguberman Date: Thu, 4 Jul 2024 00:43:25 -0500 Subject: [PATCH 255/318] Fix get_account_at response logging --- evm_loader/lib/src/types/tracer_rocks_db.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/evm_loader/lib/src/types/tracer_rocks_db.rs b/evm_loader/lib/src/types/tracer_rocks_db.rs index d14ee94e3..e4227501e 100644 --- a/evm_loader/lib/src/types/tracer_rocks_db.rs +++ b/evm_loader/lib/src/types/tracer_rocks_db.rs @@ -102,13 +102,10 @@ impl RocksDb { rpc_params![pubkey.into_owned(), slot, tx_index_in_block], ) .await?; - info!("get_account_at response: {:?}", response); - if let Some(account) = from_str(response.as_str())? { - Ok(Some(account)) - } else { - Ok(None) - } + let account = from_str::(response.as_str())?; + info!("Got Account by {pubkey:?}: owner: {:?} lamports: {:?} executable: {:?} rent_epoch: {:?}", account.owner, account.lamports, account.executable, account.rent_epoch); + Ok(Some(account)) } pub async fn get_transaction_index(&self, signature: Signature) -> RocksDbResult { From fb9fff0b36d2ca438f9bf3fe670abf9ecf81e083 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Jul 2024 09:47:36 +0300 Subject: [PATCH 256/318] Bump serde_json from 1.0.117 to 1.0.120 in /evm_loader (#481) Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.117 to 1.0.120. - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.117...v1.0.120) --- updated-dependencies: - dependency-name: serde_json dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- evm_loader/api/Cargo.toml | 2 +- evm_loader/cli/Cargo.toml | 2 +- evm_loader/lib-interface/Cargo.toml | 2 +- evm_loader/program/Cargo.toml | 2 +- evm_loader/rpc-client/Cargo.toml | 2 +- evm_loader/rpc/Cargo.toml | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index e742e7d0a..5d7d57a60 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -4741,9 +4741,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" dependencies = [ "indexmap 2.2.3", "itoa", diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 6cd3a7a6a..8c579316c 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -11,7 +11,7 @@ evm-loader = { path = "../program", default-features = false, features = ["log"] solana-sdk.workspace = true solana-client.workspace = true serde = "1.0.203" -serde_json = { version = "1.0.117", features = ["preserve_order"] } +serde_json = { version = "1.0.120", features = ["preserve_order"] } ethnum = { version = "1.5", default-features = false, features = ["serde"] } tokio = { version = "1", features = ["full"] } tracing = "0.1" diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index 064f660a5..ec849aae1 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -14,7 +14,7 @@ solana-clap-utils.workspace = true solana-cli-config.workspace = true hex = "0.4.2" serde = "1.0.203" -serde_json = { version = "1.0.117", features = ["preserve_order"] } +serde_json = { version = "1.0.120", features = ["preserve_order"] } log = "0.4.21" fern = "0.6" ethnum = { version = "1.5", default-features = false, features = ["serde"] } diff --git a/evm_loader/lib-interface/Cargo.toml b/evm_loader/lib-interface/Cargo.toml index b8889e67a..505439105 100644 --- a/evm_loader/lib-interface/Cargo.toml +++ b/evm_loader/lib-interface/Cargo.toml @@ -10,4 +10,4 @@ abi_stable = "0.11.1" thiserror = "1" async-ffi = { version = "0.5.0", features = ["abi_stable"] } serde = "1.0.203" -serde_json = "1.0.117" +serde_json = "1.0.120" diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 4f62d6f43..4bc6c8589 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -65,7 +65,7 @@ features = ["is_sync"] [dev-dependencies] tokio = { version = "1.0", features = ["full"] } -serde_json = { version = "1.0.117", features = ["preserve_order"] } +serde_json = { version = "1.0.120", features = ["preserve_order"] } solana-sdk.workspace = true diff --git a/evm_loader/rpc-client/Cargo.toml b/evm_loader/rpc-client/Cargo.toml index 752c3c212..b716179f5 100644 --- a/evm_loader/rpc-client/Cargo.toml +++ b/evm_loader/rpc-client/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] serde = "1.0.203" -serde_json = "1.0.117" +serde_json = "1.0.120" neon-lib = { path = "../lib" } thiserror = "1.0.61" async-trait = "0.1.80" diff --git a/evm_loader/rpc/Cargo.toml b/evm_loader/rpc/Cargo.toml index 9d0b9d0bb..c07ae1d27 100644 --- a/evm_loader/rpc/Cargo.toml +++ b/evm_loader/rpc/Cargo.toml @@ -13,7 +13,7 @@ neon-lib-interface = { path = "../lib-interface" } neon-lib = { path = "../lib" } semver = "1.0.23" serde = "1.0.203" -serde_json = "1.0.117" +serde_json = "1.0.120" tokio = { version = "1", features = ["full"] } build-info = "0.0.37" thiserror = "1.0" From 48b57207b93cc933497d8bbf9a7fcd9cb464b0eb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 5 Jul 2024 14:12:38 +0300 Subject: [PATCH 257/318] Bump strum from 0.26.2 to 0.26.3 in /evm_loader (#482) Bumps [strum](https://github.com/Peternator7/strum) from 0.26.2 to 0.26.3. - [Release notes](https://github.com/Peternator7/strum/releases) - [Changelog](https://github.com/Peternator7/strum/blob/master/CHANGELOG.md) - [Commits](https://github.com/Peternator7/strum/compare/v0.26.2...v0.26.3) --- updated-dependencies: - dependency-name: strum dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 6 +++--- evm_loader/lib/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 5d7d57a60..d58b2556d 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -3390,7 +3390,7 @@ dependencies = [ "solana-sdk", "spl-associated-token-account", "spl-token", - "strum 0.26.2", + "strum 0.26.3", "strum_macros 0.26.4", "thiserror", "tokio", @@ -6424,9 +6424,9 @@ dependencies = [ [[package]] name = "strum" -version = "0.26.2" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" [[package]] name = "strum_macros" diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index c4679cb7a..18508982b 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -42,7 +42,7 @@ web3 = "0.19.0" neon-lib-interface = { path = "../lib-interface" } abi_stable = "0.11.2" async-ffi = { version = "0.5.0", features = ["abi_stable"] } -strum = "0.26.2" +strum = "0.26.3" strum_macros = "0.26.4" clap = "2.33.3" lazy_static = "1.5.0" From a7984f2cfdd434b4ecfc605f12d028104f63e758 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Jul 2024 10:03:09 +0100 Subject: [PATCH 258/318] Bump proc-macro2 from 1.0.85 to 1.0.86 in /evm_loader (#484) Bumps [proc-macro2](https://github.com/dtolnay/proc-macro2) from 1.0.85 to 1.0.86. - [Release notes](https://github.com/dtolnay/proc-macro2/releases) - [Commits](https://github.com/dtolnay/proc-macro2/compare/1.0.85...1.0.86) --- updated-dependencies: - dependency-name: proc-macro2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index d58b2556d..be206a5df 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -4030,9 +4030,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.85" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] From 9560f6c5c30121310f4ac9edacbd1493e2760642 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Jul 2024 09:42:33 +0100 Subject: [PATCH 259/318] Bump syn from 2.0.66 to 2.0.70 in /evm_loader (#487) Bumps [syn](https://github.com/dtolnay/syn) from 2.0.66 to 2.0.70. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.66...2.0.70) --- updated-dependencies: - dependency-name: syn dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 78 +++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index be206a5df..a45de1f89 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -123,7 +123,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -250,7 +250,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -631,7 +631,7 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -1005,7 +1005,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.66", + "syn 2.0.70", "zstd 0.13.0", ] @@ -1048,7 +1048,7 @@ checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -1575,7 +1575,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -1592,7 +1592,7 @@ checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -1616,7 +1616,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -1627,7 +1627,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -1809,7 +1809,7 @@ checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -1900,7 +1900,7 @@ checksum = "eecf8589574ce9b895052fa12d69af7a233f99e6107f5cb8dd1044f2a17bfdcb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -1912,7 +1912,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -2051,7 +2051,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.66", + "syn 2.0.70", "toml 0.8.2", ] @@ -2226,7 +2226,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -3161,7 +3161,7 @@ checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -3562,7 +3562,7 @@ checksum = "cfb77679af88f8b125209d354a202862602672222e7f2313fdd6dc349bad4712" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -3644,7 +3644,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -3656,7 +3656,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -3718,7 +3718,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -3888,7 +3888,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -4054,7 +4054,7 @@ checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -4725,7 +4725,7 @@ checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -4809,7 +4809,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -4821,7 +4821,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -5422,7 +5422,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -5891,7 +5891,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -6217,7 +6217,7 @@ checksum = "fadbefec4f3c678215ca72bd71862697bb06b41fd77c0088902dd3203354387b" dependencies = [ "quote", "spl-discriminator-syn", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -6229,7 +6229,7 @@ dependencies = [ "proc-macro2", "quote", "sha2 0.10.8", - "syn 2.0.66", + "syn 2.0.70", "thiserror", ] @@ -6277,7 +6277,7 @@ dependencies = [ "proc-macro2", "quote", "sha2 0.10.8", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -6451,7 +6451,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -6479,9 +6479,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.66" +version = "2.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16" dependencies = [ "proc-macro2", "quote", @@ -6570,7 +6570,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -6691,7 +6691,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -6868,7 +6868,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -7171,7 +7171,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.70", "wasm-bindgen-shared", ] @@ -7205,7 +7205,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.70", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -7638,7 +7638,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] @@ -7658,7 +7658,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.70", ] [[package]] From 006c1ad789f63550759dcac6c32248baa4aed8a0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jul 2024 11:29:55 +0100 Subject: [PATCH 260/318] Bump serde_with from 3.8.2 to 3.8.3 in /evm_loader (#490) Bumps [serde_with](https://github.com/jonasbb/serde_with) from 3.8.2 to 3.8.3. - [Release notes](https://github.com/jonasbb/serde_with/releases) - [Commits](https://github.com/jonasbb/serde_with/compare/v3.8.2...v3.8.3) --- updated-dependencies: - dependency-name: serde_with dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index a45de1f89..02f560eff 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -3379,7 +3379,7 @@ dependencies = [ "scroll", "serde", "serde_json", - "serde_with 3.8.2", + "serde_with 3.8.3", "solana-account-decoder", "solana-accounts-db", "solana-cli", @@ -4784,9 +4784,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.8.2" +version = "3.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "079f3a42cd87588d924ed95b533f8d30a483388c4e400ab736a7058e34f16169" +checksum = "e73139bc5ec2d45e6c5fd85be5a46949c1c39a4c18e56915f5eb4c12f975e377" dependencies = [ "base64 0.22.1", "chrono", @@ -4796,7 +4796,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "serde_with_macros 3.8.2", + "serde_with_macros 3.8.3", "time", ] @@ -4814,9 +4814,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.8.2" +version = "3.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc03aad67c1d26b7de277d51c86892e7d9a0110a2fe44bf6b26cc569fba302d6" +checksum = "b80d3d6b56b64335c0180e5ffde23b3c5e08c14c585b51a15bd0e95393f46703" dependencies = [ "darling", "proc-macro2", From 1391011aa9ae12bc12d02267fe9fe10977a332e7 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Thu, 11 Jul 2024 21:15:04 +0700 Subject: [PATCH 261/318] Fix tests: return None if slot not found by blockhash --- evm_loader/lib/src/types/tracer_rocks_db.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evm_loader/lib/src/types/tracer_rocks_db.rs b/evm_loader/lib/src/types/tracer_rocks_db.rs index e4227501e..3e265cc00 100644 --- a/evm_loader/lib/src/types/tracer_rocks_db.rs +++ b/evm_loader/lib/src/types/tracer_rocks_db.rs @@ -140,13 +140,13 @@ impl RocksDb { Ok(env!("NEON_REVISION").to_string()) } - pub async fn get_slot_by_blockhash(&self, blockhash: String) -> RocksDbResult { + pub async fn get_slot_by_blockhash(&self, blockhash: String) -> RocksDbResult> { let response: String = self .client .request("get_slot_by_blockhash", rpc_params![blockhash]) .await?; tracing::info!("response: {:?}", response); - Ok(u64::from_str(response.as_str())?) + Ok(from_str(response.as_str())?) } pub async fn get_sync_status(&self) -> RocksDbResult { From 7c425091dc3da64ba5a166a24c3b3d9561bd138e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 11 Jul 2024 17:34:24 +0100 Subject: [PATCH 262/318] Bump serde from 1.0.203 to 1.0.204 in /evm_loader (#491) Bumps [serde](https://github.com/serde-rs/serde) from 1.0.203 to 1.0.204. - [Release notes](https://github.com/serde-rs/serde/releases) - [Commits](https://github.com/serde-rs/serde/compare/v1.0.203...v1.0.204) --- updated-dependencies: - dependency-name: serde dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 8 ++++---- evm_loader/api/Cargo.toml | 2 +- evm_loader/cli/Cargo.toml | 2 +- evm_loader/lib-interface/Cargo.toml | 2 +- evm_loader/program/Cargo.toml | 2 +- evm_loader/rpc-client/Cargo.toml | 2 +- evm_loader/rpc/Cargo.toml | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 02f560eff..abae74702 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -4701,9 +4701,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.203" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] @@ -4719,9 +4719,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.203" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 8c579316c..0bbcc12c1 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -10,7 +10,7 @@ clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } solana-sdk.workspace = true solana-client.workspace = true -serde = "1.0.203" +serde = "1.0.204" serde_json = { version = "1.0.120", features = ["preserve_order"] } ethnum = { version = "1.5", default-features = false, features = ["serde"] } tokio = { version = "1", features = ["full"] } diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index ec849aae1..67d59d4b9 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -13,7 +13,7 @@ solana-client.workspace = true solana-clap-utils.workspace = true solana-cli-config.workspace = true hex = "0.4.2" -serde = "1.0.203" +serde = "1.0.204" serde_json = { version = "1.0.120", features = ["preserve_order"] } log = "0.4.21" fern = "0.6" diff --git a/evm_loader/lib-interface/Cargo.toml b/evm_loader/lib-interface/Cargo.toml index 505439105..370ff1120 100644 --- a/evm_loader/lib-interface/Cargo.toml +++ b/evm_loader/lib-interface/Cargo.toml @@ -9,5 +9,5 @@ edition = "2021" abi_stable = "0.11.1" thiserror = "1" async-ffi = { version = "0.5.0", features = ["abi_stable"] } -serde = "1.0.203" +serde = "1.0.204" serde_json = "1.0.120" diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 4bc6c8589..be5e52a87 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -52,7 +52,7 @@ static_assertions = "1" borsh = "0.10" bincode = "1" serde_bytes = "0.11.15" -serde = { version = "1.0.203", default-features = false, features = ["derive", "rc"] } +serde = { version = "1.0.204", default-features = false, features = ["derive", "rc"] } ethnum = { version = "1.5", default-features = false, features = ["serde"] } cfg-if = { version = "1.0" } log = { version = "0.4", default-features = false, optional = true } diff --git a/evm_loader/rpc-client/Cargo.toml b/evm_loader/rpc-client/Cargo.toml index b716179f5..5cb968e50 100644 --- a/evm_loader/rpc-client/Cargo.toml +++ b/evm_loader/rpc-client/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -serde = "1.0.203" +serde = "1.0.204" serde_json = "1.0.120" neon-lib = { path = "../lib" } thiserror = "1.0.61" diff --git a/evm_loader/rpc/Cargo.toml b/evm_loader/rpc/Cargo.toml index c07ae1d27..7a4d13cd8 100644 --- a/evm_loader/rpc/Cargo.toml +++ b/evm_loader/rpc/Cargo.toml @@ -12,7 +12,7 @@ jsonrpc-v2 = "0.13.0" neon-lib-interface = { path = "../lib-interface" } neon-lib = { path = "../lib" } semver = "1.0.23" -serde = "1.0.203" +serde = "1.0.204" serde_json = "1.0.120" tokio = { version = "1", features = ["full"] } build-info = "0.0.37" From ebd315083fe53f00e33e1ae4dd3877164e5477fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 Jul 2024 09:16:15 +0100 Subject: [PATCH 263/318] Bump log from 0.4.21 to 0.4.22 in /evm_loader (#492) Bumps [log](https://github.com/rust-lang/log) from 0.4.21 to 0.4.22. - [Release notes](https://github.com/rust-lang/log/releases) - [Changelog](https://github.com/rust-lang/log/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/log/compare/0.4.21...0.4.22) --- updated-dependencies: - dependency-name: log dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- evm_loader/cli/Cargo.toml | 2 +- evm_loader/lib/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index abae74702..f03b8e2e0 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -3111,9 +3111,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lru" diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index 67d59d4b9..bd62f0f8e 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -15,7 +15,7 @@ solana-cli-config.workspace = true hex = "0.4.2" serde = "1.0.204" serde_json = { version = "1.0.120", features = ["preserve_order"] } -log = "0.4.21" +log = "0.4.22" fern = "0.6" ethnum = { version = "1.5", default-features = false, features = ["serde"] } tokio = { version = "1", features = ["full"] } diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 18508982b..3e5d6d171 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -27,7 +27,7 @@ hex = { version = "0.4", features = ["serde"] } serde = "1.0" serde_json = { version = "1.0", features = ["preserve_order"] } serde_with = { version = "3.8", features = ["hex"] } -log = "0.4.21" +log = "0.4.22" rand = "0.8" ethnum = { version = "1.5", default-features = false, features = ["serde"] } goblin = { version = "0.6.0" } From 44d43084f22055f098e6ead2952f1b94864e3d19 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Mon, 15 Jul 2024 09:45:38 +0100 Subject: [PATCH 264/318] NDEV-3095: Compare status and logs between emulation and receipt (#460) * NDEV-3095: Compare status and logs between emulation and receipt * Remove RefCell from return_data --- evm_loader/lib/src/abi/trace.rs | 3 +- evm_loader/lib/src/account_storage.rs | 69 ++++++++++++++++--- evm_loader/lib/src/commands/emulate.rs | 19 ++++- evm_loader/lib/src/commands/trace.rs | 8 +-- .../program/src/account_storage/backend.rs | 41 ++++++++++- evm_loader/program/src/account_storage/mod.rs | 15 +++- evm_loader/program/src/evm/database.rs | 3 +- evm_loader/program/src/evm/opcode.rs | 18 ++--- evm_loader/program/src/executor/state.rs | 28 +++++--- .../program/src/executor/synced_state.rs | 24 +++++-- .../src/instruction/transaction_execute.rs | 2 +- .../src/instruction/transaction_step.rs | 13 ++-- 12 files changed, 185 insertions(+), 58 deletions(-) diff --git a/evm_loader/lib/src/abi/trace.rs b/evm_loader/lib/src/abi/trace.rs index 491bf284f..10942a739 100644 --- a/evm_loader/lib/src/abi/trace.rs +++ b/evm_loader/lib/src/abi/trace.rs @@ -1,6 +1,7 @@ use serde_json::Value; use super::params_to_neon_error; +use crate::commands::emulate::EmulateResponse; use crate::commands::get_config::BuildConfigSimulator; use crate::commands::trace::{self}; use crate::config::APIOptions; @@ -11,7 +12,7 @@ pub async fn execute( rpc: &(impl Rpc + BuildConfigSimulator), config: &APIOptions, params: &str, -) -> NeonResult { +) -> NeonResult<(EmulateResponse, Option)> { let params: EmulateApiRequest = serde_json::from_str(params).map_err(|_| params_to_neon_error(params))?; diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index c5e0d1c20..dd9a350ce 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -1,8 +1,11 @@ use crate::account_data::AccountData; +use crate::commands::get_config::{BuildConfigSimulator, ChainInfo}; +use crate::tracing::{AccountOverrides, BlockOverrides}; use crate::{rpc::Rpc, solana_simulator::SolanaSimulator, NeonError, NeonResult}; use async_trait::async_trait; use elsa::FrozenMap; use ethnum::U256; +use evm_loader::account_storage::LogCollector; pub use evm_loader::account_storage::{AccountStorage, SyncedAccountStorage}; use evm_loader::{ account::{ @@ -35,9 +38,7 @@ use std::{ convert::TryInto, rc::Rc, }; - -use crate::commands::get_config::{BuildConfigSimulator, ChainInfo}; -use crate::tracing::{AccountOverrides, BlockOverrides}; +use web3::types::Log; const FAKE_OPERATOR: Pubkey = pubkey!("neonoperator1111111111111111111111111111111"); @@ -113,7 +114,9 @@ pub struct EmulatorAccountStorage<'rpc, T: Rpc> { state_overrides: Option, accounts_cache: FrozenMap>>, used_accounts: FrozenMap>>, - return_data: RefCell>, + return_data: Option, + logs: Vec, + logs_stack: Vec, } impl<'rpc, T: Rpc + BuildConfigSimulator> EmulatorAccountStorage<'rpc, T> { @@ -174,7 +177,9 @@ impl<'rpc, T: Rpc + BuildConfigSimulator> EmulatorAccountStorage<'rpc, T> { rent, accounts_cache, used_accounts: FrozenMap::new(), - return_data: RefCell::new(None), + return_data: None, + logs: vec![], + logs_stack: vec![], }; let target_chain_id = tx_chain_id.unwrap_or_else(|| storage.default_chain_id()); @@ -206,7 +211,9 @@ impl<'rpc, T: Rpc + BuildConfigSimulator> EmulatorAccountStorage<'rpc, T> { state_overrides: other.state_overrides.clone(), accounts_cache: other.accounts_cache.clone(), used_accounts: other.used_accounts.clone(), - return_data: RefCell::new(None), + return_data: None, + logs: other.logs.clone(), + logs_stack: other.logs_stack.clone(), }; let target_chain_id = tx_chain_id.unwrap_or_else(|| storage.default_chain_id()); storage.apply_balance_overrides(target_chain_id).await?; @@ -908,6 +915,33 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { pub fn is_timestamp_used(&self) -> bool { *self.timestamp_used.borrow() } + + pub fn logs(&self) -> Vec { + self.logs.clone() + } +} + +impl LogCollector for EmulatorAccountStorage<'_, T> { + fn collect_log( + &mut self, + address: &[u8; 20], + topics: [[u8; 32]; N], + data: &[u8], + ) { + self.logs.push(Log { + address: address.into(), + topics: topics.iter().map(Into::into).collect(), + data: data.into(), + block_hash: None, + block_number: None, + transaction_hash: None, + transaction_index: None, + log_index: None, + transaction_log_index: None, + log_type: None, + removed: None, + }); + } } #[async_trait(?Send)] @@ -940,14 +974,13 @@ impl AccountStorage for EmulatorAccountStorage<'_, T> { fn return_data(&self) -> Option<(Pubkey, Vec)> { info!("return_data"); self.return_data - .borrow() .as_ref() .map(|data| (data.program_id, data.data.clone())) } - fn set_return_data(&self, data: &[u8]) { + fn set_return_data(&mut self, data: &[u8]) { info!("set_return_data"); - *self.return_data.borrow_mut() = Some(TransactionReturnData { + self.return_data = Some(TransactionReturnData { program_id: self.program_id, data: data.to_vec(), }); @@ -1367,7 +1400,7 @@ impl SyncedAccountStorage for EmulatorAccountStorage<'_, T> { } if let Some(return_data) = result.return_data { - *self.return_data.borrow_mut() = Some(return_data); + self.return_data = Some(return_data); } for meta in &instruction.accounts { @@ -1400,6 +1433,7 @@ impl SyncedAccountStorage for EmulatorAccountStorage<'_, T> { fn snapshot(&mut self) { info!("snapshot"); self.call_stack.push(self.accounts.clone()); + self.logs_stack.push(self.logs.len()); } fn revert_snapshot(&mut self) { @@ -1411,10 +1445,25 @@ impl SyncedAccountStorage for EmulatorAccountStorage<'_, T> { } else { self.execute_status.reverts_before_solana_calls = true; } + + let logs_stack_len = self + .logs_stack + .pop() + .expect("Fatal Error: Inconsistent EVM Logs Stack"); + + self.logs.truncate(logs_stack_len); + + if self.logs_stack.is_empty() { + // sanity check + assert!(self.logs.is_empty()); + } } fn commit_snapshot(&mut self) { self.call_stack.pop().expect("No snapshots to commit"); + self.logs_stack + .pop() + .expect("Fatal Error: Inconsistent EVM Logs Stack"); } } diff --git a/evm_loader/lib/src/commands/emulate.rs b/evm_loader/lib/src/commands/emulate.rs index c6a4fb665..ef16d54dc 100644 --- a/evm_loader/lib/src/commands/emulate.rs +++ b/evm_loader/lib/src/commands/emulate.rs @@ -20,6 +20,7 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; use serde_with::{hex::Hex, serde_as, DisplayFromStr}; use solana_sdk::{account::Account, pubkey::Pubkey}; +use web3::types::Log; #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] @@ -42,10 +43,14 @@ pub struct EmulateResponse { pub used_gas: u64, pub iterations: u64, pub solana_accounts: Vec, + pub logs: Vec, } impl EmulateResponse { - pub fn revert(e: &E) -> Self { + pub fn revert( + e: &E, + backend: &SyncedExecutorState>, + ) -> Self { let revert_message = build_revert_message(&e.to_string()); let exit_status = ExitStatus::Revert(revert_message); Self { @@ -58,6 +63,7 @@ impl EmulateResponse { used_gas: 0, iterations: 0, solana_accounts: vec![], + logs: backend.backend().logs(), } } } @@ -141,6 +147,7 @@ pub async fn execute( used_gas: response.used_gas.max(response2.used_gas), iterations: response.iterations.max(response2.iterations), solana_accounts: combined_solana_accounts, + logs: response.logs.clone(), }; return Ok((emul_response, result.1)); @@ -169,14 +176,19 @@ async fn emulate_trx( let mut backend = SyncedExecutorState::new(storage); let mut evm = match Machine::new(&tx, origin, &mut backend, tracer).await { Ok(evm) => evm, - Err(e) => return Ok((EmulateResponse::revert(&e), None)), + Err(e) => return Ok((EmulateResponse::revert(&e, &backend), None)), }; let (exit_status, steps_executed, tracer) = evm.execute(step_limit, &mut backend).await?; if exit_status == ExitStatus::StepLimit { - return Ok((EmulateResponse::revert(&NeonError::TooManySteps), None)); + return Ok(( + EmulateResponse::revert(&NeonError::TooManySteps, &backend), + None, + )); } + let logs = backend.backend().logs(); + debug!("Execute done, result={exit_status:?}"); debug!("{steps_executed} steps executed"); @@ -214,6 +226,7 @@ async fn emulate_trx( solana_accounts, result: exit_status.into_result().unwrap_or_default(), iterations, + logs, }, tracer.map(|tracer| tracer.into_traces(used_gas)), )) diff --git a/evm_loader/lib/src/commands/trace.rs b/evm_loader/lib/src/commands/trace.rs index b3d59a321..77beb7d21 100644 --- a/evm_loader/lib/src/commands/trace.rs +++ b/evm_loader/lib/src/commands/trace.rs @@ -1,5 +1,6 @@ #![allow(clippy::missing_errors_doc)] +use crate::commands::emulate::EmulateResponse; use serde_json::Value; use solana_sdk::pubkey::Pubkey; @@ -13,7 +14,7 @@ pub async fn trace_transaction( rpc: &(impl Rpc + BuildConfigSimulator), program_id: Pubkey, emulate_request: EmulateRequest, -) -> Result { +) -> Result<(EmulateResponse, Option), NeonError> { let trace_config = emulate_request .trace_config .as_ref() @@ -22,8 +23,5 @@ pub async fn trace_transaction( let tracer = new_tracer(&emulate_request.tx, trace_config)?; - let (_, emulated_traces) = - super::emulate::execute(rpc, program_id, emulate_request, Some(tracer)).await?; - - Ok(emulated_traces.expect("traces should not be None")) + super::emulate::execute(rpc, program_id, emulate_request, Some(tracer)).await } diff --git a/evm_loader/program/src/account_storage/backend.rs b/evm_loader/program/src/account_storage/backend.rs index 56564513c..c0a87def1 100644 --- a/evm_loader/program/src/account_storage/backend.rs +++ b/evm_loader/program/src/account_storage/backend.rs @@ -1,4 +1,4 @@ -use crate::account_storage::{AccountStorage, ProgramAccountStorage}; +use crate::account_storage::{AccountStorage, LogCollector, ProgramAccountStorage}; use crate::config::STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT; use crate::error::Result; use crate::executor::OwnedAccountInfo; @@ -8,6 +8,43 @@ use solana_program::account_info::AccountInfo; use solana_program::{pubkey::Pubkey, rent::Rent, sysvar::slot_hashes}; use std::convert::TryInto; +use crate::debug::log_data; + +impl LogCollector for ProgramAccountStorage<'_> { + fn collect_log( + &mut self, + address: &[u8; 20], + topics: [[u8; 32]; N], + data: &[u8], + ) { + match N { + 0 => log_data(&[b"LOG0", address, &[0], data]), + 1 => log_data(&[b"LOG1", address, &[1], &topics[0], data]), + 2 => log_data(&[b"LOG2", address, &[2], &topics[0], &topics[1], data]), + 3 => log_data(&[ + b"LOG3", + address, + &[3], + &topics[0], + &topics[1], + &topics[2], + data, + ]), + 4 => log_data(&[ + b"LOG4", + address, + &[4], + &topics[0], + &topics[1], + &topics[2], + &topics[3], + data, + ]), + _ => unreachable!(), + } + } +} + impl<'a> AccountStorage for ProgramAccountStorage<'a> { fn program_id(&self) -> &Pubkey { &crate::ID @@ -36,7 +73,7 @@ impl<'a> AccountStorage for ProgramAccountStorage<'a> { solana_program::program::get_return_data() } - fn set_return_data(&self, data: &[u8]) { + fn set_return_data(&mut self, data: &[u8]) { solana_program::program::set_return_data(data); } diff --git a/evm_loader/program/src/account_storage/mod.rs b/evm_loader/program/src/account_storage/mod.rs index e4baef638..6dd9c408b 100644 --- a/evm_loader/program/src/account_storage/mod.rs +++ b/evm_loader/program/src/account_storage/mod.rs @@ -36,7 +36,7 @@ pub struct ProgramAccountStorage<'a> { /// Account storage /// Trait to access account info #[maybe_async(?Send)] -pub trait AccountStorage { +pub trait AccountStorage: LogCollector { /// Get `NeonEVM` program id fn program_id(&self) -> &Pubkey; /// Get operator pubkey @@ -56,7 +56,7 @@ pub trait AccountStorage { fn return_data(&self) -> Option<(Pubkey, Vec)>; /// Set return data to Solana - fn set_return_data(&self, data: &[u8]); + fn set_return_data(&mut self, data: &[u8]); /// Get account nonce async fn nonce(&self, address: Address, chain_id: u64) -> u64; @@ -95,7 +95,7 @@ pub trait AccountStorage { } #[maybe_async(?Send)] -pub trait SyncedAccountStorage { +pub trait SyncedAccountStorage: AccountStorage { async fn set_code(&mut self, address: Address, chain_id: u64, code: Vec) -> Result<()>; async fn set_storage(&mut self, address: Address, index: U256, value: [u8; 32]) -> Result<()>; async fn increment_nonce(&mut self, address: Address, chain_id: u64) -> Result<()>; @@ -119,3 +119,12 @@ pub trait SyncedAccountStorage { fn revert_snapshot(&mut self); fn commit_snapshot(&mut self); } + +pub trait LogCollector { + fn collect_log( + &mut self, + address: &[u8; 20], + topics: [[u8; 32]; N], + data: &[u8], + ); +} diff --git a/evm_loader/program/src/evm/database.rs b/evm_loader/program/src/evm/database.rs index 1fbf5625d..bad42fff2 100644 --- a/evm_loader/program/src/evm/database.rs +++ b/evm_loader/program/src/evm/database.rs @@ -1,4 +1,5 @@ use super::{Buffer, Context}; +use crate::account_storage::LogCollector; use crate::{error::Result, executor::OwnedAccountInfo, types::Address}; use ethnum::U256; use maybe_async::maybe_async; @@ -7,7 +8,7 @@ use solana_program::{ }; #[maybe_async(?Send)] -pub trait Database { +pub trait Database: LogCollector { fn program_id(&self) -> &Pubkey; fn operator(&self) -> Pubkey; fn chain_id_to_token(&self, chain_id: u64) -> Pubkey; diff --git a/evm_loader/program/src/evm/opcode.rs b/evm_loader/program/src/evm/opcode.rs index e3789ea1f..630a9b102 100644 --- a/evm_loader/program/src/evm/opcode.rs +++ b/evm_loader/program/src/evm/opcode.rs @@ -1003,11 +1003,12 @@ impl Machine { } /// Append log record with N topics - #[rustfmt::skip] #[maybe_async] - pub async fn opcode_log_0_4(&mut self, _backend: &mut B) -> Result { + pub async fn opcode_log_0_4(&mut self, backend: &mut B) -> Result { + let address = self.context.contract; + if self.is_static { - return Err(Error::StaticModeViolation(self.context.contract)); + return Err(Error::StaticModeViolation(address)); } let offset = self.stack.pop_usize()?; @@ -1023,16 +1024,7 @@ impl Machine { topics }; - let address = self.context.contract.as_bytes(); - - match N { - 0 => log_data(&[b"LOG0", address, &[0], data]), - 1 => log_data(&[b"LOG1", address, &[1], &topics[0], data]), - 2 => log_data(&[b"LOG2", address, &[2], &topics[0], &topics[1], data]), - 3 => log_data(&[b"LOG3", address, &[3], &topics[0], &topics[1], &topics[2], data]), - 4 => log_data(&[b"LOG4", address, &[4], &topics[0], &topics[1], &topics[2], &topics[3], data]), - _ => unreachable!(), - } + backend.collect_log(address.as_bytes(), topics, data); Ok(Action::Continue) } diff --git a/evm_loader/program/src/executor/state.rs b/evm_loader/program/src/executor/state.rs index 66831ca7d..8010109b8 100644 --- a/evm_loader/program/src/executor/state.rs +++ b/evm_loader/program/src/executor/state.rs @@ -1,6 +1,11 @@ use std::cell::RefCell; use std::collections::BTreeMap; +use crate::account_storage::{AccountStorage, LogCollector}; +use crate::error::{Error, Result}; +use crate::evm::database::Database; +use crate::evm::{Context, ExitStatus}; +use crate::types::Address; use ethnum::{AsU256, U256}; use maybe_async::maybe_async; use mpl_token_metadata::programs::MPL_TOKEN_METADATA_ID; @@ -8,12 +13,6 @@ use solana_program::instruction::Instruction; use solana_program::pubkey::Pubkey; use solana_program::rent::Rent; -use crate::account_storage::AccountStorage; -use crate::error::{Error, Result}; -use crate::evm::database::Database; -use crate::evm::{Context, ExitStatus}; -use crate::types::Address; - use super::action::Action; use super::cache::Cache; use super::precompile_extension::PrecompiledContracts; @@ -25,7 +24,7 @@ pub type TouchedAccounts = BTreeMap; /// Represents the state of executor abstracted away from a self.backend. /// UPDATE `serialize/deserialize` WHEN THIS STRUCTURE CHANGES pub struct ExecutorState<'a, B: AccountStorage> { - pub backend: &'a B, + backend: &'a mut B, cache: RefCell, actions: Vec, stack: Vec, @@ -44,7 +43,7 @@ impl<'a, B: AccountStorage> ExecutorState<'a, B> { cursor.position().try_into().map_err(Error::from) } - pub fn deserialize_from(buffer: &[u8], backend: &'a B) -> Result { + pub fn deserialize_from(buffer: &[u8], backend: &'a mut B) -> Result { let (cache, actions, stack, exit_status) = bincode::deserialize(buffer)?; Ok(Self { backend, @@ -57,7 +56,7 @@ impl<'a, B: AccountStorage> ExecutorState<'a, B> { } #[must_use] - pub fn new(backend: &'a B) -> Self { + pub fn new(backend: &'a mut B) -> Self { let cache = Cache { block_number: backend.block_number(), block_timestamp: backend.block_timestamp(), @@ -168,6 +167,17 @@ impl<'a, B: AccountStorage> ExecutorState<'a, B> { } } +impl LogCollector for ExecutorState<'_, B> { + fn collect_log( + &mut self, + address: &[u8; 20], + topics: [[u8; 32]; N], + data: &[u8], + ) { + self.backend.collect_log(address, topics, data); + } +} + #[maybe_async(?Send)] impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { fn program_id(&self) -> &Pubkey { diff --git a/evm_loader/program/src/executor/synced_state.rs b/evm_loader/program/src/executor/synced_state.rs index 9c31db97a..c681a0d62 100644 --- a/evm_loader/program/src/executor/synced_state.rs +++ b/evm_loader/program/src/executor/synced_state.rs @@ -4,7 +4,7 @@ use solana_program::instruction::Instruction; use solana_program::pubkey::Pubkey; use solana_program::rent::Rent; -use crate::account_storage::{AccountStorage, SyncedAccountStorage}; +use crate::account_storage::{AccountStorage, LogCollector, SyncedAccountStorage}; use crate::error::{Error, Result}; use crate::evm::database::Database; use crate::evm::Context; @@ -22,12 +22,12 @@ enum Action { } pub struct SyncedExecutorState<'a, B: AccountStorage> { - pub backend: &'a mut B, + backend: &'a mut B, actions: Vec, stack: Vec, } -impl<'a, B: AccountStorage + SyncedAccountStorage> SyncedExecutorState<'a, B> { +impl<'a, B: SyncedAccountStorage> SyncedExecutorState<'a, B> { #[must_use] pub fn new(backend: &'a mut B) -> Self { Self { @@ -36,10 +36,26 @@ impl<'a, B: AccountStorage + SyncedAccountStorage> SyncedExecutorState<'a, B> { stack: Vec::with_capacity(16), } } + + #[must_use] + pub fn backend(&self) -> &B { + self.backend + } +} + +impl LogCollector for SyncedExecutorState<'_, B> { + fn collect_log( + &mut self, + address: &[u8; 20], + topics: [[u8; 32]; N], + data: &[u8], + ) { + self.backend.collect_log(address, topics, data); + } } #[maybe_async(?Send)] -impl<'a, B: AccountStorage + SyncedAccountStorage> Database for SyncedExecutorState<'a, B> { +impl<'a, B: SyncedAccountStorage> Database for SyncedExecutorState<'a, B> { fn program_id(&self) -> &Pubkey { self.backend.program_id() } diff --git a/evm_loader/program/src/instruction/transaction_execute.rs b/evm_loader/program/src/instruction/transaction_execute.rs index cfe292672..3239a11c3 100644 --- a/evm_loader/program/src/instruction/transaction_execute.rs +++ b/evm_loader/program/src/instruction/transaction_execute.rs @@ -26,7 +26,7 @@ pub fn execute( account_storage.origin(origin, &trx)?.increment_nonce()?; let (exit_reason, apply_state, steps_executed) = { - let mut backend = ExecutorState::new(&account_storage); + let mut backend = ExecutorState::new(&mut account_storage); let mut evm = Machine::new(&trx, origin, &mut backend, None::)?; let (result, steps_executed, _) = evm.execute(u64::MAX, &mut backend)?; diff --git a/evm_loader/program/src/instruction/transaction_step.rs b/evm_loader/program/src/instruction/transaction_step.rs index f58f66f0e..16ce917c2 100644 --- a/evm_loader/program/src/instruction/transaction_step.rs +++ b/evm_loader/program/src/instruction/transaction_step.rs @@ -22,7 +22,7 @@ pub fn do_begin<'a>( ) -> Result<()> { debug_print!("do_begin"); - let account_storage = ProgramAccountStorage::new(accounts)?; + let mut account_storage = ProgramAccountStorage::new(accounts)?; let origin = storage.trx_origin(); @@ -43,7 +43,8 @@ pub fn do_begin<'a>( origin_account.burn(gas_limit_in_tokens)?; // Initialize EVM and serialize it to the Holder - let mut backend = ExecutorState::new(&account_storage); + let mut backend = ExecutorState::new(&mut account_storage); + let evm = Machine::new(storage.trx(), origin, &mut backend, None)?; serialize_evm_state(&mut storage, &backend, &evm)?; @@ -74,17 +75,17 @@ pub fn do_continue<'a>( ))); } - let account_storage = ProgramAccountStorage::new(accounts)?; + let mut account_storage = ProgramAccountStorage::new(accounts)?; let (mut backend, mut evm) = if reset { log_data(&[b"RESET"]); storage.reset_steps_executed(); - let mut backend = ExecutorState::new(&account_storage); + let mut backend = ExecutorState::new(&mut account_storage); let evm = Machine::new(storage.trx(), storage.trx_origin(), &mut backend, None)?; (backend, evm) } else { - deserialize_evm_state(&storage, &account_storage)? + deserialize_evm_state(&storage, &mut account_storage)? }; let mut steps_executed = 0; @@ -213,7 +214,7 @@ fn serialize_evm_state( fn deserialize_evm_state<'a, 'r>( state: &StateAccount<'a>, - account_storage: &'r ProgramAccountStorage<'a>, + account_storage: &'r mut ProgramAccountStorage<'a>, ) -> Result<(EvmBackend<'a, 'r>, Evm<'a, 'r>)> { let (evm_state_len, evm_machine_len) = state.buffer_variables(); let buffer = state.buffer(); From 9b94c8f1b1ce8139814e6a6d76934c4ea8a80147 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Jul 2024 12:13:33 +0100 Subject: [PATCH 265/318] Bump thiserror from 1.0.61 to 1.0.62 in /evm_loader (#494) Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.61 to 1.0.62. - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](https://github.com/dtolnay/thiserror/compare/1.0.61...1.0.62) --- updated-dependencies: - dependency-name: thiserror dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 8 ++++---- evm_loader/rpc-client/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index f03b8e2e0..7f8cdf6de 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -6555,18 +6555,18 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.61" +version = "1.0.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "f2675633b1499176c2dff06b0856a27976a8f9d436737b4cf4f312d4d91d8bbb" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "d20468752b09f49e909e55a5d338caa8bedf615594e9d80bc4c565d30faf798c" dependencies = [ "proc-macro2", "quote", diff --git a/evm_loader/rpc-client/Cargo.toml b/evm_loader/rpc-client/Cargo.toml index 5cb968e50..5b659978a 100644 --- a/evm_loader/rpc-client/Cargo.toml +++ b/evm_loader/rpc-client/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" serde = "1.0.204" serde_json = "1.0.120" neon-lib = { path = "../lib" } -thiserror = "1.0.61" +thiserror = "1.0.62" async-trait = "0.1.80" jsonrpsee-core = "0.22.3" jsonrpsee-http-client = "0.22.3" From 65555752c2903efa5168e3458a59964f65af7d09 Mon Sep 17 00:00:00 2001 From: Semen Medvedev Date: Tue, 16 Jul 2024 14:23:19 +0700 Subject: [PATCH 266/318] NDEV-3050 Suppose that get_account_at may return missing account --- evm_loader/lib/src/types/tracer_rocks_db.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/evm_loader/lib/src/types/tracer_rocks_db.rs b/evm_loader/lib/src/types/tracer_rocks_db.rs index 3e265cc00..01177cca6 100644 --- a/evm_loader/lib/src/types/tracer_rocks_db.rs +++ b/evm_loader/lib/src/types/tracer_rocks_db.rs @@ -103,9 +103,13 @@ impl RocksDb { ) .await?; - let account = from_str::(response.as_str())?; - info!("Got Account by {pubkey:?}: owner: {:?} lamports: {:?} executable: {:?} rent_epoch: {:?}", account.owner, account.lamports, account.executable, account.rent_epoch); - Ok(Some(account)) + let account = from_str::>(response.as_str())?; + if let Some(account) = &account { + info!("Got Account by {pubkey:?} owner: {:?} lamports: {:?} executable: {:?} rent_epoch: {:?}", account.owner, account.lamports, account.executable, account.rent_epoch); + } else { + info!("Got None for Account by {pubkey:?}"); + } + Ok(account) } pub async fn get_transaction_index(&self, signature: Signature) -> RocksDbResult { From ca394f752d1903e9c43677ccca1ae0fa510bd6ae Mon Sep 17 00:00:00 2001 From: iguberman Date: Tue, 16 Jul 2024 12:57:27 -0500 Subject: [PATCH 267/318] Fix get_account_at response logging --- rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 50fa4928b..c6e4d7d50 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.73" +channel = "1.79" From b8d6f7dcb6d5924e43c7c738ea1528e76b4576f1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Jul 2024 09:29:39 +0100 Subject: [PATCH 268/318] Bump syn from 2.0.70 to 2.0.71 in /evm_loader (#497) Bumps [syn](https://github.com/dtolnay/syn) from 2.0.70 to 2.0.71. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/2.0.70...2.0.71) --- updated-dependencies: - dependency-name: syn dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 78 +++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 7f8cdf6de..6c42056ce 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -123,7 +123,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -250,7 +250,7 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -631,7 +631,7 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -1005,7 +1005,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.70", + "syn 2.0.71", "zstd 0.13.0", ] @@ -1048,7 +1048,7 @@ checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -1575,7 +1575,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -1592,7 +1592,7 @@ checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -1616,7 +1616,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -1627,7 +1627,7 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -1809,7 +1809,7 @@ checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -1900,7 +1900,7 @@ checksum = "eecf8589574ce9b895052fa12d69af7a233f99e6107f5cb8dd1044f2a17bfdcb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -1912,7 +1912,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -2051,7 +2051,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.70", + "syn 2.0.71", "toml 0.8.2", ] @@ -2226,7 +2226,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -3161,7 +3161,7 @@ checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -3562,7 +3562,7 @@ checksum = "cfb77679af88f8b125209d354a202862602672222e7f2313fdd6dc349bad4712" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -3644,7 +3644,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -3656,7 +3656,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -3718,7 +3718,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -3888,7 +3888,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -4054,7 +4054,7 @@ checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -4725,7 +4725,7 @@ checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -4809,7 +4809,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -4821,7 +4821,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -5422,7 +5422,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -5891,7 +5891,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -6217,7 +6217,7 @@ checksum = "fadbefec4f3c678215ca72bd71862697bb06b41fd77c0088902dd3203354387b" dependencies = [ "quote", "spl-discriminator-syn", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -6229,7 +6229,7 @@ dependencies = [ "proc-macro2", "quote", "sha2 0.10.8", - "syn 2.0.70", + "syn 2.0.71", "thiserror", ] @@ -6277,7 +6277,7 @@ dependencies = [ "proc-macro2", "quote", "sha2 0.10.8", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -6451,7 +6451,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -6479,9 +6479,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.70" +version = "2.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16" +checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462" dependencies = [ "proc-macro2", "quote", @@ -6570,7 +6570,7 @@ checksum = "d20468752b09f49e909e55a5d338caa8bedf615594e9d80bc4c565d30faf798c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -6691,7 +6691,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -6868,7 +6868,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -7171,7 +7171,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", "wasm-bindgen-shared", ] @@ -7205,7 +7205,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -7638,7 +7638,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] @@ -7658,7 +7658,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.70", + "syn 2.0.71", ] [[package]] From 2febccc52bb9300bf9a59275429623d41d2c4f98 Mon Sep 17 00:00:00 2001 From: s-medvedev <40623263+s-medvedev@users.noreply.github.com> Date: Wed, 17 Jul 2024 16:38:08 +0700 Subject: [PATCH 269/318] SLA-109 Use special constant for operator account inside the action list (#496) * SLA-109 Use a special constant for the operator account inside the action list NeonEVM puts `Action::ExternalInstriction` with the current operator on each iteration. If different operators executed iterations it leads to a problem, because on the final iteration, we have an action with the previous operator. Solution: we put a special constant to the action list and change this constant with the real operator in the final iteration. --- evm_loader/lib/src/account_storage.rs | 5 +---- evm_loader/program/src/account/mod.rs | 5 ++++- evm_loader/program/src/account_storage/apply.rs | 17 +++++++---------- .../program/src/account_storage/backend.rs | 7 +------ evm_loader/program/src/account_storage/mod.rs | 4 +++- .../program/src/account_storage/synced.rs | 16 +++++++--------- .../precompile_extension/call_solana.rs | 10 +++++++--- .../executor/precompile_extension/metaplex.rs | 5 +++-- .../src/executor/precompile_extension/mod.rs | 3 ++- .../executor/precompile_extension/neon_token.rs | 9 +++------ .../executor/precompile_extension/spl_token.rs | 3 ++- evm_loader/program/src/executor/state.rs | 2 +- 12 files changed, 41 insertions(+), 45 deletions(-) diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index dd9a350ce..3fd6be96b 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -12,7 +12,7 @@ use evm_loader::{ legacy::{LegacyEtherData, LegacyStorageData}, BalanceAccount, ContractAccount, StorageCell, StorageCellAddress, }, - account_storage::find_slot_hash, + account_storage::{find_slot_hash, FAKE_OPERATOR}, config::STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT, error::Error as EvmLoaderError, executor::OwnedAccountInfo, @@ -25,7 +25,6 @@ use solana_sdk::{ clock::Clock, instruction::Instruction, program_error::ProgramError, - pubkey, pubkey::{Pubkey, PubkeyError}, rent::Rent, system_program, @@ -40,8 +39,6 @@ use std::{ }; use web3::types::Log; -const FAKE_OPERATOR: Pubkey = pubkey!("neonoperator1111111111111111111111111111111"); - #[derive(Default, Clone, Copy)] pub struct ExecuteStatus { pub external_solana_call: bool, diff --git a/evm_loader/program/src/account/mod.rs b/evm_loader/program/src/account/mod.rs index 99580761c..134262179 100644 --- a/evm_loader/program/src/account/mod.rs +++ b/evm_loader/program/src/account/mod.rs @@ -4,7 +4,7 @@ use solana_program::pubkey::Pubkey; use solana_program::rent::Rent; use std::cell::{Ref, RefMut}; -pub use crate::config::ACCOUNT_SEED_VERSION; +pub use crate::{account_storage::FAKE_OPERATOR, config::ACCOUNT_SEED_VERSION}; pub use ether_balance::{BalanceAccount, Header as BalanceHeader}; pub use ether_contract::{AllocateResult, ContractAccount, Header as ContractHeader}; @@ -272,6 +272,9 @@ impl<'a> AccountsDB<'a> { #[must_use] pub fn get(&self, pubkey: &Pubkey) -> &AccountInfo<'a> { + if pubkey == &FAKE_OPERATOR || pubkey == self.operator.key { + return self.operator_info(); + } let index = self .sorted_accounts .binary_search_by_key(&pubkey, |a| a.key) diff --git a/evm_loader/program/src/account_storage/apply.rs b/evm_loader/program/src/account_storage/apply.rs index efe8cbaac..630bef837 100644 --- a/evm_loader/program/src/account_storage/apply.rs +++ b/evm_loader/program/src/account_storage/apply.rs @@ -1,13 +1,12 @@ use std::collections::HashMap; use ethnum::U256; -use solana_program::account_info::AccountInfo; use solana_program::instruction::Instruction; use solana_program::program::{invoke_signed_unchecked, invoke_unchecked}; use solana_program::system_program; use crate::account::{AllocateResult, BalanceAccount, ContractAccount, StorageCell}; -use crate::account_storage::ProgramAccountStorage; +use crate::account_storage::{ProgramAccountStorage, FAKE_OPERATOR}; use crate::config::{ ACCOUNT_SEED_VERSION, PAYMENT_TO_TREASURE, STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT, }; @@ -132,7 +131,7 @@ impl<'a> ProgramAccountStorage<'a> { } Action::ExternalInstruction { program_id, - accounts, + mut accounts, data, seeds, .. @@ -148,13 +147,11 @@ impl<'a> ProgramAccountStorage<'a> { let program = self.accounts.get(&program_id).clone(); accounts_info.push(program); - for meta in &accounts { - let account: AccountInfo<'a> = - if meta.pubkey == self.accounts.operator_key() { - self.accounts.operator_info().clone() - } else { - self.accounts.get(&meta.pubkey).clone() - }; + for meta in &mut accounts { + if meta.pubkey == FAKE_OPERATOR { + meta.pubkey = self.accounts.operator_key(); + } + let account = self.accounts.get(&meta.pubkey).clone(); accounts_info.push(account); } diff --git a/evm_loader/program/src/account_storage/backend.rs b/evm_loader/program/src/account_storage/backend.rs index c0a87def1..9ecc959c8 100644 --- a/evm_loader/program/src/account_storage/backend.rs +++ b/evm_loader/program/src/account_storage/backend.rs @@ -164,12 +164,7 @@ impl<'a> AccountStorage for ProgramAccountStorage<'a> { fn clone_solana_account(&self, address: &Pubkey) -> OwnedAccountInfo { // This is used to emulate external instruction // One of instruction accounts can be operator - let info = if address == &self.accounts.operator_key() { - self.accounts.operator_info() - } else { - self.accounts.get(address) - }; - + let info = self.accounts.get(address); OwnedAccountInfo::from_account_info(self.program_id(), info) } diff --git a/evm_loader/program/src/account_storage/mod.rs b/evm_loader/program/src/account_storage/mod.rs index 6dd9c408b..6b722a19f 100644 --- a/evm_loader/program/src/account_storage/mod.rs +++ b/evm_loader/program/src/account_storage/mod.rs @@ -4,7 +4,7 @@ use crate::types::Address; use ethnum::U256; use maybe_async::maybe_async; use solana_program::{ - account_info::AccountInfo, instruction::Instruction, pubkey::Pubkey, rent::Rent, + account_info::AccountInfo, instruction::Instruction, pubkey, pubkey::Pubkey, rent::Rent, }; #[cfg(target_os = "solana")] use {crate::account::AccountsDB, solana_program::clock::Clock}; @@ -33,6 +33,8 @@ pub struct ProgramAccountStorage<'a> { synced_modified_contracts: std::collections::HashSet, } +pub const FAKE_OPERATOR: Pubkey = pubkey!("neonoperator1111111111111111111111111111111"); + /// Account storage /// Trait to access account info #[maybe_async(?Send)] diff --git a/evm_loader/program/src/account_storage/synced.rs b/evm_loader/program/src/account_storage/synced.rs index 3c95e4cd6..77ab8c8ed 100644 --- a/evm_loader/program/src/account_storage/synced.rs +++ b/evm_loader/program/src/account_storage/synced.rs @@ -1,11 +1,10 @@ use ethnum::U256; -use solana_program::account_info::AccountInfo; use solana_program::instruction::Instruction; use solana_program::program::{invoke_signed_unchecked, invoke_unchecked}; use solana_program::system_program; use crate::account::{AllocateResult, ContractAccount, StorageCell}; -use crate::account_storage::SyncedAccountStorage; +use crate::account_storage::{SyncedAccountStorage, FAKE_OPERATOR}; use crate::config::{ACCOUNT_SEED_VERSION, STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT}; use crate::error::Result; use crate::types::Address; @@ -102,7 +101,7 @@ impl<'a> SyncedAccountStorage for crate::account_storage::ProgramAccountStorage< fn execute_external_instruction( &mut self, - instruction: Instruction, + mut instruction: Instruction, seeds: Vec>>, _fee: u64, _emulated_internally: bool, @@ -118,12 +117,11 @@ impl<'a> SyncedAccountStorage for crate::account_storage::ProgramAccountStorage< let program = self.accounts.get(&instruction.program_id).clone(); accounts_info.push(program); - for meta in &instruction.accounts { - let account: AccountInfo<'a> = if meta.pubkey == self.accounts.operator_key() { - self.accounts.operator_info().clone() - } else { - self.accounts.get(&meta.pubkey).clone() - }; + for meta in &mut instruction.accounts { + if meta.pubkey == FAKE_OPERATOR { + meta.pubkey = self.accounts.operator_key(); + } + let account = self.accounts.get(&meta.pubkey).clone(); accounts_info.push(account); } diff --git a/evm_loader/program/src/executor/precompile_extension/call_solana.rs b/evm_loader/program/src/executor/precompile_extension/call_solana.rs index ad1fbb1e5..1c618602d 100644 --- a/evm_loader/program/src/executor/precompile_extension/call_solana.rs +++ b/evm_loader/program/src/executor/precompile_extension/call_solana.rs @@ -1,4 +1,5 @@ use crate::{ + account_storage::FAKE_OPERATOR, config::ACCOUNT_SEED_VERSION, error::{Error, Result}, evm::database::Database, @@ -321,7 +322,10 @@ async fn execute_external_instruction( } for meta in &instruction.accounts { - if meta.pubkey == state.operator() || meta.pubkey == *state.program_id() { + if meta.pubkey == FAKE_OPERATOR + || meta.pubkey == state.operator() + || meta.pubkey == *state.program_id() + { return Err(Error::InvalidAccountForCall(meta.pubkey)); } } @@ -345,7 +349,7 @@ async fn execute_external_instruction( let payer = state.external_account(payer_pubkey).await?; if payer.lamports < required_lamports { let transfer_instruction = solana_program::system_instruction::transfer( - &state.operator(), + &FAKE_OPERATOR, &payer_pubkey, required_lamports - payer.lamports, ); @@ -367,7 +371,7 @@ async fn execute_external_instruction( if payer.lamports > 0 { let transfer_instruction = solana_program::system_instruction::transfer( &payer_pubkey, - &state.operator(), + &FAKE_OPERATOR, payer.lamports, ); state diff --git a/evm_loader/program/src/executor/precompile_extension/metaplex.rs b/evm_loader/program/src/executor/precompile_extension/metaplex.rs index 1da971bb7..5df716274 100644 --- a/evm_loader/program/src/executor/precompile_extension/metaplex.rs +++ b/evm_loader/program/src/executor/precompile_extension/metaplex.rs @@ -14,6 +14,7 @@ use solana_program::pubkey::Pubkey; use crate::{ account::ACCOUNT_SEED_VERSION, + account_storage::FAKE_OPERATOR, error::{Error, Result}, evm::database::Database, types::Address, @@ -201,7 +202,7 @@ async fn create_metadata( .mint(mint) .mint_authority(signer_pubkey) .update_authority(signer_pubkey, true) - .payer(state.operator()) + .payer(FAKE_OPERATOR) .is_mutable(true) .data(DataV2 { name, @@ -259,7 +260,7 @@ async fn create_master_edition( .mint(mint) .mint_authority(signer_pubkey) .update_authority(signer_pubkey) - .payer(state.operator()); + .payer(FAKE_OPERATOR); if let Some(max_supply) = max_supply { instruction_builder.max_supply(max_supply); diff --git a/evm_loader/program/src/executor/precompile_extension/mod.rs b/evm_loader/program/src/executor/precompile_extension/mod.rs index c527bf3a7..0d0812c99 100644 --- a/evm_loader/program/src/executor/precompile_extension/mod.rs +++ b/evm_loader/program/src/executor/precompile_extension/mod.rs @@ -1,4 +1,5 @@ use crate::{ + account_storage::FAKE_OPERATOR, error::Result, evm::{database::Database, Context}, types::Address, @@ -89,7 +90,7 @@ pub async fn create_account( if required_lamports > 0 { let transfer = - system_instruction::transfer(&state.operator(), &account.key, required_lamports); + system_instruction::transfer(&FAKE_OPERATOR, &account.key, required_lamports); state .queue_external_instruction(transfer, vec![], required_lamports, true) .await?; diff --git a/evm_loader/program/src/executor/precompile_extension/neon_token.rs b/evm_loader/program/src/executor/precompile_extension/neon_token.rs index 48865df7b..8931725d6 100644 --- a/evm_loader/program/src/executor/precompile_extension/neon_token.rs +++ b/evm_loader/program/src/executor/precompile_extension/neon_token.rs @@ -8,6 +8,7 @@ use spl_associated_token_account::get_associated_token_address; use crate::{ account::token, + account_storage::FAKE_OPERATOR, error::{Error, Result}, evm::database::Database, types::Address, @@ -107,12 +108,8 @@ async fn withdraw( if !spl_token::check_id(&account.owner) { use spl_associated_token_account::instruction::create_associated_token_account; - let create_associated = create_associated_token_account( - &state.operator(), - &target, - &mint_address, - &spl_token::ID, - ); + let create_associated = + create_associated_token_account(&FAKE_OPERATOR, &target, &mint_address, &spl_token::ID); let fee = state.rent().minimum_balance(spl_token::state::Account::LEN); state diff --git a/evm_loader/program/src/executor/precompile_extension/spl_token.rs b/evm_loader/program/src/executor/precompile_extension/spl_token.rs index a90a976b8..589852fd5 100644 --- a/evm_loader/program/src/executor/precompile_extension/spl_token.rs +++ b/evm_loader/program/src/executor/precompile_extension/spl_token.rs @@ -9,6 +9,7 @@ use solana_program::{ use super::create_account; use crate::{ account::ACCOUNT_SEED_VERSION, + account_storage::FAKE_OPERATOR, error::{Error, Result}, evm::database::Database, types::Address, @@ -389,7 +390,7 @@ async fn close_account( let close_account = spl_token::instruction::close_account( &spl_token::ID, &account, - &state.operator(), + &FAKE_OPERATOR, &signer_pubkey, &[], )?; diff --git a/evm_loader/program/src/executor/state.rs b/evm_loader/program/src/executor/state.rs index 8010109b8..3cfe6184d 100644 --- a/evm_loader/program/src/executor/state.rs +++ b/evm_loader/program/src/executor/state.rs @@ -456,7 +456,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { self.touch_solana(m.pubkey); let account = self.backend.clone_solana_account(&m.pubkey).await; - accounts.insert(account.key, account); + accounts.insert(m.pubkey, account); } for action in &self.actions { From 34ceaf2cb397fe300bee9300d77a0aa520a0391a Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Wed, 17 Jul 2024 13:46:26 +0300 Subject: [PATCH 270/318] SLA-110 Log account revision changes (#500) --- evm_loader/program/src/account/state.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/evm_loader/program/src/account/state.rs b/evm_loader/program/src/account/state.rs index 1539d3654..f02ba689b 100644 --- a/evm_loader/program/src/account/state.rs +++ b/evm_loader/program/src/account/state.rs @@ -5,6 +5,7 @@ use std::mem::size_of; use crate::account_storage::AccountStorage; use crate::config::DEFAULT_CHAIN_ID; +use crate::debug::log_data; use crate::error::{Error, Result}; use crate::types::serde::bytes_32; use crate::types::{Address, Transaction}; @@ -198,6 +199,7 @@ impl<'a> StateAccount<'a> { let revision_entry = &state.data.revisions[account.key]; if revision_entry != &account_revision { + log_data(&[b"INVALID_REVISION", account.key.as_ref()]); status = AccountsStatus::NeedRestart; break; } From fa9293979ecf7b00c0b14fd9d79bddee9e30c82a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 19 Jul 2024 15:56:29 +0300 Subject: [PATCH 271/318] Bump async-trait from 0.1.80 to 0.1.81 in /evm_loader (#499) Bumps [async-trait](https://github.com/dtolnay/async-trait) from 0.1.80 to 0.1.81. - [Release notes](https://github.com/dtolnay/async-trait/releases) - [Commits](https://github.com/dtolnay/async-trait/compare/0.1.80...0.1.81) --- updated-dependencies: - dependency-name: async-trait dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 4 ++-- evm_loader/lib/Cargo.toml | 2 +- evm_loader/program/Cargo.toml | 2 +- evm_loader/rpc-client/Cargo.toml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 6c42056ce..ddb07ddc4 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -625,9 +625,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.80" +version = "0.1.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" dependencies = [ "proc-macro2", "quote", diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 3e5d6d171..82fb960cc 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -35,7 +35,7 @@ scroll = "0.11.0" tokio = { version = "1", features = ["full"] } clickhouse = "0.11.6" tracing = "0.1" -async-trait = "0.1.80" +async-trait = "0.1.81" build-info = "0.0.37" enum_dispatch = "0.3.13" web3 = "0.19.0" diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index be5e52a87..424794ecb 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -57,7 +57,7 @@ ethnum = { version = "1.5", default-features = false, features = ["serde"] } cfg-if = { version = "1.0" } log = { version = "0.4", default-features = false, optional = true } maybe-async = "0.2.10" -async-trait = { version = "0.1.80", optional = true } +async-trait = { version = "0.1.81", optional = true } [target.'cfg(target_os = "solana")'.dependencies.maybe-async] version = "0.2.7" diff --git a/evm_loader/rpc-client/Cargo.toml b/evm_loader/rpc-client/Cargo.toml index 5b659978a..55f86378c 100644 --- a/evm_loader/rpc-client/Cargo.toml +++ b/evm_loader/rpc-client/Cargo.toml @@ -10,7 +10,7 @@ serde = "1.0.204" serde_json = "1.0.120" neon-lib = { path = "../lib" } thiserror = "1.0.62" -async-trait = "0.1.80" +async-trait = "0.1.81" jsonrpsee-core = "0.22.3" jsonrpsee-http-client = "0.22.3" jsonrpsee-types = "0.22.3" From ec20537d14986d3be2ce7c1735db17859a206767 Mon Sep 17 00:00:00 2001 From: s-medvedev <40623263+s-medvedev@users.noreply.github.com> Date: Fri, 19 Jul 2024 20:37:35 +0700 Subject: [PATCH 272/318] SLA-99 Do not track update accounts for specific owners (#485) (#488) * SLA-99 Do not track update accounts for specific owners (#485) --------- Co-authored-by: Semen Medvedev --- evm_loader/program-macro/src/config_parser.rs | 9 +++++++++ evm_loader/program-macro/src/lib.rs | 13 +++++++++++++ evm_loader/program/config/default.toml | 3 +++ evm_loader/program/config/devnet.toml | 6 ++++++ evm_loader/program/config/govertest.toml | 3 +++ evm_loader/program/config/mainnet.toml | 6 ++++++ evm_loader/program/config/rollup.toml | 3 +++ evm_loader/program/config/testnet.toml | 3 +++ evm_loader/program/src/account/state.rs | 8 ++++++++ 9 files changed, 54 insertions(+) diff --git a/evm_loader/program-macro/src/config_parser.rs b/evm_loader/program-macro/src/config_parser.rs index 51848ae8f..77ccf1922 100644 --- a/evm_loader/program-macro/src/config_parser.rs +++ b/evm_loader/program-macro/src/config_parser.rs @@ -17,6 +17,7 @@ pub struct NetSpecificConfig { pub neon_chain_id: u64, pub neon_token_mint: String, pub chains: Vec, + pub no_update_tracking_owners: Vec, } impl Parse for NetSpecificConfig { @@ -38,6 +39,13 @@ impl Parse for NetSpecificConfig { .map(|v| v.as_str().unwrap().to_string()) .collect::>(); + let no_update_tracking_owners = root["no_update_tracking_owners"] + .as_array() + .unwrap() + .iter() + .map(|v| v.as_str().unwrap().to_string()) + .collect::>(); + let chains = root["chain"] .as_table() .unwrap() @@ -69,6 +77,7 @@ impl Parse for NetSpecificConfig { neon_chain_id, neon_token_mint, chains, + no_update_tracking_owners, }) } } diff --git a/evm_loader/program-macro/src/lib.rs b/evm_loader/program-macro/src/lib.rs index ec3b5c5c0..0eb1337fc 100644 --- a/evm_loader/program-macro/src/lib.rs +++ b/evm_loader/program-macro/src/lib.rs @@ -66,6 +66,7 @@ pub fn net_specific_config_parser(tokens: TokenStream) -> TokenStream { neon_chain_id, neon_token_mint, operators_whitelist, + no_update_tracking_owners, mut chains, } = parse_macro_input!(tokens as NetSpecificConfig); @@ -77,6 +78,14 @@ pub fn net_specific_config_parser(tokens: TokenStream) -> TokenStream { operators.sort_unstable(); let operators_len = operators.len(); + let mut no_update_tracking_owners: Vec> = no_update_tracking_owners + .iter() + .map(|key| bs58::decode(key).into_vec().unwrap()) + .collect(); + + no_update_tracking_owners.sort_unstable(); + let no_update_tracking_owners_len = no_update_tracking_owners.len(); + chains.sort_unstable_by_key(|c| c.id); let chains_len = chains.len(); @@ -100,6 +109,10 @@ pub fn net_specific_config_parser(tokens: TokenStream) -> TokenStream { #(::solana_program::pubkey::Pubkey::new_from_array([#((#operators),)*]),)* ]; + pub const NO_UPDATE_TRACKING_OWNERS: [::solana_program::pubkey::Pubkey; #no_update_tracking_owners_len] = [ + #(::solana_program::pubkey::Pubkey::new_from_array([#((#no_update_tracking_owners),)*]),)* + ]; + pub const CHAIN_ID_LIST: [(u64, &str, ::solana_program::pubkey::Pubkey); #chains_len] = [ #( (#chain_ids, #chain_names, ::solana_program::pubkey::Pubkey::new_from_array([#(#chain_tokens),*])) ),* ]; diff --git a/evm_loader/program/config/default.toml b/evm_loader/program/config/default.toml index 986667357..5939e4b37 100644 --- a/evm_loader/program/config/default.toml +++ b/evm_loader/program/config/default.toml @@ -1,4 +1,7 @@ program_id = "53DfF883gyixYNXnM7s5xhdeyV8mVk9T4i2hGV9vG9io" + +no_update_tracking_owners = [] + operators_whitelist = [ "9kPRbbwKL5SYELF4cZqWWFmP88QkKys51DoaUBx8eK73", "BMp6gEnveANdvSvspESJUrNczuHz1GF5UQKjVLCkAZih", diff --git a/evm_loader/program/config/devnet.toml b/evm_loader/program/config/devnet.toml index 00f47003c..319c98aec 100644 --- a/evm_loader/program/config/devnet.toml +++ b/evm_loader/program/config/devnet.toml @@ -1,4 +1,10 @@ program_id = "eeLSJgWzzxrqKv1UxtRVVH8FX3qCQWUs9QuAjJpETGU" + +no_update_tracking_owners = [ + "HEvSKofvBgfaexv23kMabbYqxasxU3mQ4ibBMEmJWHny", # Chainlink oracle + "rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ", # Pyth oracle +] + operators_whitelist = [ "NeoQM3utcHGxhKT41Nq81g8t4xGcPNFpkAgYj1N2N8v", "Gw3Xiwve6HdvpJeQguhwT23cpK9nRjSy1NpNYCFY4XU9", diff --git a/evm_loader/program/config/govertest.toml b/evm_loader/program/config/govertest.toml index c9fe2df8b..cce68f0b8 100644 --- a/evm_loader/program/config/govertest.toml +++ b/evm_loader/program/config/govertest.toml @@ -1,4 +1,7 @@ program_id = "53DfF883gyixYNXnM7s5xhdeyV8mVk9T4i2hGV9vG9io" + +no_update_tracking_owners = [] + operators_whitelist = [ "9kPRbbwKL5SYELF4cZqWWFmP88QkKys51DoaUBx8eK73", "BMp6gEnveANdvSvspESJUrNczuHz1GF5UQKjVLCkAZih", diff --git a/evm_loader/program/config/mainnet.toml b/evm_loader/program/config/mainnet.toml index e3660baf9..7e8204154 100644 --- a/evm_loader/program/config/mainnet.toml +++ b/evm_loader/program/config/mainnet.toml @@ -1,4 +1,10 @@ program_id = "NeonVMyRX5GbCrsAHnUwx1nYYoJAtskU1bWUo6JGNyG" + +no_update_tracking_owners = [ + "HEvSKofvBgfaexv23kMabbYqxasxU3mQ4ibBMEmJWHny", # Chainlink oracle + "rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ", # Pyth oracle +] + operators_whitelist = [ "NeonPQFrw5stVvs1rFLDxALWUBDCnSPsWBP83RfNUKK", "GYt9w8MaXztDLhhsxmQr7Ar9FJ6MmaFwav7qBrxZKwhd", diff --git a/evm_loader/program/config/rollup.toml b/evm_loader/program/config/rollup.toml index 93bf2290d..b19446e01 100644 --- a/evm_loader/program/config/rollup.toml +++ b/evm_loader/program/config/rollup.toml @@ -1,4 +1,7 @@ program_id = "EgbRZxFRQTiZpQGinE5jT6KQq5jtVnjtLdSTkW5UTcAv" + +no_update_tracking_owners = [] + operators_whitelist = [ "2Gsipy7yniskehFAccTp4ShhmdTiP8UsLWVFdxsG6ZGt", "2fx77qnumM3sw5duzMYod8c8xSLavE4RwJAdNdeYZpFq", diff --git a/evm_loader/program/config/testnet.toml b/evm_loader/program/config/testnet.toml index 8e22e1371..ef01514c7 100644 --- a/evm_loader/program/config/testnet.toml +++ b/evm_loader/program/config/testnet.toml @@ -1,4 +1,7 @@ program_id = "eeLSJgWzzxrqKv1UxtRVVH8FX3qCQWUs9QuAjJpETGU" + +no_update_tracking_owners = [] + operators_whitelist = [ "NeoQM3utcHGxhKT41Nq81g8t4xGcPNFpkAgYj1N2N8v", "Gw3Xiwve6HdvpJeQguhwT23cpK9nRjSy1NpNYCFY4XU9", diff --git a/evm_loader/program/src/account/state.rs b/evm_loader/program/src/account/state.rs index f02ba689b..9fac9299b 100644 --- a/evm_loader/program/src/account/state.rs +++ b/evm_loader/program/src/account/state.rs @@ -11,6 +11,7 @@ use crate::types::serde::bytes_32; use crate::types::{Address, Transaction}; use ethnum::U256; use serde::{Deserialize, Serialize}; +use solana_program::hash::Hash; use solana_program::system_program; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; @@ -35,6 +36,13 @@ enum AccountRevision { impl AccountRevision { pub fn new(program_id: &Pubkey, info: &AccountInfo) -> Self { if (info.owner != program_id) && !system_program::check_id(info.owner) { + if crate::config::NO_UPDATE_TRACKING_OWNERS + .binary_search(info.owner) + .is_ok() + { + return AccountRevision::Hash(Hash::default().to_bytes()); + } + let hash = solana_program::hash::hashv(&[ info.owner.as_ref(), &info.lamports().to_le_bytes(), From 4669ba8a8c832562590e674d343e91e6b0795ee8 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Fri, 19 Jul 2024 16:44:37 +0300 Subject: [PATCH 273/318] SLA-110 Ignore Pyth legacy accounts (#503) --- evm_loader/program/config/devnet.toml | 1 + evm_loader/program/config/mainnet.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/evm_loader/program/config/devnet.toml b/evm_loader/program/config/devnet.toml index 319c98aec..06761ba8b 100644 --- a/evm_loader/program/config/devnet.toml +++ b/evm_loader/program/config/devnet.toml @@ -3,6 +3,7 @@ program_id = "eeLSJgWzzxrqKv1UxtRVVH8FX3qCQWUs9QuAjJpETGU" no_update_tracking_owners = [ "HEvSKofvBgfaexv23kMabbYqxasxU3mQ4ibBMEmJWHny", # Chainlink oracle "rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ", # Pyth oracle + "gSbePebfvPy7tRqimPoVecS2UsBvYv46ynrzWocc92s", # Pyth legacy oracle ] operators_whitelist = [ diff --git a/evm_loader/program/config/mainnet.toml b/evm_loader/program/config/mainnet.toml index 7e8204154..b037c0165 100644 --- a/evm_loader/program/config/mainnet.toml +++ b/evm_loader/program/config/mainnet.toml @@ -3,6 +3,7 @@ program_id = "NeonVMyRX5GbCrsAHnUwx1nYYoJAtskU1bWUo6JGNyG" no_update_tracking_owners = [ "HEvSKofvBgfaexv23kMabbYqxasxU3mQ4ibBMEmJWHny", # Chainlink oracle "rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ", # Pyth oracle + "FsJ3A3u2vn5cTVofAjvy6y5kwABJAqYWpe4975bi2epH", # Pyth legacy oracle ] operators_whitelist = [ From 6bd36a7a40fa3fc04f60bfc1ca10635437250b73 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Fri, 19 Jul 2024 19:01:11 +0300 Subject: [PATCH 274/318] SLA-115 correctly handle empty accounts (#504) --- evm_loader/lib/src/account_storage.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index 3fd6be96b..5776845a3 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -543,6 +543,7 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { self._add_legacy_storage(&legacy_storage, &info, pubkey) .await } + evm_loader::account::TAG_EMPTY => Ok(self.add_empty_account(pubkey)), _ => { unimplemented!(); } From 47fd840e1e85411bf4df391a3f111302caa46614 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 20 Jul 2024 18:34:33 +0300 Subject: [PATCH 275/318] Bump serde_with from 3.8.3 to 3.9.0 in /evm_loader (#502) Bumps [serde_with](https://github.com/jonasbb/serde_with) from 3.8.3 to 3.9.0. - [Release notes](https://github.com/jonasbb/serde_with/releases) - [Commits](https://github.com/jonasbb/serde_with/compare/v3.8.3...v3.9.0) --- updated-dependencies: - dependency-name: serde_with dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 12 ++++++------ evm_loader/lib/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index ddb07ddc4..6cbee83ea 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -3379,7 +3379,7 @@ dependencies = [ "scroll", "serde", "serde_json", - "serde_with 3.8.3", + "serde_with 3.9.0", "solana-account-decoder", "solana-accounts-db", "solana-cli", @@ -4784,9 +4784,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.8.3" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e73139bc5ec2d45e6c5fd85be5a46949c1c39a4c18e56915f5eb4c12f975e377" +checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" dependencies = [ "base64 0.22.1", "chrono", @@ -4796,7 +4796,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "serde_with_macros 3.8.3", + "serde_with_macros 3.9.0", "time", ] @@ -4814,9 +4814,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.8.3" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b80d3d6b56b64335c0180e5ffde23b3c5e08c14c585b51a15bd0e95393f46703" +checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" dependencies = [ "darling", "proc-macro2", diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 82fb960cc..d44963722 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -26,7 +26,7 @@ base64 = "0.22" hex = { version = "0.4", features = ["serde"] } serde = "1.0" serde_json = { version = "1.0", features = ["preserve_order"] } -serde_with = { version = "3.8", features = ["hex"] } +serde_with = { version = "3.9", features = ["hex"] } log = "0.4.22" rand = "0.8" ethnum = { version = "1.5", default-features = false, features = ["serde"] } From 60285c72c728db634b7f38be77e84293c0bacf2e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 21 Jul 2024 00:54:14 +0300 Subject: [PATCH 276/318] Bump thiserror from 1.0.62 to 1.0.63 in /evm_loader (#505) Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.62 to 1.0.63. - [Release notes](https://github.com/dtolnay/thiserror/releases) - [Commits](https://github.com/dtolnay/thiserror/compare/1.0.62...1.0.63) --- updated-dependencies: - dependency-name: thiserror dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 8 ++++---- evm_loader/rpc-client/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 6cbee83ea..c312de8b8 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -6555,18 +6555,18 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.62" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2675633b1499176c2dff06b0856a27976a8f9d436737b4cf4f312d4d91d8bbb" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.62" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d20468752b09f49e909e55a5d338caa8bedf615594e9d80bc4c565d30faf798c" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", diff --git a/evm_loader/rpc-client/Cargo.toml b/evm_loader/rpc-client/Cargo.toml index 55f86378c..773cd83be 100644 --- a/evm_loader/rpc-client/Cargo.toml +++ b/evm_loader/rpc-client/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" serde = "1.0.204" serde_json = "1.0.120" neon-lib = { path = "../lib" } -thiserror = "1.0.62" +thiserror = "1.0.63" async-trait = "0.1.81" jsonrpsee-core = "0.22.3" jsonrpsee-http-client = "0.22.3" From 9febc469a77cccbefb3136b1b72a4313d9cebb70 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Wed, 24 Jul 2024 11:54:53 +0200 Subject: [PATCH 277/318] NDEV-3110: Update Solana to v1.18.18 (#302) * NDEV-2736: Update Solana to v1.18.18 Fix SolanaSimulator Bank creation logic Fix replace_blockhash Use ACCOUNTS_DB_CONFIG_FOR_TESTING Enable dev-context-only-utils feature Use 0 flush_threads Increase --limit-ledger-size 400000000 Use cargo build-sbf * Add id to requests * Truncate data in AccountData Debug impl * More logs New logs to debug level * Use Solana message processor Fix program_indices wip Add TODO wip wip wip wip wip wip wip wip Transation execution works Populate TransactionExecutionDetails Try fix simulate_transaction Clean up error handling cargo clippy cargo clippy cargo clippy Complete process_transaction More simulate_transaction Use TransactionSimulationResult to return post_simulation_accounts Add test_encode Remove TransactionExecutionDetails usage Log encoded tx Remove unused genesis_config_info Remove unused sync_sysvar_accounts Remove unused errors Remove redundant timings logic Make some logs debug Remove unused code Extract load_programs Extract build_program_indices Make fn private Cleanup Cleanup Fix sync_sysvar_accounts Fix tx JSON encoding * More logs * Address code review * Revert "More logs" This reverts commit fc4acabb72c3da846855d4ab8867ead45a7175e1. --------- Co-authored-by: Anton Lisanin --- .github/workflows/deploy.py | 4 +- Dockerfile | 18 +- ci/solana-run-neon.sh | 1 + evm_loader/Cargo.lock | 1925 +++++++++-------- evm_loader/Cargo.toml | 23 +- evm_loader/api/Cargo.toml | 4 +- evm_loader/cli/Cargo.toml | 4 +- evm_loader/lib-interface/Cargo.toml | 2 +- evm_loader/lib/Cargo.toml | 15 +- evm_loader/lib/src/account_data.rs | 35 +- evm_loader/lib/src/account_storage.rs | 15 +- evm_loader/lib/src/commands/emulate.rs | 8 +- evm_loader/lib/src/commands/get_config.rs | 3 +- .../lib/src/commands/simulate_solana.rs | 29 +- evm_loader/lib/src/commands/trace.rs | 7 +- .../lib/src/commands/transaction_executor.rs | 1 + evm_loader/lib/src/rpc/db_call_client.rs | 2 + evm_loader/lib/src/rpc/emulator_client.rs | 5 + evm_loader/lib/src/rpc/validator_client.rs | 13 + evm_loader/lib/src/solana_simulator/error.rs | 16 +- evm_loader/lib/src/solana_simulator/mod.rs | 686 ++++-- evm_loader/lib/src/solana_simulator/utils.rs | 114 +- evm_loader/lib/src/types/mod.rs | 6 + evm_loader/lib/src/types/tracer_ch_common.rs | 2 +- evm_loader/lib/src/types/tracer_ch_db.rs | 52 +- evm_loader/program-macro/src/config_parser.rs | 2 +- evm_loader/program/Cargo.toml | 10 +- evm_loader/program/src/account/mod.rs | 1 + evm_loader/program/src/account/state.rs | 1 + evm_loader/rpc-client/Cargo.toml | 6 +- evm_loader/rpc/Cargo.toml | 2 +- rust-toolchain.toml | 2 +- 32 files changed, 1767 insertions(+), 1247 deletions(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index 23b131ccc..75d30904c 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -32,8 +32,8 @@ IMAGE_NAME = os.environ.get("IMAGE_NAME") RUN_LINK_REPO = os.environ.get("RUN_LINK_REPO") DOCKERHUB_ORG_NAME = os.environ.get("DOCKERHUB_ORG_NAME") -SOLANA_NODE_VERSION = 'v1.17.34' -SOLANA_BPF_VERSION = 'v1.17.34' +SOLANA_NODE_VERSION = 'v1.18.18' +SOLANA_BPF_VERSION = 'v1.18.18' VERSION_BRANCH_TEMPLATE = r"[vt]{1}\d{1,2}\.\d{1,2}\.x.*" docker_client = docker.APIClient() diff --git a/Dockerfile b/Dockerfile index d1e42ca8b..b82ac9665 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ ARG SOLANA_IMAGE # Install BPF SDK -FROM solanalabs/rust:1.73.0 AS builder +FROM solanalabs/rust:1.75.0 AS builder RUN cargo install rustfilt WORKDIR /opt ARG SOLANA_BPF_VERSION @@ -20,14 +20,14 @@ RUN cargo fmt --check && \ cargo clippy --release && \ cargo build --release && \ cargo test --release && \ - cargo build-bpf --manifest-path program/Cargo.toml --features devnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-devnet.so && \ - cargo build-bpf --manifest-path program/Cargo.toml --features testnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-testnet.so && \ - cargo build-bpf --manifest-path program/Cargo.toml --features govertest && cp target/deploy/evm_loader.so target/deploy/evm_loader-govertest.so && \ - cargo build-bpf --manifest-path program/Cargo.toml --features govertest,emergency && cp target/deploy/evm_loader.so target/deploy/evm_loader-govertest-emergency.so && \ - cargo build-bpf --manifest-path program/Cargo.toml --features mainnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-mainnet.so && \ - cargo build-bpf --manifest-path program/Cargo.toml --features mainnet,emergency && cp target/deploy/evm_loader.so target/deploy/evm_loader-mainnet-emergency.so && \ - cargo build-bpf --manifest-path program/Cargo.toml --features rollup && cp target/deploy/evm_loader.so target/deploy/evm_loader-rollup.so && \ - cargo build-bpf --manifest-path program/Cargo.toml --features ci --dump + cargo build-sbf --manifest-path program/Cargo.toml --features devnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-devnet.so && \ + cargo build-sbf --manifest-path program/Cargo.toml --features testnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-testnet.so && \ + cargo build-sbf --manifest-path program/Cargo.toml --features govertest && cp target/deploy/evm_loader.so target/deploy/evm_loader-govertest.so && \ + cargo build-sbf --manifest-path program/Cargo.toml --features govertest,emergency && cp target/deploy/evm_loader.so target/deploy/evm_loader-govertest-emergency.so && \ + cargo build-sbf --manifest-path program/Cargo.toml --features mainnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-mainnet.so && \ + cargo build-sbf --manifest-path program/Cargo.toml --features mainnet,emergency && cp target/deploy/evm_loader.so target/deploy/evm_loader-mainnet-emergency.so && \ + cargo build-sbf --manifest-path program/Cargo.toml --features rollup && cp target/deploy/evm_loader.so target/deploy/evm_loader-rollup.so && \ + cargo build-sbf --manifest-path program/Cargo.toml --features ci --dump # Add neon_test_invoke_program to the genesis diff --git a/ci/solana-run-neon.sh b/ci/solana-run-neon.sh index b7b35527b..78033faf5 100755 --- a/ci/solana-run-neon.sh +++ b/ci/solana-run-neon.sh @@ -20,6 +20,7 @@ VALIDATOR_ARGS=( --ticks-per-slot 16 --upgradeable-program ${EVM_LOADER} ${EVM_LOADER_PATH} ${EVM_LOADER_AUTHORITY_KEYPAIR} --bpf-program ${METAPLEX} ${METAPLEX_PATH} + --limit-ledger-size 400000000 ) LIST_OF_TEST_PROGRAMS=("test_invoke_program" "counter" "cross_program_invocation" "transfer_sol" "transfer_tokens") diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index c312de8b8..fda9508b1 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -62,11 +62,11 @@ dependencies = [ [[package]] name = "actix-codec" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8" +checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "bytes", "futures-core", "futures-sink", @@ -79,18 +79,18 @@ dependencies = [ [[package]] name = "actix-http" -version = "3.7.0" +version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb9843d84c775696c37d9a418bbb01b932629d01870722c0f13eb3f95e2536d" +checksum = "3ae682f693a9cd7b058f2b0b5d9a6d7728a8555779bedbbc35dd88528611d020" dependencies = [ "actix-codec", "actix-rt", "actix-service", "actix-utils", - "ahash 0.8.5", + "ahash 0.8.11", "base64 0.22.1", - "bitflags 2.4.0", - "brotli 6.0.0", + "bitflags 2.6.0", + "brotli", "bytes", "bytestring", "derive_more", @@ -113,7 +113,7 @@ dependencies = [ "tokio", "tokio-util", "tracing", - "zstd 0.13.0", + "zstd 0.13.2", ] [[package]] @@ -123,7 +123,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -154,9 +154,9 @@ dependencies = [ [[package]] name = "actix-rt" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28f32d40287d3f402ae0028a9d54bef51af15c8769492826a69d28f81893151d" +checksum = "24eda4e2a6e042aa4e55ac438a2ae052d3b5da0ecf83d7411e1a368946925208" dependencies = [ "futures-core", "tokio", @@ -164,9 +164,9 @@ dependencies = [ [[package]] name = "actix-server" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eb13e7eef0423ea6eab0e59f6c72e7cb46d33691ad56a726b3cd07ddec2c2d4" +checksum = "b02303ce8d4e8be5b855af6cf3c3a08f3eff26880faad82bab679c22d3650cb5" dependencies = [ "actix-rt", "actix-service", @@ -174,7 +174,7 @@ dependencies = [ "futures-core", "futures-util", "mio", - "socket2 0.5.4", + "socket2", "tokio", "tracing", ] @@ -215,7 +215,7 @@ dependencies = [ "actix-service", "actix-utils", "actix-web-codegen", - "ahash 0.8.5", + "ahash 0.8.11", "bytes", "bytestring", "cfg-if", @@ -236,7 +236,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "smallvec", - "socket2 0.5.4", + "socket2", "time", "url", ] @@ -250,14 +250,14 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] name = "addr2line" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "gimli", ] @@ -306,23 +306,23 @@ dependencies = [ [[package]] name = "ahash" -version = "0.7.6" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom 0.2.12", + "getrandom 0.2.15", "once_cell", "version_check", ] [[package]] name = "ahash" -version = "0.8.5" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7d5a2cecb58716e47d67d5703a249964b14c7be1ec3cad3affc295b2d1c35d" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom 0.2.12", + "getrandom 0.2.15", "once_cell", "version_check", "zerocopy", @@ -330,9 +330,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.1" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -388,6 +388,20 @@ version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +[[package]] +name = "aquamarine" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1da02abba9f9063d786eab1509833ebb2fac0f966862ca59439c76b9c566760" +dependencies = [ + "include_dir", + "itertools 0.10.5", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "ark-bn254" version = "0.4.0" @@ -429,7 +443,7 @@ dependencies = [ "derivative", "digest 0.10.7", "itertools 0.10.5", - "num-bigint 0.4.4", + "num-bigint 0.4.6", "num-traits", "paste", "rustc_version", @@ -452,7 +466,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" dependencies = [ - "num-bigint 0.4.4", + "num-bigint 0.4.6", "num-traits", "proc-macro2", "quote", @@ -481,7 +495,7 @@ dependencies = [ "ark-serialize-derive", "ark-std", "digest 0.10.7", - "num-bigint 0.4.4", + "num-bigint 0.4.6", ] [[package]] @@ -507,9 +521,9 @@ dependencies = [ [[package]] name = "arrayref" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" +checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" [[package]] name = "arrayvec" @@ -593,11 +607,11 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.2" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d495b6dc0184693324491a5ac05f559acc97bf937ab31d7a1c33dd0016be6d2b" +checksum = "fec134f64e2bc57411226dfc4e52dec859ddfc7e711fc5e07b612584f000e4aa" dependencies = [ - "brotli 3.3.4", + "brotli", "flate2", "futures-core", "memchr", @@ -631,7 +645,7 @@ checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -647,15 +661,15 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" dependencies = [ "addr2line", "cc", @@ -722,9 +736,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" dependencies = [ "serde", ] @@ -752,9 +766,9 @@ dependencies = [ [[package]] name = "blake3" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87" +checksum = "30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52" dependencies = [ "arrayref", "arrayvec", @@ -809,6 +823,16 @@ dependencies = [ "hashbrown 0.13.2", ] +[[package]] +name = "borsh" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed" +dependencies = [ + "borsh-derive 1.5.1", + "cfg_aliases 0.2.1", +] + [[package]] name = "borsh-derive" version = "0.9.3" @@ -835,6 +859,20 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "borsh-derive" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b" +dependencies = [ + "once_cell", + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.72", + "syn_derive", +] + [[package]] name = "borsh-derive-internal" version = "0.9.3" @@ -879,17 +917,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "brotli" -version = "3.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor 2.3.4", -] - [[package]] name = "brotli" version = "6.0.0" @@ -898,24 +925,14 @@ checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", - "brotli-decompressor 4.0.0", -] - -[[package]] -name = "brotli-decompressor" -version = "2.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", + "brotli-decompressor", ] [[package]] name = "brotli-decompressor" -version = "4.0.0" +version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6221fe77a248b9117d431ad93761222e1cf8ff282d9d1d5d9f53d6299a1cf76" +checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -938,9 +955,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.4.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d4260bcc2e8fc9df1eac4919a720effeb63a3f0952f5bf4944adfa18897f09" +checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" dependencies = [ "memchr", ] @@ -973,7 +990,7 @@ dependencies = [ "pretty_assertions", "rustc_version", "serde_json", - "zstd 0.13.0", + "zstd 0.13.2", ] [[package]] @@ -999,21 +1016,21 @@ dependencies = [ "bincode", "build-info-common", "chrono", - "num-bigint 0.4.4", + "num-bigint 0.4.6", "num-traits", "proc-macro-error", "proc-macro2", "quote", "serde_json", - "syn 2.0.71", - "zstd 0.13.0", + "syn 2.0.72", + "zstd 0.13.2", ] [[package]] name = "bumpalo" -version = "3.12.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bv" @@ -1033,35 +1050,35 @@ checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" [[package]] name = "bytemuck" -version = "1.14.3" +version = "1.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2ef034f05691a48569bd920a96c81b9d91bbad1ab5ac7c4616c1f6ef36cb79f" +checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.4.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192" +checksum = "1ee891b04274a59bd38b412188e24b849617b2e45a0fd8d057deb63e7403761b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952" [[package]] name = "bytestring" @@ -1095,9 +1112,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" dependencies = [ "serde", ] @@ -1114,9 +1131,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.4" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12024c4645c97566567129c204f65d5815a8c9aecf30fcbe682b2fe034996d36" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" dependencies = [ "serde", ] @@ -1146,9 +1163,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.83" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f" dependencies = [ "jobserver", "libc", @@ -1160,11 +1177,23 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chrono" -version = "0.4.34" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", @@ -1172,7 +1201,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.52.3", + "windows-targets 0.52.6", ] [[package]] @@ -1201,9 +1230,9 @@ dependencies = [ [[package]] name = "clap" -version = "3.2.23" +version = "3.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" dependencies = [ "atty", "bitflags 1.3.2", @@ -1212,7 +1241,7 @@ dependencies = [ "once_cell", "strsim 0.10.0", "termcolor", - "textwrap 0.16.0", + "textwrap 0.16.1", ] [[package]] @@ -1267,16 +1296,6 @@ dependencies = [ "cc", ] -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - [[package]] name = "combine" version = "3.8.1" @@ -1292,24 +1311,24 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "2.2.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ "crossbeam-utils", ] [[package]] name = "console" -version = "0.15.7" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" dependencies = [ "encode_unicode", "lazy_static", "libc", "unicode-width", - "windows-sys 0.45.0", + "windows-sys 0.52.0", ] [[package]] @@ -1389,9 +1408,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -1399,9 +1418,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "core_extensions" @@ -1420,18 +1439,18 @@ checksum = "69f3b219d28b6e3b4ac87bc1fc522e0803ab22e055da177bff0068c4150c61a6" [[package]] name = "cpufeatures" -version = "0.2.6" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "280a9f2d8b3a38871a3c8a46fb80db65e5e5ed97da80c4d08bf27fb63e35e181" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] @@ -1451,46 +1470,37 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.8" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" dependencies = [ - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.14" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "autocfg", - "cfg-if", "crossbeam-utils", - "memoffset 0.8.0", - "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.15" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" -dependencies = [ - "cfg-if", -] +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -1529,12 +1539,12 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.4.1" +version = "3.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e95fbd621905b854affdc67943b043a0fbb6ed7385fd5a25650d19a8a6cfdf" +checksum = "672465ae37dc1bc6380a6547a8883d5dd397b0f1faaad4f265726cc7042a5345" dependencies = [ - "nix 0.27.1", - "windows-sys 0.48.0", + "nix 0.28.0", + "windows-sys 0.52.0", ] [[package]] @@ -1551,55 +1561,11 @@ dependencies = [ "zeroize", ] -[[package]] -name = "cxx" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn 2.0.71", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.71", -] - [[package]] name = "darling" -version = "0.20.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ "darling_core", "darling_macro", @@ -1607,45 +1573,48 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", - "strsim 0.10.0", - "syn 2.0.71", + "strsim 0.11.1", + "syn 2.0.72", ] [[package]] name = "darling_macro" -version = "0.20.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] name = "dashmap" -version = "4.0.2" +version = "5.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", - "num_cpus", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", "rayon", ] [[package]] name = "data-encoding" -version = "2.3.3" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "der" @@ -1665,7 +1634,7 @@ dependencies = [ "asn1-rs", "displaydoc", "nom", - "num-bigint 0.4.4", + "num-bigint 0.4.6", "num-traits", "rusticata-macros", ] @@ -1699,15 +1668,15 @@ dependencies = [ [[package]] name = "derive_more" -version = "0.99.17" +version = "0.99.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ "convert_case", "proc-macro2", "quote", "rustc_version", - "syn 1.0.109", + "syn 2.0.72", ] [[package]] @@ -1728,6 +1697,12 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +[[package]] +name = "difflib" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" + [[package]] name = "digest" version = "0.9.0" @@ -1750,9 +1725,9 @@ dependencies = [ [[package]] name = "dir-diff" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2860407d7d7e2e004bb2128510ad9e8d669e76fa005ccf567977b5d71b8b4a0b" +checksum = "a7ad16bf5f84253b50d6557681c58c3ab67c47c77d39fed9aeb56e947290bd10" dependencies = [ "walkdir", ] @@ -1780,13 +1755,13 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.72", ] [[package]] @@ -1809,9 +1784,15 @@ checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] +[[package]] +name = "downcast" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" + [[package]] name = "eager" version = "0.1.0" @@ -1855,9 +1836,9 @@ dependencies = [ [[package]] name = "either" -version = "1.10.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "elsa" @@ -1876,31 +1857,31 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.32" +version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" dependencies = [ "cfg-if", ] [[package]] name = "enum-iterator" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7add3873b5dd076766ee79c8e406ad1a472c385476b9e38849f8eec24f1be689" +checksum = "9fd242f399be1da0a5354aa462d57b4ab2b4ee0683cc552f7c007d2d12d36e94" dependencies = [ "enum-iterator-derive", ] [[package]] name = "enum-iterator-derive" -version = "1.2.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eecf8589574ce9b895052fa12d69af7a233f99e6107f5cb8dd1044f2a17bfdcb" +checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -1912,7 +1893,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -1945,9 +1926,9 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys 0.52.0", @@ -1965,7 +1946,7 @@ dependencies = [ "regex", "serde", "serde_json", - "sha3 0.10.7", + "sha3 0.10.8", "thiserror", "uint", ] @@ -2051,8 +2032,8 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.71", - "toml 0.8.2", + "syn 2.0.72", + "toml 0.8.15", ] [[package]] @@ -2066,9 +2047,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "feature-probe" @@ -2087,14 +2068,14 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.22" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.3.5", - "windows-sys 0.48.0", + "redox_syscall 0.4.1", + "windows-sys 0.52.0", ] [[package]] @@ -2111,14 +2092,23 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.27" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" dependencies = [ "crc32fast", "miniz_oxide", ] +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +dependencies = [ + "num-traits", +] + [[package]] name = "fnv" version = "1.0.7" @@ -2150,13 +2140,10 @@ dependencies = [ ] [[package]] -name = "fs-err" -version = "2.11.0" +name = "fragile" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" -dependencies = [ - "autocfg", -] +checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "fuchsia-cprng" @@ -2172,9 +2159,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", @@ -2187,9 +2174,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", @@ -2197,15 +2184,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", @@ -2214,44 +2201,44 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-timer" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-channel", "futures-core", @@ -2319,9 +2306,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "js-sys", @@ -2332,9 +2319,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "git2" @@ -2342,7 +2329,7 @@ version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b903b73e45dc0c6c596f2d37eccece7c1c8bb6e4407b001096387c63d0d93724" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.6.0", "libc", "libgit2-sys", "log", @@ -2363,18 +2350,18 @@ checksum = "a7666983ed0dd8d21a6f6576ee00053ca0926fb281a5522577a4dbd0f1b54143" dependencies = [ "log", "plain", - "scroll", + "scroll 0.11.0", ] [[package]] name = "goblin" -version = "0.6.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6b4de4a8eb6c46a8c77e1d3be942cb9a8bf073c22374578e5ba4b08ed0ff68" +checksum = "1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47" dependencies = [ "log", "plain", - "scroll", + "scroll 0.12.0", ] [[package]] @@ -2389,7 +2376,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 2.2.3", + "indexmap 2.2.6", "slab", "tokio", "tokio-util", @@ -2411,7 +2398,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" dependencies = [ - "ahash 0.7.6", + "ahash 0.7.8", ] [[package]] @@ -2420,7 +2407,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash 0.7.6", + "ahash 0.7.8", ] [[package]] @@ -2429,14 +2416,14 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash 0.8.5", + "ahash 0.8.11", ] [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "headers" @@ -2494,9 +2481,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.1" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hex" @@ -2515,14 +2502,15 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "hidapi" -version = "2.4.1" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "723777263b0dcc5730aec947496bd8c3940ba63c15f5633b288cc615f4f6af79" +checksum = "9e58251020fe88fe0dae5ebcc1be92b4995214af84725b375d08354d0311c23c" dependencies = [ "cc", + "cfg-if", "libc", "pkg-config", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -2563,9 +2551,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.9" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", @@ -2574,9 +2562,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http", @@ -2585,15 +2573,15 @@ dependencies = [ [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "humantime" @@ -2603,9 +2591,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.27" +version = "0.14.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" dependencies = [ "bytes", "futures-channel", @@ -2618,7 +2606,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.9", + "socket2", "tokio", "tower-service", "tracing", @@ -2627,9 +2615,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", "http", @@ -2656,26 +2644,25 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.56" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows", + "windows-core", ] [[package]] name = "iana-time-zone-haiku" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ - "cxx", - "cxx-build", + "cc", ] [[package]] @@ -2758,11 +2745,30 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "include_dir" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd" +dependencies = [ + "include_dir_macros", +] + +[[package]] +name = "include_dir_macros" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "index_list" -version = "0.2.7" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9d968042a4902e08810946fc7cd5851eb75e80301342305af755ca06cb82ce" +checksum = "2cb725b6505e51229de32027e0cfcd9db29da4d89156f9747b0a5195643fa3e1" [[package]] name = "indexmap" @@ -2777,12 +2783,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.3" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "serde", ] @@ -2801,18 +2807,18 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ "cfg-if", ] [[package]] name = "ipnet" -version = "2.7.2" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "itertools" @@ -2834,24 +2840,24 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jobserver" -version = "0.1.26" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -2890,9 +2896,9 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.22.3" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71962a1c49af43adf81d337e4ebc93f3c915faf6eccaa14d74e255107dfd7723" +checksum = "b4b257e1ec385e07b0255dde0b933f948b5c8b8c28d42afda9587c3a967b896d" dependencies = [ "anyhow", "async-trait", @@ -2909,9 +2915,9 @@ dependencies = [ [[package]] name = "jsonrpsee-http-client" -version = "0.22.3" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c13987da51270bda2c1c9b40c19be0fe9b225c7a0553963d8f17e683a50ce84" +checksum = "1ccf93fc4a0bfe05d851d37d7c32b7f370fe94336b52a2f0efc5f1981895c2e5" dependencies = [ "async-trait", "hyper", @@ -2929,9 +2935,9 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.22.3" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e53c72de6cd2ad6ac1aa6e848206ef8b736f92ed02354959130373dfa5b3cbd" +checksum = "150d6168405890a7a3231a3c74843f58b8959471f6df76078db2619ddee1d07d" dependencies = [ "anyhow", "beef", @@ -2942,9 +2948,9 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" dependencies = [ "cpufeatures", ] @@ -2963,9 +2969,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libgit2-sys" @@ -2989,6 +2995,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.6.0", + "libc", +] + [[package]] name = "libsecp256k1" version = "0.6.0" @@ -3039,9 +3055,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.12" +version = "1.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97137b25e321a73eef1418d1d5d2eda4d77e12813f8e6dead84bc52c5870a7b" +checksum = "c15da26e5af7e25c90b37a2d75cdbf940cf4a55316de9d84c679c9b8bfabf82e" dependencies = [ "cc", "libc", @@ -3057,19 +3073,10 @@ checksum = "3c9a85a9752c549ceb7578064b4ed891179d20acd85f27318573b64d2d7ee7ee" dependencies = [ "ark-bn254", "ark-ff", - "num-bigint 0.4.4", + "num-bigint 0.4.6", "thiserror", ] -[[package]] -name = "link-cplusplus" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" -dependencies = [ - "cc", -] - [[package]] name = "linked_list_allocator" version = "0.10.5" @@ -3078,9 +3085,9 @@ checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286" [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "local-channel" @@ -3101,9 +3108,9 @@ checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -3126,9 +3133,9 @@ dependencies = [ [[package]] name = "lz4" -version = "1.24.0" +version = "1.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e9e2dd86df36ce760a60f6ff6ad526f7ba1f14ba0356f8254fb6905e6494df1" +checksum = "958b4caa893816eea05507c20cfe47574a43d9a697138a7872990bba8a0ece68" dependencies = [ "libc", "lz4-sys", @@ -3136,9 +3143,9 @@ dependencies = [ [[package]] name = "lz4-sys" -version = "1.9.4" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d27b317e207b10f69f5e75494119e391a96f48861ae870d1da6edac98ca900" +checksum = "109de74d5d2353660401699a4174a4ff23fcc649caf553df71933c7fb45ad868" dependencies = [ "cc", "libc", @@ -3161,14 +3168,14 @@ checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" @@ -3190,18 +3197,9 @@ dependencies = [ [[package]] name = "memoffset" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" -dependencies = [ - "autocfg", -] - -[[package]] -name = "memoffset" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" dependencies = [ "autocfg", ] @@ -3232,9 +3230,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", ] @@ -3251,6 +3249,33 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "mockall" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c84490118f2ee2d74570d114f3d0493cbf02790df303d2707606c3e14e07c96" +dependencies = [ + "cfg-if", + "downcast", + "fragile", + "lazy_static", + "mockall_derive", + "predicates", + "predicates-tree", +] + +[[package]] +name = "mockall_derive" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "modular-bitfield" version = "0.11.2" @@ -3274,9 +3299,9 @@ dependencies = [ [[package]] name = "mpl-token-metadata" -version = "4.1.1" +version = "4.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b2de608098eb2ef2a5392069dea83084967e25a4d69d0380a6bb02454fc0fe" +checksum = "caf0f61b553e424a6234af1268456972ee66c2222e1da89079242251fa7479e5" dependencies = [ "borsh 0.10.3", "num-derive 0.3.3", @@ -3287,11 +3312,10 @@ dependencies = [ [[package]] name = "native-tls" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" dependencies = [ - "lazy_static", "libc", "log", "openssl", @@ -3368,7 +3392,7 @@ dependencies = [ "enum_dispatch", "ethnum", "evm-loader", - "goblin 0.6.1", + "goblin 0.8.2", "hex", "hex-literal", "hyper", @@ -3376,18 +3400,21 @@ dependencies = [ "log", "neon-lib-interface", "rand 0.8.5", - "scroll", + "scroll 0.12.0", "serde", "serde_json", "serde_with 3.9.0", "solana-account-decoder", "solana-accounts-db", + "solana-bpf-loader-program", "solana-cli", "solana-cli-config", "solana-client", + "solana-loader-v4-program", "solana-program-runtime", "solana-runtime", "solana-sdk", + "solana-transaction-status", "spl-associated-token-account", "spl-token", "strum 0.26.3", @@ -3462,12 +3489,13 @@ dependencies = [ [[package]] name = "nix" -version = "0.27.1" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.6.0", "cfg-if", + "cfg_aliases 0.1.1", "libc", ] @@ -3481,6 +3509,12 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "normalize-line-endings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -3518,11 +3552,10 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ - "autocfg", "num-integer", "num-traits", ] @@ -3556,30 +3589,29 @@ dependencies = [ [[package]] name = "num-derive" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfb77679af88f8b125209d354a202862602672222e7f2313fdd6dc349bad4712" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-iter" -version = "0.1.43" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ "autocfg", "num-integer", @@ -3600,9 +3632,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] @@ -3613,7 +3645,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.1", + "hermit-abi 0.3.9", "libc", ] @@ -3628,11 +3660,11 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683751d591e6d81200c39fb0d1032608b77724f34114db54f571ff1317b337c0" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" dependencies = [ - "num_enum_derive 0.7.1", + "num_enum_derive 0.7.2", ] [[package]] @@ -3644,19 +3676,19 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] name = "num_enum_derive" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c11e44798ad209ccdd91fc192f0526a369a01234f7373e1b141c96d7cee4f0e" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" dependencies = [ - "proc-macro-crate 1.3.1", + "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -3667,9 +3699,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "object" -version = "0.32.2" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" dependencies = [ "memchr", ] @@ -3691,17 +3723,17 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opaque-debug" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.64" +version = "0.10.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" +checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.6.0", "cfg-if", "foreign-types", "libc", @@ -3718,7 +3750,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -3729,9 +3761,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.101" +version = "0.9.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff" +checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" dependencies = [ "cc", "libc", @@ -3741,9 +3773,9 @@ dependencies = [ [[package]] name = "os_str_bytes" -version = "6.5.0" +version = "6.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" [[package]] name = "ouroboros" @@ -3776,9 +3808,9 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "parity-scale-codec" -version = "3.6.4" +version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8e946cc0cc711189c0b0249fb8b599cbeeab9784d83c415719368bb8d4ac64" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" dependencies = [ "arrayvec", "bitvec", @@ -3790,11 +3822,11 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.6.4" +version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a296c3079b5fefbc499e1de58dc26c09b1b9a5952d26694ee89f04a43ebbb3e" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" dependencies = [ - "proc-macro-crate 1.3.1", + "proc-macro-crate 3.1.0", "proc-macro2", "quote", "syn 1.0.109", @@ -3802,9 +3834,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -3812,22 +3844,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.7" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.2.16", + "redox_syscall 0.5.3", "smallvec", - "windows-sys 0.45.0", + "windows-targets 0.52.6", ] [[package]] name = "paste" -version = "1.0.12" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pbkdf2" @@ -3873,29 +3905,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.3" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.3" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -3916,9 +3948,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.26" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "plain" @@ -3940,9 +3972,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.4.3" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31114a898e107c51bb1609ffaf55a0e011cf6a4d7f1170d0015a165082c0338b" +checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" [[package]] name = "powerfmt" @@ -3956,6 +3988,36 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "predicates" +version = "2.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd" +dependencies = [ + "difflib", + "float-cmp", + "itertools 0.10.5", + "normalize-line-endings", + "predicates-core", + "regex", +] + +[[package]] +name = "predicates-core" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" + +[[package]] +name = "predicates-tree" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +dependencies = [ + "predicates-core", + "termtree", +] + [[package]] name = "pretty-hex" version = "0.3.0" @@ -4001,7 +4063,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ "once_cell", - "toml_edit 0.19.8", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit 0.21.1", ] [[package]] @@ -4054,7 +4125,7 @@ checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -4100,7 +4171,7 @@ checksum = "055b4e778e8feb9f93c4e439f71dc2156ef13360b432b799e179a8c4cdf0b1d7" dependencies = [ "bytes", "libc", - "socket2 0.5.4", + "socket2", "tracing", "windows-sys 0.48.0", ] @@ -4207,7 +4278,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.12", + "getrandom 0.2.15", ] [[package]] @@ -4230,9 +4301,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.7.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", @@ -4240,14 +4311,12 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.11.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ - "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "num_cpus", ] [[package]] @@ -4273,43 +4342,43 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.16" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "redox_syscall" -version = "0.3.5" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", ] [[package]] name = "redox_users" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ - "getrandom 0.2.12", - "redox_syscall 0.2.16", + "getrandom 0.2.15", + "libredox", "thiserror", ] [[package]] name = "regex" -version = "1.10.3" +version = "1.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.5", - "regex-syntax 0.8.2", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", ] [[package]] @@ -4323,20 +4392,20 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.5" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.2", + "regex-syntax 0.8.4", ] [[package]] name = "regex-lite" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b661b2f27137bdbc16f00eda72866a92bb28af1753ffbd56744fb6e2e9cd8e" +checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" [[package]] name = "regex-syntax" @@ -4346,9 +4415,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "repr_offset" @@ -4361,9 +4430,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.20" +version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ "async-compression", "base64 0.21.7", @@ -4390,6 +4459,8 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", + "sync_wrapper", + "system-configuration", "tokio", "tokio-native-tls", "tokio-rustls", @@ -4399,7 +4470,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 0.25.2", + "webpki-roots 0.25.4", "winreg", ] @@ -4426,7 +4497,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.12", + "getrandom 0.2.15", "libc", "spin 0.9.8", "untrusted 0.9.0", @@ -4454,30 +4525,30 @@ dependencies = [ [[package]] name = "rpassword" -version = "7.2.0" +version = "7.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6678cf63ab3491898c0d021b493c94c9b221d91295294a2a5746eacbe5928322" +checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f" dependencies = [ "libc", "rtoolbox", - "winapi", + "windows-sys 0.48.0", ] [[package]] name = "rtoolbox" -version = "0.0.1" +version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "034e22c514f5c0cb8a10ff341b9b048b5ceb21591f31c8f44c43b960f9b3524a" +checksum = "c247d24e63230cdb56463ae328478bd5eac8b8faa8c69461a77e8e323afac90e" dependencies = [ "libc", - "winapi", + "windows-sys 0.48.0", ] [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" @@ -4511,11 +4582,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.31" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", @@ -4536,9 +4607,9 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" dependencies = [ "openssl-probe", "rustls-pemfile", @@ -4548,9 +4619,9 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ "base64 0.21.7", ] @@ -4567,15 +4638,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.14" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" @@ -4588,11 +4659,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.21" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" dependencies = [ - "windows-sys 0.42.0", + "windows-sys 0.52.0", ] [[package]] @@ -4602,39 +4673,53 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] -name = "scratch" -version = "1.0.5" +name = "scroll" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" +checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" +dependencies = [ + "scroll_derive 0.11.1", +] [[package]] name = "scroll" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" +checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6" dependencies = [ - "scroll_derive", + "scroll_derive 0.12.0", ] [[package]] name = "scroll_derive" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdbda6ac5cd1321e724fa9cee216f3a61885889b896f073b8f82322789c5250e" +checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.72", +] + +[[package]] +name = "scroll_derive" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", ] [[package]] name = "sct" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring 0.16.20", - "untrusted 0.7.1", + "ring 0.17.8", + "untrusted 0.9.0", ] [[package]] @@ -4669,11 +4754,11 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.8.2" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "core-foundation", "core-foundation-sys", "libc", @@ -4682,9 +4767,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.8.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" +checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" dependencies = [ "core-foundation-sys", "libc", @@ -4699,6 +4784,15 @@ dependencies = [ "serde", ] +[[package]] +name = "seqlock" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5c67b6f14ecc5b86c66fa63d76b5092352678545a8a3cdae80aef5128371910" +dependencies = [ + "parking_lot", +] + [[package]] name = "serde" version = "1.0.204" @@ -4725,7 +4819,7 @@ checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -4745,7 +4839,7 @@ version = "1.0.120" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" dependencies = [ - "indexmap 2.2.3", + "indexmap 2.2.6", "itoa", "ryu", "serde", @@ -4753,9 +4847,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.3" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" dependencies = [ "serde", ] @@ -4792,7 +4886,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.2.3", + "indexmap 2.2.6", "serde", "serde_derive", "serde_json", @@ -4809,7 +4903,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -4821,16 +4915,16 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] name = "serde_yaml" -version = "0.9.25" +version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a49e178e4452f45cb61d0cd8cebc1b0fafd3e41929e996cef79aa3aca91f574" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.2.3", + "indexmap 2.2.6", "itoa", "ryu", "serde", @@ -4899,9 +4993,9 @@ dependencies = [ [[package]] name = "sha3" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54c2bb1a323307527314a36bfb73f24febb08ce2b8a554bf4ffd6f51ad15198c" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ "digest 0.10.7", "keccak", @@ -4909,9 +5003,9 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] @@ -4924,9 +5018,9 @@ checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" [[package]] name = "signal-hook-registry" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ "libc", ] @@ -4955,9 +5049,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] @@ -4970,22 +5064,12 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "socket2" -version = "0.5.4" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -5005,9 +5089,9 @@ dependencies = [ [[package]] name = "solana-account-decoder" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a9721ff8b83683cb7dd856079cde8a8010bfd282d482699a867ad50ea9e727e" +checksum = "b4a1297281b114406a9165c6f55ff9f8706f6244545194c7aa837f9b25dee16e" dependencies = [ "Inflector", "base64 0.21.7", @@ -5030,9 +5114,9 @@ dependencies = [ [[package]] name = "solana-accounts-db" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cdae5f9d2562360bd07fde58976f6ff8f7d90c8311bc5a4959edd7ba61ccec4" +checksum = "ff031129c39c32d0176be1e3bb9352dc83c521187058d6c16febfee2aedddca0" dependencies = [ "arrayref", "bincode", @@ -5045,7 +5129,6 @@ dependencies = [ "dashmap", "flate2", "fnv", - "fs-err", "im", "index_list", "itertools 0.10.5", @@ -5054,10 +5137,10 @@ dependencies = [ "lz4", "memmap2", "modular-bitfield", - "num-derive 0.3.3", + "num-derive 0.4.2", "num-traits", "num_cpus", - "num_enum 0.6.1", + "num_enum 0.7.2", "ouroboros", "percentage", "qualifier_attr", @@ -5065,14 +5148,17 @@ dependencies = [ "rayon", "regex", "rustc_version", + "seqlock", "serde", "serde_derive", + "smallvec", "solana-bucket-map", "solana-config-program", "solana-frozen-abi", "solana-frozen-abi-macro", "solana-measure", "solana-metrics", + "solana-nohash-hasher", "solana-program-runtime", "solana-rayon-threadlimit", "solana-sdk", @@ -5089,14 +5175,14 @@ dependencies = [ [[package]] name = "solana-address-lookup-table-program" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c471a3f150762652b5d77f83432b8574738e621fae4885c47132cfe33676d27c" +checksum = "622d95db00595a3dd2abd2ee22c37cf3744ba3df8f531d5c79faa3c155e2814b" dependencies = [ "bincode", "bytemuck", "log", - "num-derive 0.3.3", + "num-derive 0.4.2", "num-traits", "rustc_version", "serde", @@ -5110,9 +5196,9 @@ dependencies = [ [[package]] name = "solana-bpf-loader-program" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a99a75cdd7d4e40b51d8de8125f3d44db3f7735d96f4e3f31ee79d3110a8f4d" +checksum = "9934493a6034c8cf05913ba6812c057f6cd4792ad75c335e8d971adf63ce01c7" dependencies = [ "bincode", "byteorder", @@ -5129,16 +5215,16 @@ dependencies = [ [[package]] name = "solana-bucket-map" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9830a7dbea75c0cbd62a4ca31bcd9b8832fbdb915c949740a44a496630fb5eb6" +checksum = "0da941e0bde672cd33696961450efa2efb8b46322c4f814c1894c9c264122d1b" dependencies = [ "bv", "bytemuck", "log", "memmap2", "modular-bitfield", - "num_enum 0.6.1", + "num_enum 0.7.2", "rand 0.8.5", "solana-measure", "solana-sdk", @@ -5147,9 +5233,9 @@ dependencies = [ [[package]] name = "solana-clap-utils" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4af0fe4584d7692f24e573b17a5245cfc0d99a4e351b0185dfe02baf52f99864" +checksum = "811569ed647c15e97afd142297b0ad14a87149c51e11df740014daa81f297f8b" dependencies = [ "chrono", "clap 2.34.0", @@ -5164,9 +5250,9 @@ dependencies = [ [[package]] name = "solana-cli" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50775240fd486edb16add2664efeda82e4fdb78850ae70b1b2219dcbbf04ef30" +checksum = "d5a9e83ff7d553663d3d68405b425f2701412f60c72820a325ce4d907a834974" dependencies = [ "bincode", "bs58 0.4.0", @@ -5215,9 +5301,9 @@ dependencies = [ [[package]] name = "solana-cli-config" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "914499b160f7562cbec40d5a688a81028760870e35d22b3061596ebe677409a8" +checksum = "3cb4459594cbdbc6f3cd199bbca486f0ef7f1ecf107dce9cffa3f9d69df31dc7" dependencies = [ "dirs-next", "lazy_static", @@ -5231,9 +5317,9 @@ dependencies = [ [[package]] name = "solana-cli-output" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a32a72324bc9a47a0c72af93bba2fb7530cffab019a67eb24b2b22d81c8de1ce" +checksum = "eb454e8df10d664ef0e1137c69af0f2d9fa0de713c1b608656318a76a2f5d3cc" dependencies = [ "Inflector", "base64 0.21.7", @@ -5258,16 +5344,16 @@ dependencies = [ [[package]] name = "solana-client" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "250ffcda91bc30c2adcc290c9b7c796f59884f1043ae3bcf3245f05158c7986c" +checksum = "792ed1869858f35b4359f696771517b4848cd3ff6e2d58155c4bcb292f30166b" dependencies = [ "async-trait", "bincode", "dashmap", "futures", "futures-util", - "indexmap 2.2.3", + "indexmap 2.2.6", "indicatif", "log", "quinn", @@ -5291,9 +5377,9 @@ dependencies = [ [[package]] name = "solana-compute-budget-program" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8703a92306dfdc4760e18db14b2f8b36c9769e5c47f0656bc77355875674e079" +checksum = "3dde13cdf503b7269435ceee5a94f8c42313e9257df00e6c2aa06466345dd3fc" dependencies = [ "solana-program-runtime", "solana-sdk", @@ -5301,9 +5387,9 @@ dependencies = [ [[package]] name = "solana-config-program" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16fd2daba039bad58277ec88143b1fe624f2352d8ccb2a80bba3693de61df440" +checksum = "e6db8509d749ff1396a0b538ade995908361563b4f2c875b09cf096ba4ba0fae" dependencies = [ "bincode", "chrono", @@ -5315,15 +5401,15 @@ dependencies = [ [[package]] name = "solana-connection-cache" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "868e7fb550af97ad6fc283a5628f8ffb6dafd590dc30254163e7c9003f13ceb0" +checksum = "257511b6c2b54c28eae24c5a9b7bab74522439fcd721d09e63092768333ba7b7" dependencies = [ "async-trait", "bincode", "crossbeam-channel", "futures-util", - "indexmap 2.2.3", + "indexmap 2.2.6", "log", "rand 0.8.5", "rayon", @@ -5337,9 +5423,9 @@ dependencies = [ [[package]] name = "solana-cost-model" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3b79a349b86d02948720e4416463d50fd4f828b6a63512e47b497613df0d720" +checksum = "c391b492eb79c24756ee149b19f5504f7a2554612a8d2860fb9701df4e202a8b" dependencies = [ "lazy_static", "log", @@ -5361,9 +5447,9 @@ dependencies = [ [[package]] name = "solana-faucet" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64540db924b65d0ffeeaac031eb1a6a99892333714f740f01a5ef718cff01ef1" +checksum = "fdd43150e893ba19b5cb222cb0539feb232da55b89a1591cda63daf85cf7bd5d" dependencies = [ "bincode", "byteorder", @@ -5385,17 +5471,13 @@ dependencies = [ [[package]] name = "solana-frozen-abi" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219c484f952f006e37a1a2598aebcc4dcfd48478c03fc2ce2d99787a5c78f248" +checksum = "3f498a2b290abca1cf77feacef01b904be725fd46a7aea5ba121cce8c1269dcf" dependencies = [ - "ahash 0.8.5", - "blake3", "block-buffer 0.10.4", "bs58 0.4.0", "bv", - "byteorder", - "cc", "either", "generic-array", "im", @@ -5406,7 +5488,6 @@ dependencies = [ "serde", "serde_bytes", "serde_derive", - "serde_json", "sha2 0.10.8", "solana-frozen-abi-macro", "subtle", @@ -5415,21 +5496,21 @@ dependencies = [ [[package]] name = "solana-frozen-abi-macro" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe4e1dc5fd61ac10c304b3eb8ddb49737b13e975281d623a6083cf5cf0a8616" +checksum = "e4ab48d1be18021f5c13f94671e766699511044f81aab3376313f6a2392f8fab" dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] name = "solana-loader-v4-program" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad035401037e6e7d1dc19c0ae4b613b36632b60443d28716355a4e0041892fa2" +checksum = "6d5e1fcf36f771e210db47d9e4db1e88821d334b313e6fb3c19cf6a987617ffb" dependencies = [ "log", "solana-measure", @@ -5440,9 +5521,9 @@ dependencies = [ [[package]] name = "solana-logger" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64b4f281f2263de6d9cc65680b90b6bd2c93ba7de573db83fc86e2d05ca7ea8c" +checksum = "ed08bcdd54232d2017071a6f5d664b34649ef0110801ac310a01418215f22ff7" dependencies = [ "env_logger", "lazy_static", @@ -5451,9 +5532,9 @@ dependencies = [ [[package]] name = "solana-measure" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a3ed981230b6a3a8aebf9f03424f5c1ff98be75cc7f0ecb153879e8e439aea" +checksum = "5db05e4bba8562a2419cb980301152fc7f60f643065c3aba4b3b5d6e3bd66e45" dependencies = [ "log", "solana-sdk", @@ -5461,9 +5542,9 @@ dependencies = [ [[package]] name = "solana-metrics" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efb65329e6716dc0ce5b1d719d6e0052e7ff1179ab361916f256054d6b846ee1" +checksum = "f7a77735beed78eb221e123e0d46a991dc91db9e199d5c5fdbea22a55149d162" dependencies = [ "crossbeam-channel", "gethostname", @@ -5476,19 +5557,19 @@ dependencies = [ [[package]] name = "solana-net-utils" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8345ffe2bd2a25a02e5dea046bbbf58f81f6b44ee97224474eae1c0ea03b520a" +checksum = "4f76d98286bdb149ce5375c3c7d7301e5d1bf7bf2576789d3fd488cf93d32471" dependencies = [ "bincode", - "clap 3.2.23", + "clap 3.2.25", "crossbeam-channel", "log", "nix 0.26.4", "rand 0.8.5", "serde", "serde_derive", - "socket2 0.5.4", + "socket2", "solana-logger", "solana-sdk", "solana-version", @@ -5496,13 +5577,19 @@ dependencies = [ "url", ] +[[package]] +name = "solana-nohash-hasher" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b8a731ed60e89177c8a7ab05fe0f1511cedd3e70e773f288f9de33a9cfdc21e" + [[package]] name = "solana-perf" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0326bd89c2453bf2a408ff676cff4ed0080bff2a5c6543db5f62423bc23ad6e8" +checksum = "3b0a1b27503716c3f5362c61215d2ccf88a3ecf95fce51b2b59951c38a9ad94c" dependencies = [ - "ahash 0.8.5", + "ahash 0.8.11", "bincode", "bv", "caps", @@ -5527,9 +5614,9 @@ dependencies = [ [[package]] name = "solana-program" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93dc0f422549c23c4464eaa9383f4b09cd92b50dea750731dd3c31d3ee2d310f" +checksum = "d97cec6d3d60ef58168c8b3e97fd88e8903fa059eff6635361427c61c946ec1e" dependencies = [ "ark-bn254", "ark-ec", @@ -5537,10 +5624,11 @@ dependencies = [ "ark-serialize", "base64 0.21.7", "bincode", - "bitflags 2.4.0", + "bitflags 2.6.0", "blake3", "borsh 0.10.3", "borsh 0.9.3", + "borsh 1.5.1", "bs58 0.4.0", "bv", "bytemuck", @@ -5548,7 +5636,7 @@ dependencies = [ "console_error_panic_hook", "console_log", "curve25519-dalek", - "getrandom 0.2.12", + "getrandom 0.2.15", "itertools 0.10.5", "js-sys", "lazy_static", @@ -5556,9 +5644,9 @@ dependencies = [ "libsecp256k1", "light-poseidon", "log", - "memoffset 0.9.0", - "num-bigint 0.4.4", - "num-derive 0.3.3", + "memoffset 0.9.1", + "num-bigint 0.4.6", + "num-derive 0.4.2", "num-traits", "parking_lot", "rand 0.8.5", @@ -5569,7 +5657,7 @@ dependencies = [ "serde_derive", "serde_json", "sha2 0.10.8", - "sha3 0.10.7", + "sha3 0.10.8", "solana-frozen-abi", "solana-frozen-abi-macro", "solana-sdk-macro", @@ -5581,9 +5669,9 @@ dependencies = [ [[package]] name = "solana-program-runtime" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b407440b708ffda97e25b8cb977f72d1bb7466c28ea5f58751613df0af8d576" +checksum = "d4b76599d73401663bc1fde39f9fa5e538bd74451ea4a8d4e3ac14541be0a5de" dependencies = [ "base64 0.21.7", "bincode", @@ -5592,7 +5680,7 @@ dependencies = [ "itertools 0.10.5", "libc", "log", - "num-derive 0.3.3", + "num-derive 0.4.2", "num-traits", "percentage", "rand 0.8.5", @@ -5609,9 +5697,9 @@ dependencies = [ [[package]] name = "solana-pubsub-client" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f82da20e0c0bb39f9123cf61a6e3c76a8e30b0f09e5215decfb7f6b54734f04" +checksum = "09aacbdbeaa5722b2ab1f843673f66c317609741f494a6ef11e2e8928cc7449e" dependencies = [ "crossbeam-channel", "futures-util", @@ -5634,9 +5722,9 @@ dependencies = [ [[package]] name = "solana-quic-client" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8478a6b4f2c2b8fa330d54ff22386a1792498cb6e84ce3893840337a992e47c6" +checksum = "b2eeabd12e1039aa62cad34179fc1f139fca5c7bfeb7683057643bebff3506b0" dependencies = [ "async-mutex", "async-trait", @@ -5661,9 +5749,9 @@ dependencies = [ [[package]] name = "solana-rayon-threadlimit" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df0aac27af8e94f907f6a65305e0a7909800336e7108bd3ce1dc1f3ef011a20" +checksum = "8ad791cc224c84d69498eeeaeadfc5af2cf710ec2719e48b51f2e2b6e67d8163" dependencies = [ "lazy_static", "num_cpus", @@ -5671,15 +5759,15 @@ dependencies = [ [[package]] name = "solana-remote-wallet" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a97d60701d3fe0fde4871c5856da9e52ba733fbcfb030482278c3af4ffa0bf3" +checksum = "fca3c68439865c87d5a01c26dc0dcbcce2d45331adf8f0bf92a7c7d44853fefb" dependencies = [ "console", "dialoguer", "hidapi", "log", - "num-derive 0.3.3", + "num-derive 0.4.2", "num-traits", "parking_lot", "qstring", @@ -5691,9 +5779,9 @@ dependencies = [ [[package]] name = "solana-rpc-client" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b750c49be9dd90981f3c12c8357d0b0c847bf5b8c638c3eff3c09f6ea199393" +checksum = "c1c9bdb88ebcea8b13103019ed0d39b7d4391dc84a0d614dc8ba2e1ca43468e9" dependencies = [ "async-trait", "base64 0.21.7", @@ -5717,9 +5805,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-api" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "314d0f87fc7bab16b1b4674c03d4e92c7008fa181b67210780542c0e6cbfce38" +checksum = "e5bb93738a111d44dfeec6ccdd6a49f0478550a25a60e38badb2bd713599de44" dependencies = [ "base64 0.21.7", "bs58 0.4.0", @@ -5739,9 +5827,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-nonce-utils" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acf79164ae52ee1ee85cd7aeb1bb715a9f3b90678ee00501896d173dbc31731" +checksum = "e066df081489cd10c91648f1e87d2b945fac2fcdfb34a715234a0b079a4c4375" dependencies = [ "clap 2.34.0", "solana-clap-utils", @@ -5752,10 +5840,11 @@ dependencies = [ [[package]] name = "solana-runtime" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3dfd09f3cd529ab56b33a1b389b449ddc31b338f062822c7cc30375a2f234b" +checksum = "4c8e16747198f45ab41f146d1ab1782d83016fb9ed1ce7612b9174018f907bd5" dependencies = [ + "aquamarine", "arrayref", "base64 0.21.7", "bincode", @@ -5769,7 +5858,6 @@ dependencies = [ "dir-diff", "flate2", "fnv", - "fs-err", "im", "index_list", "itertools 0.10.5", @@ -5778,11 +5866,12 @@ dependencies = [ "lru", "lz4", "memmap2", + "mockall", "modular-bitfield", - "num-derive 0.3.3", + "num-derive 0.4.2", "num-traits", "num_cpus", - "num_enum 0.6.1", + "num_enum 0.7.2", "ouroboros", "percentage", "qualifier_attr", @@ -5793,7 +5882,6 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "siphasher", "solana-accounts-db", "solana-address-lookup-table-program", "solana-bpf-loader-program", @@ -5829,15 +5917,15 @@ dependencies = [ [[package]] name = "solana-sdk" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3892ee0e2acdfbeae7315db6c7c56356384631deb943377de5957074bd2dc4d1" +checksum = "1c335bdf35728ea876506babffcfd85fa4dd66af6438f9472afc91b278946909" dependencies = [ "assert_matches", "base64 0.21.7", "bincode", - "bitflags 2.4.0", - "borsh 0.10.3", + "bitflags 2.6.0", + "borsh 1.5.1", "bs58 0.4.0", "bytemuck", "byteorder", @@ -5854,9 +5942,9 @@ dependencies = [ "libsecp256k1", "log", "memmap2", - "num-derive 0.3.3", + "num-derive 0.4.2", "num-traits", - "num_enum 0.6.1", + "num_enum 0.7.2", "pbkdf2 0.11.0", "qstring", "qualifier_attr", @@ -5870,7 +5958,8 @@ dependencies = [ "serde_json", "serde_with 2.3.3", "sha2 0.10.8", - "sha3 0.10.7", + "sha3 0.10.8", + "siphasher", "solana-frozen-abi", "solana-frozen-abi-macro", "solana-logger", @@ -5883,15 +5972,15 @@ dependencies = [ [[package]] name = "solana-sdk-macro" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8019cc997f6c07f09b23dfeb2c45530fa94df2e2fb9d654f3c772c9766a1511f" +checksum = "4ba67050b90454a8638913a7d5775703c0557157def04ddcc8b59c964cda8535" dependencies = [ "bs58 0.4.0", "proc-macro2", "quote", "rustversion", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -5902,9 +5991,9 @@ checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" [[package]] name = "solana-stake-program" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11c21a028ed8abed4a7a52b8410875d799b31b58489653e05ae885e2ba799463" +checksum = "c2ef08f7b2485af8578bfd4e23689286e5360b50d3cc9f350dfe3ad9fdabc679" dependencies = [ "bincode", "log", @@ -5917,16 +6006,16 @@ dependencies = [ [[package]] name = "solana-streamer" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "067d167db6be6f25c21e4c615607757ae7161b20e08197ec2d1a63360e522069" +checksum = "27e8269eaa4aef1a9697fe8b9f659402272746c3fdd374fbffa96f68fe6745a6" dependencies = [ "async-channel", "bytes", "crossbeam-channel", "futures-util", "histogram", - "indexmap 2.2.3", + "indexmap 2.2.6", "itertools 0.10.5", "libc", "log", @@ -5950,9 +6039,9 @@ dependencies = [ [[package]] name = "solana-system-program" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4fa662731817f995cd114ce44d780be2814982a7674540be8d1c596a2d1ca43" +checksum = "22c8b55398485962ea6127fe84c5768a5ae4a4ecdbd80a0917eb6945593481f9" dependencies = [ "bincode", "log", @@ -5964,9 +6053,9 @@ dependencies = [ [[package]] name = "solana-thin-client" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0815c6d64a4bd71fd92ce33e82c24f5e8a5b105b26619521c4a8a43ab7573a9a" +checksum = "e5c174c724bbe19a53862156e1a5d2cf6cdf1bd5d5d9853b4696b2d9d836123b" dependencies = [ "bincode", "log", @@ -5979,14 +6068,14 @@ dependencies = [ [[package]] name = "solana-tpu-client" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "576431a39a612dac9387fecb5e80fe58989b740337a07bca41f0d02695e415f9" +checksum = "4dcdf9d7109d25900d0532539b00f53e820fb7200f6dc18f90e9d2be20c3d466" dependencies = [ "async-trait", "bincode", "futures-util", - "indexmap 2.2.3", + "indexmap 2.2.6", "indicatif", "log", "rayon", @@ -6003,9 +6092,9 @@ dependencies = [ [[package]] name = "solana-transaction-status" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0d8e2d97a8569afba70a105b402057b253fd9caee92c7ed2c3e1c3e0173fe91" +checksum = "7595aef5a9ddfdecd0966cc12ad0006713e4f8d87eafb4cb7b60fb18d98eff3a" dependencies = [ "Inflector", "base64 0.21.7", @@ -6028,9 +6117,9 @@ dependencies = [ [[package]] name = "solana-udp-client" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8297b04cb335ffac5b4a2c727dd82a2f72c8a96e3d5e1c159e01866b74a17e50" +checksum = "9a59c49a3766232005385bd70f15b0fce756fa6e73fb6397ce9ed34113f090e2" dependencies = [ "async-trait", "solana-connection-cache", @@ -6043,9 +6132,9 @@ dependencies = [ [[package]] name = "solana-version" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84a9f9ff3feebfaa960ac5387b133c6ef2c266779cb4932aed6acac5b83cb7b" +checksum = "73ece37d745e1fb3455acd69b8ba6ecea3ebcefde29e0f40ee8e6467acc4dc04" dependencies = [ "log", "rustc_version", @@ -6059,9 +6148,9 @@ dependencies = [ [[package]] name = "solana-vote" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8a2355a2b40d7b0b3a9ec5a5bd2196494c620a287ce6e4234cc4722fcb0cbb5" +checksum = "67ca2744cf5509c7680a90d6704d00fbab899aa586542c4257fb23d4712b380c" dependencies = [ "crossbeam-channel", "itertools 0.10.5", @@ -6078,13 +6167,13 @@ dependencies = [ [[package]] name = "solana-vote-program" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab0fe8455b2f06016cddefe7e3a7b9c0a57661d44816a4105c81f1088cfc1ac" +checksum = "6944bb3f8f34cc815017f6a50027331f5e7f48321e7998f1572cc898438b6a8a" dependencies = [ "bincode", "log", - "num-derive 0.3.3", + "num-derive 0.4.2", "num-traits", "rustc_version", "serde", @@ -6100,12 +6189,12 @@ dependencies = [ [[package]] name = "solana-zk-token-proof-program" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad624adcac620e41d052b29705f30c003b2e396ebca0145c1d296a1ef13f5aa7" +checksum = "51bd480f4b1b87dea1cdca14f3c6ba8e778e88756dc44ac090e797aab9c8759d" dependencies = [ "bytemuck", - "num-derive 0.3.3", + "num-derive 0.4.2", "num-traits", "solana-program-runtime", "solana-sdk", @@ -6114,9 +6203,9 @@ dependencies = [ [[package]] name = "solana-zk-token-sdk" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a06e103ed5adf1664f9cca3d1c64edad8b5b603255d8a5dd21a4ac5d86b89c" +checksum = "616130045004bccc9dd016fe03ac458db38bd61456f1d16f126acb60f968dcae" dependencies = [ "aes-gcm-siv", "base64 0.21.7", @@ -6128,7 +6217,7 @@ dependencies = [ "itertools 0.10.5", "lazy_static", "merlin", - "num-derive 0.3.3", + "num-derive 0.4.2", "num-traits", "rand 0.7.3", "serde", @@ -6155,7 +6244,7 @@ dependencies = [ "log", "rand 0.8.5", "rustc-demangle", - "scroll", + "scroll 0.11.0", "thiserror", "winapi", ] @@ -6190,7 +6279,7 @@ checksum = "992d9c64c2564cc8f63a4b508bf3ebcdf2254b0429b13cd1d31adb6162432a5f" dependencies = [ "assert_matches", "borsh 0.10.3", - "num-derive 0.4.1", + "num-derive 0.4.2", "num-traits", "solana-program", "spl-token", @@ -6211,25 +6300,25 @@ dependencies = [ [[package]] name = "spl-discriminator-derive" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fadbefec4f3c678215ca72bd71862697bb06b41fd77c0088902dd3203354387b" +checksum = "07fd7858fc4ff8fb0e34090e41d7eb06a823e1057945c26d480bfc21d2338a93" dependencies = [ "quote", "spl-discriminator-syn", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] name = "spl-discriminator-syn" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e5f2044ca42c8938d54d1255ce599c79a1ffd86b677dfab695caa20f9ffc3f2" +checksum = "18fea7be851bd98d10721782ea958097c03a0c2a07d8d4997041d0ece6319a63" dependencies = [ "proc-macro2", "quote", "sha2 0.10.8", - "syn 2.0.71", + "syn 2.0.72", "thiserror", ] @@ -6261,7 +6350,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "249e0318493b6bcf27ae9902600566c689b7dfba9f1bdff5893e92253374e78c" dependencies = [ - "num-derive 0.4.1", + "num-derive 0.4.2", "num-traits", "solana-program", "spl-program-error-derive", @@ -6270,21 +6359,21 @@ dependencies = [ [[package]] name = "spl-program-error-derive" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5269c8e868da17b6552ef35a51355a017bd8e0eae269c201fef830d35fa52c" +checksum = "1845dfe71fd68f70382232742e758557afe973ae19e6c06807b2c30f5d5cb474" dependencies = [ "proc-macro2", "quote", "sha2 0.10.8", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] name = "spl-tlv-account-resolution" -version = "0.5.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f335787add7fa711819f9e7c573f8145a5358a709446fe2d24bf2a88117c90" +checksum = "615d381f48ddd2bb3c57c7f7fb207591a2a05054639b18a62e785117dd7a8683" dependencies = [ "bytemuck", "solana-program", @@ -6317,9 +6406,9 @@ checksum = "d697fac19fd74ff472dfcc13f0b442dd71403178ce1de7b5d16f83a33561c059" dependencies = [ "arrayref", "bytemuck", - "num-derive 0.4.1", + "num-derive 0.4.2", "num-traits", - "num_enum 0.7.1", + "num_enum 0.7.2", "solana-program", "solana-security-txt", "solana-zk-token-sdk", @@ -6413,6 +6502,12 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "strum" version = "0.24.1" @@ -6451,7 +6546,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -6479,15 +6574,33 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.71" +version = "2.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "syn_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "synstructure" version = "0.12.6" @@ -6500,6 +6613,27 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tap" version = "1.0.1" @@ -6508,9 +6642,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tar" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" +checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" dependencies = [ "filetime", "libc", @@ -6519,9 +6653,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.10.0" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", "fastrand", @@ -6531,13 +6665,19 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.2.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] +[[package]] +name = "termtree" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" + [[package]] name = "textwrap" version = "0.11.0" @@ -6549,9 +6689,9 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" [[package]] name = "thiserror" @@ -6570,7 +6710,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -6581,9 +6721,9 @@ checksum = "bcbb6aa301e5d3b0b5ef639c9a9c7e2f1c944f177b460c04dc24c69b1fa2bd99" [[package]] name = "thread_local" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ "cfg-if", "once_cell", @@ -6650,9 +6790,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -6665,11 +6805,10 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.29.1" +version = "1.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" +checksum = "eb2caba9f80616f438e09748d5acda951967e1ea58508ef53d9c6402485a46df" dependencies = [ - "autocfg", "backtrace", "bytes", "libc", @@ -6678,20 +6817,20 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.4.9", + "socket2", "tokio-macros", "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -6716,9 +6855,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" dependencies = [ "futures-core", "pin-project-lite", @@ -6737,14 +6876,14 @@ dependencies = [ "tokio", "tokio-rustls", "tungstenite", - "webpki-roots 0.25.2", + "webpki-roots 0.25.4", ] [[package]] name = "tokio-util" -version = "0.7.7" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" dependencies = [ "bytes", "futures-core", @@ -6752,7 +6891,6 @@ dependencies = [ "futures-sink", "pin-project-lite", "tokio", - "tracing", ] [[package]] @@ -6766,47 +6904,58 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.2" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" +checksum = "ac2caab0bf757388c6c0ae23b3293fdb463fee59434529014f85e3263b995c28" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.20.2", + "toml_edit 0.22.16", ] [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.19.8" +version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 1.9.3", + "indexmap 2.2.6", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap 2.2.6", "toml_datetime", - "winnow 0.4.1", + "winnow 0.5.40", ] [[package]] name = "toml_edit" -version = "0.20.2" +version = "0.22.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +checksum = "278f3d518e152219c994ce877758516bca5e118eaed6996192a774fb9fbf0788" dependencies = [ - "indexmap 2.2.3", + "indexmap 2.2.6", "serde", "serde_spanned", "toml_datetime", - "winnow 0.5.15", + "winnow 0.6.15", ] [[package]] @@ -6868,7 +7017,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -6912,15 +7061,15 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tstr" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cca3264971090dec0feef3b455a3c178f02762f7550cf4592991ac64b3be2d7e" +checksum = "7f8e0294f14baae476d0dd0a2d780b2e24d66e349a9de876f5126777a37bdba7" dependencies = [ "tstr_proc_macros", ] @@ -6960,9 +7109,9 @@ checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "uint" @@ -6978,36 +7127,36 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "unicode-xid" @@ -7036,9 +7185,9 @@ dependencies = [ [[package]] name = "unsafe-libyaml" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" [[package]] name = "untrusted" @@ -7064,9 +7213,9 @@ dependencies = [ [[package]] name = "url" -version = "2.5.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna 0.5.0", @@ -7081,11 +7230,11 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] name = "uuid" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" dependencies = [ - "getrandom 0.2.12", + "getrandom 0.2.15", ] [[package]] @@ -7120,9 +7269,9 @@ checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" [[package]] name = "walkdir" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", @@ -7130,11 +7279,10 @@ dependencies = [ [[package]] name = "want" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "log", "try-lock", ] @@ -7152,9 +7300,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -7162,24 +7310,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.34" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ "cfg-if", "js-sys", @@ -7189,9 +7337,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -7199,28 +7347,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "web-sys" -version = "0.3.61" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", @@ -7285,9 +7433,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.25.2" +version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "winapi" @@ -7307,11 +7455,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -7321,36 +7469,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets 0.48.0", -] - -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" +name = "windows-core" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.42.2", + "windows-targets 0.52.6", ] [[package]] @@ -7359,7 +7483,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.0", + "windows-targets 0.48.5", ] [[package]] @@ -7368,194 +7492,144 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.3", + "windows-targets 0.52.6", ] [[package]] name = "windows-targets" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] name = "windows-targets" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" -dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", -] - -[[package]] -name = "windows-targets" -version = "0.52.3" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.3", - "windows_aarch64_msvc 0.52.3", - "windows_i686_gnu 0.52.3", - "windows_i686_msvc 0.52.3", - "windows_x86_64_gnu 0.52.3", - "windows_x86_64_gnullvm 0.52.3", - "windows_x86_64_msvc 0.52.3", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.3" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] -name = "windows_i686_msvc" -version = "0.42.2" +name = "windows_i686_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.3" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.3" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.4.1" +version = "0.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" dependencies = [ "memchr", ] [[package]] name = "winnow" -version = "0.5.15" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" +checksum = "557404e450152cd6795bb558bca69e43c585055f4606e3bcae5894fc6dac9ba0" dependencies = [ "memchr", ] @@ -7599,11 +7673,13 @@ dependencies = [ [[package]] name = "xattr" -version = "1.0.1" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4686009f71ff3e5c4dbcf1a282d0a44db3f021ba69350cd42086b3e5f1c6985" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" dependencies = [ "libc", + "linux-raw-sys", + "rustix", ] [[package]] @@ -7623,22 +7699,22 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -7658,7 +7734,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -7672,11 +7748,11 @@ dependencies = [ [[package]] name = "zstd" -version = "0.13.0" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bffb3309596d527cfcba7dfc6ed6052f1d39dfbd7c867aa2e865e4a449c10110" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" dependencies = [ - "zstd-safe 7.0.0", + "zstd-safe 7.2.0", ] [[package]] @@ -7691,20 +7767,19 @@ dependencies = [ [[package]] name = "zstd-safe" -version = "7.0.0" +version = "7.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43747c7422e2924c11144d5229878b98180ef8b06cca4ab5af37afc8a8d8ea3e" +checksum = "fa556e971e7b568dc775c136fc9de8c779b1c2fc3a63defaafadffdbd3181afa" dependencies = [ "zstd-sys", ] [[package]] name = "zstd-sys" -version = "2.0.8+zstd.1.5.5" +version = "2.0.12+zstd.1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c" +checksum = "0a4e40c320c3cb459d9a9ff6de98cff88f4751ee9275d140e2be94a2b74e4c13" dependencies = [ "cc", - "libc", "pkg-config", ] diff --git a/evm_loader/Cargo.toml b/evm_loader/Cargo.toml index 92c51938f..d91765a5d 100644 --- a/evm_loader/Cargo.toml +++ b/evm_loader/Cargo.toml @@ -12,16 +12,19 @@ members = [ ] [workspace.dependencies] -solana-clap-utils = "=1.17.34" -solana-cli = "=1.17.34" -solana-cli-config = "=1.17.34" -solana-client = "=1.17.34" -solana-account-decoder = "=1.17.34" -solana-program = { version = "=1.17.34", default-features = false } -solana-sdk = "=1.17.34" -solana-program-runtime = "=1.17.34" -solana-runtime = "=1.17.34" -solana-accounts-db = "=1.17.34" +solana-clap-utils = "=1.18.18" +solana-cli = "=1.18.18" +solana-cli-config = "=1.18.18" +solana-client = "=1.18.18" +solana-account-decoder = "=1.18.18" +solana-program = { version = "=1.18.18", default-features = false } +solana-sdk = "=1.18.18" +solana-program-runtime = "=1.18.18" +solana-runtime = { version = "=1.18.18", features = ["dev-context-only-utils"] } +solana-accounts-db = "=1.18.18" +solana-bpf-loader-program = "=1.18.18" +solana-loader-v4-program = "=1.18.18" +solana-transaction-status = "=1.18.18" [profile.test] debug = true diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 0bbcc12c1..256822c3c 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -clap = "2.33.3" +clap = "2.34.0" evm-loader = { path = "../program", default-features = false, features = ["log"] } solana-sdk.workspace = true solana-client.workspace = true @@ -20,7 +20,7 @@ tracing-appender = "0.2.3" neon-lib = { path = "../lib" } actix-web = "4.8.0" actix-request-identifier = "4.2.0" -hex = "0.4.2" +hex = "0.4.3" build-info = "0.0.37" [build-dependencies] diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index bd62f0f8e..8cf6ca5a2 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -6,13 +6,13 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -clap = "2.33.3" +clap = "2.34.0" evm-loader = { path = "../program", default-features = false, features = ["log"] } solana-sdk.workspace = true solana-client.workspace = true solana-clap-utils.workspace = true solana-cli-config.workspace = true -hex = "0.4.2" +hex = "0.4.3" serde = "1.0.204" serde_json = { version = "1.0.120", features = ["preserve_order"] } log = "0.4.22" diff --git a/evm_loader/lib-interface/Cargo.toml b/evm_loader/lib-interface/Cargo.toml index 370ff1120..d3a5607d8 100644 --- a/evm_loader/lib-interface/Cargo.toml +++ b/evm_loader/lib-interface/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -abi_stable = "0.11.1" +abi_stable = "0.11.3" thiserror = "1" async-ffi = { version = "0.5.0", features = ["abi_stable"] } serde = "1.0.204" diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index d44963722..6577ed2ef 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" [dependencies] thiserror = "1.0" anyhow = "1.0" -bincode = "1.3.1" +bincode = "1.3.3" hyper = "0.14" evm-loader = { path = "../program", default-features = false, features = ["log", "async-trait"] } solana-sdk.workspace = true @@ -19,6 +19,9 @@ solana-cli.workspace = true solana-program-runtime.workspace = true solana-runtime.workspace = true solana-accounts-db.workspace = true +solana-bpf-loader-program.workspace = true +solana-loader-v4-program.workspace = true +solana-transaction-status.workspace = true spl-token = { version = "~4.0", default-features = false, features = ["no-entrypoint"] } spl-associated-token-account = { version = "~2.3", default-features = false, features = ["no-entrypoint"] } bs58 = "0.5.1" @@ -30,8 +33,8 @@ serde_with = { version = "3.9", features = ["hex"] } log = "0.4.22" rand = "0.8" ethnum = { version = "1.5", default-features = false, features = ["serde"] } -goblin = { version = "0.6.0" } -scroll = "0.11.0" +goblin = { version = "0.8.2" } +scroll = "0.12.0" tokio = { version = "1", features = ["full"] } clickhouse = "0.11.6" tracing = "0.1" @@ -40,14 +43,14 @@ build-info = "0.0.37" enum_dispatch = "0.3.13" web3 = "0.19.0" neon-lib-interface = { path = "../lib-interface" } -abi_stable = "0.11.2" +abi_stable = "0.11.3" async-ffi = { version = "0.5.0", features = ["abi_stable"] } strum = "0.26.3" strum_macros = "0.26.4" -clap = "2.33.3" +clap = "2.34.0" lazy_static = "1.5.0" elsa = "1.10.0" -arrayref = "0.3.6" +arrayref = "0.3.8" [dev-dependencies] hex-literal = "0.4.1" diff --git a/evm_loader/lib/src/account_data.rs b/evm_loader/lib/src/account_data.rs index 376218121..9c1535d62 100644 --- a/evm_loader/lib/src/account_data.rs +++ b/evm_loader/lib/src/account_data.rs @@ -1,14 +1,18 @@ -pub use evm_loader::account_storage::{AccountStorage, SyncedAccountStorage}; -// use solana_sdk::account::{ReadableAccount, WritableAccount}; +use std::fmt; + +use solana_sdk::account_info::IntoAccountInfo; +use solana_sdk::entrypoint::MAX_PERMITTED_DATA_INCREASE; use solana_sdk::system_program; -// use solana_sdk::clock::Epoch; use solana_sdk::{ account::{Account, ReadableAccount}, account_info::AccountInfo, pubkey::Pubkey, }; -#[derive(Clone, Debug)] +pub use evm_loader::account_storage::{AccountStorage, SyncedAccountStorage}; +use evm_loader::solana_program::debug_account_data::debug_account_data; + +#[derive(Clone)] #[repr(C)] pub struct AccountData { original_length: u32, @@ -20,8 +24,24 @@ pub struct AccountData { pub rent_epoch: u64, } -use solana_sdk::account_info::IntoAccountInfo; -use solana_sdk::entrypoint::MAX_PERMITTED_DATA_INCREASE; +impl fmt::Debug for AccountData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut debug_struct = f.debug_struct("AccountData"); + + debug_struct + .field("original_length", &self.original_length) + .field("pubkey", &bs58::encode(&self.pubkey).into_string()) + .field("lamports", &self.lamports) + .field("owner", &bs58::encode(&self.owner).into_string()) + .field("executable", &self.executable) + .field("rent_epoch", &self.rent_epoch) + .field("data_len", &self.data.len()); + + debug_account_data(&self.data, &mut debug_struct); + + debug_struct.finish() + } +} impl AccountData { #[must_use] @@ -157,9 +177,10 @@ impl<'a> From<&'a AccountData> for Account { #[cfg(test)] mod tests { - use super::*; use std::str::FromStr; + use super::*; + #[tokio::test] async fn test_account_data() { let mut account_data = AccountData::new(Pubkey::default()); diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index 5776845a3..92d247dfa 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -332,6 +332,11 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { let mut response = self.rpc.get_multiple_accounts(&missing_keys).await?; + debug!( + "get_multiple_accounts: missing_keys={:?} response={response:?}", + missing_keys + ); + let mut j = 0_usize; for i in 0..pubkeys.len() { if exists[i] { @@ -560,6 +565,7 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { fn add_empty_account(&self, pubkey: Pubkey) -> &RefCell { let account_data = AccountData::new(pubkey); self.mark_account(pubkey, false); + info!("add_empty_account(pubkey={pubkey}, account_data={account_data:?})"); self.accounts .insert(pubkey, Box::new(RefCell::new(account_data))) } @@ -569,6 +575,8 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { pubkey: Pubkey, is_writable: bool, ) -> NeonResult<&RefCell> { + info!("use_account(pubkey={pubkey}, is_writable={is_writable})"); + if pubkey == self.operator() { return Err(EvmLoaderError::InvalidAccountForCall(pubkey).into()); } @@ -581,8 +589,10 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { let account = self._get_account_from_rpc(pubkey).await?; if let Some(account) = account { + info!("found account for pubkey={pubkey} in RPC account={account:?}"); self.add_account(pubkey, account).await } else { + info!("account not found in RPC, adding empty account for pubkey={pubkey}"); Ok(self.add_empty_account(pubkey)) } } @@ -1341,7 +1351,7 @@ impl SyncedAccountStorage for EmulatorAccountStorage<'_, T> { .await .map_err(|e| EvmLoaderError::Custom(e.to_string()))?; - solana_simulator.set_sysvar(&Clock { + solana_simulator.set_clock(Clock { slot: self.block_number, epoch_start_timestamp: self.block_timestamp, epoch: 0, @@ -1380,10 +1390,9 @@ impl SyncedAccountStorage for EmulatorAccountStorage<'_, T> { .await .map_err(|e| EvmLoaderError::Custom(e.to_string()))?; - let trx = Transaction::new_unsigned(Message::new_with_blockhash( + let trx = Transaction::new_unsigned(Message::new( &[instruction.clone()], Some(&solana_simulator.payer().pubkey()), - &solana_simulator.blockhash(), )); let result = solana_simulator diff --git a/evm_loader/lib/src/commands/emulate.rs b/evm_loader/lib/src/commands/emulate.rs index ef16d54dc..a7f2b48df 100644 --- a/evm_loader/lib/src/commands/emulate.rs +++ b/evm_loader/lib/src/commands/emulate.rs @@ -15,7 +15,7 @@ use evm_loader::{ executor::SyncedExecutorState, gasometer::LAMPORTS_PER_SIGNATURE, }; -use log::{debug, info}; +use log::{debug, error, info}; use serde::{Deserialize, Serialize}; use serde_json::Value; use serde_with::{hex::Hex, serde_as, DisplayFromStr}; @@ -176,11 +176,15 @@ async fn emulate_trx( let mut backend = SyncedExecutorState::new(storage); let mut evm = match Machine::new(&tx, origin, &mut backend, tracer).await { Ok(evm) => evm, - Err(e) => return Ok((EmulateResponse::revert(&e, &backend), None)), + Err(e) => { + error!("EVM creation failed {e:?}"); + return Ok((EmulateResponse::revert(&e, &backend), None)); + } }; let (exit_status, steps_executed, tracer) = evm.execute(step_limit, &mut backend).await?; if exit_status == ExitStatus::StepLimit { + error!("Step_limit={step_limit} exceeded"); return Ok(( EmulateResponse::revert(&NeonError::TooManySteps, &backend), None, diff --git a/evm_loader/lib/src/commands/get_config.rs b/evm_loader/lib/src/commands/get_config.rs index faca62327..de3c675b7 100644 --- a/evm_loader/lib/src/commands/get_config.rs +++ b/evm_loader/lib/src/commands/get_config.rs @@ -3,7 +3,6 @@ use async_trait::async_trait; use base64::Engine; use enum_dispatch::enum_dispatch; -use solana_sdk::signer::Signer; use std::collections::BTreeMap; use tokio::sync::OnceCell; @@ -16,6 +15,7 @@ use crate::NeonResult; use crate::rpc::{CallDbClient, CloneRpcClient}; use serde_with::{serde_as, DisplayFromStr}; use solana_client::rpc_config::RpcSimulateTransactionConfig; +use solana_sdk::signature::Signer; #[derive(Debug, Serialize, Deserialize)] pub enum Status { @@ -44,6 +44,7 @@ pub struct GetConfigResponse { pub config: BTreeMap, } +#[allow(clippy::large_enum_variant)] pub enum ConfigSimulator<'r> { CloneRpcClient { program_id: Pubkey, diff --git a/evm_loader/lib/src/commands/simulate_solana.rs b/evm_loader/lib/src/commands/simulate_solana.rs index 44bee35fc..64fc69763 100644 --- a/evm_loader/lib/src/commands/simulate_solana.rs +++ b/evm_loader/lib/src/commands/simulate_solana.rs @@ -1,6 +1,13 @@ use std::collections::HashSet; +use crate::{ + rpc::Rpc, + solana_simulator::{SolanaSimulator, SyncState}, + types::SimulateSolanaRequest, + NeonResult, +}; use bincode::Options; +use log::info; use serde::{Deserialize, Serialize}; use serde_with::serde_as; use solana_program_runtime::compute_budget::ComputeBudget; @@ -9,13 +16,7 @@ use solana_sdk::{ pubkey::Pubkey, transaction::{SanitizedTransaction, Transaction, VersionedTransaction}, }; - -use crate::{ - rpc::Rpc, - solana_simulator::{SolanaSimulator, SyncState}, - types::SimulateSolanaRequest, - NeonResult, -}; +use solana_transaction_status::EncodableWithMeta; #[serde_as] #[derive(Deserialize, Serialize, Debug, Default)] @@ -101,6 +102,10 @@ pub async fn execute( let mut transactions: Vec = vec![]; for data in request.transactions { let tx = decode_transaction(&data)?; + info!( + "Encoded transaction: {}", + serde_json::to_string(&tx.json_encode()).unwrap() + ); transactions.push(tx); } @@ -119,16 +124,14 @@ pub async fn execute( let accounts = account_keys(&sanitized_transactions); simulator.sync_accounts(rpc, &accounts).await?; - simulator.replace_blockhash(&request.blockhash.into()); - // Process transactions let mut results = Vec::new(); for tx in sanitized_transactions { - let r = simulator.process_transaction(tx)?; + let r = simulator.process_transaction(request.blockhash.into(), &tx)?; results.push(SimulateSolanaTransactionResult { - error: r.status.err(), - logs: r.log_messages.unwrap_or_default(), - executed_units: r.executed_units, + error: r.result.err(), + logs: r.logs, + executed_units: r.units_consumed, }); } diff --git a/evm_loader/lib/src/commands/trace.rs b/evm_loader/lib/src/commands/trace.rs index 77beb7d21..1a243421e 100644 --- a/evm_loader/lib/src/commands/trace.rs +++ b/evm_loader/lib/src/commands/trace.rs @@ -1,6 +1,7 @@ #![allow(clippy::missing_errors_doc)] use crate::commands::emulate::EmulateResponse; +use log::info; use serde_json::Value; use solana_sdk::pubkey::Pubkey; @@ -23,5 +24,9 @@ pub async fn trace_transaction( let tracer = new_tracer(&emulate_request.tx, trace_config)?; - super::emulate::execute(rpc, program_id, emulate_request, Some(tracer)).await + let response = super::emulate::execute(rpc, program_id, emulate_request, Some(tracer)).await?; + + info!("response: {:?}", response); + + Ok(response) } diff --git a/evm_loader/lib/src/commands/transaction_executor.rs b/evm_loader/lib/src/commands/transaction_executor.rs index 158b89874..75f190f95 100644 --- a/evm_loader/lib/src/commands/transaction_executor.rs +++ b/evm_loader/lib/src/commands/transaction_executor.rs @@ -21,6 +21,7 @@ use { }; #[derive(Default, Debug, Serialize, Deserialize)] +#[allow(clippy::struct_field_names)] pub struct Stats { pub total_objects: u32, pub corrected_objects: u32, diff --git a/evm_loader/lib/src/rpc/db_call_client.rs b/evm_loader/lib/src/rpc/db_call_client.rs index 599416c52..a3d849edf 100644 --- a/evm_loader/lib/src/rpc/db_call_client.rs +++ b/evm_loader/lib/src/rpc/db_call_client.rs @@ -2,6 +2,7 @@ use super::{e, Rpc}; use crate::types::TracerDb; use crate::NeonError; use async_trait::async_trait; +use log::debug; use solana_client::{ client_error::Result as ClientResult, client_error::{ClientError, ClientErrorKind}, @@ -61,6 +62,7 @@ impl Rpc for CallDbClient { for key in pubkeys { result.push(self.get_account_at(key).await?); } + debug!("get_multiple_accounts: pubkeys={pubkeys:?} result={result:?}"); Ok(result) } diff --git a/evm_loader/lib/src/rpc/emulator_client.rs b/evm_loader/lib/src/rpc/emulator_client.rs index 11f6822b9..5a63af7f6 100644 --- a/evm_loader/lib/src/rpc/emulator_client.rs +++ b/evm_loader/lib/src/rpc/emulator_client.rs @@ -1,5 +1,6 @@ use async_trait::async_trait; use evm_loader::account_storage::AccountStorage; +use log::debug; use solana_client::client_error::Result as ClientResult; use solana_sdk::{ account::Account, @@ -30,6 +31,7 @@ impl<'rpc, T: Rpc> Rpc for EmulatorAccountStorage<'rpc, T> { &self, pubkeys: &[Pubkey], ) -> ClientResult>> { + debug!("get_multiple_accounts: pubkeys={:?}", pubkeys); if pubkeys.is_empty() { return Ok(Vec::new()); } @@ -46,6 +48,7 @@ impl<'rpc, T: Rpc> Rpc for EmulatorAccountStorage<'rpc, T> { } if let Some(account_data) = self.accounts_get(pubkey) { + debug!("cached account pubkey={pubkey} account_data={account_data:?}"); accounts[i] = Some(Account::from(&*account_data)); continue; } @@ -56,6 +59,8 @@ impl<'rpc, T: Rpc> Rpc for EmulatorAccountStorage<'rpc, T> { let response = self._get_multiple_accounts_from_rpc(&missing_keys).await?; + debug!("get_multiple_accounts: missing_keys={missing_keys:?} response={response:?}",); + let mut j = 0_usize; for i in 0..pubkeys.len() { if exists[i] { diff --git a/evm_loader/lib/src/rpc/validator_client.rs b/evm_loader/lib/src/rpc/validator_client.rs index f3322d72b..1c64a8623 100644 --- a/evm_loader/lib/src/rpc/validator_client.rs +++ b/evm_loader/lib/src/rpc/validator_client.rs @@ -17,6 +17,7 @@ use solana_sdk::{ }; use std::{error::Error, ops::Deref, time::Duration}; use std::{future::Future, sync::Arc}; +use tracing::debug; fn should_retry(e: &ClientError) -> bool { let ClientErrorKind::Reqwest(reqwest_error) = e.kind() else { @@ -142,6 +143,10 @@ impl Rpc for CloneRpcClient { if pubkeys.len() == 1 { let account = Rpc::get_account(self, &pubkeys[0]).await?; + debug!( + "get_multiple_accounts: single account pubkey={} account={:?}", + pubkeys[0], account + ); return Ok(vec![account]); } @@ -150,6 +155,10 @@ impl Rpc for CloneRpcClient { let request = || self.rpc.get_multiple_accounts(chunk); let mut accounts = with_retries(self.max_retries, request).await?; + debug!( + "get_multiple_accounts: chunk pubkey={:?} account={:?}", + chunk, accounts + ); result.append(&mut accounts); } @@ -201,6 +210,10 @@ impl Rpc for CloneRpcClient { } } + for feature in &result { + debug!("Deactivated feature: {}", feature); + } + cache.replace(Cache { data: result.clone(), timestamp: Instant::now(), diff --git a/evm_loader/lib/src/solana_simulator/error.rs b/evm_loader/lib/src/solana_simulator/error.rs index f863ea2fa..6bd4ac33e 100644 --- a/evm_loader/lib/src/solana_simulator/error.rs +++ b/evm_loader/lib/src/solana_simulator/error.rs @@ -1,21 +1,21 @@ #[derive(Debug, thiserror::Error)] pub enum Error { - #[error("Unexpected response")] - UnexpectedResponse, + // #[error("Unexpected response")] + // UnexpectedResponse, #[error("Program Account error")] ProgramAccountError, #[error("Rpc Client error {0:?}")] RpcClientError(#[from] solana_client::client_error::ClientError), - #[error("IO error {0:?}")] - IoError(#[from] std::io::Error), + // #[error("IO error {0:?}")] + // IoError(#[from] std::io::Error), #[error("Bincode error {0:?}")] BincodeError(#[from] bincode::Error), - #[error("TryFromIntError error {0:?}")] - TryFromIntError(#[from] std::num::TryFromIntError), + // #[error("TryFromIntError error {0:?}")] + // TryFromIntError(#[from] std::num::TryFromIntError), #[error("Transaction error {0:?}")] TransactionError(#[from] solana_sdk::transaction::TransactionError), - #[error("Sanitize error {0:?}")] - SanitizeError(#[from] solana_sdk::sanitize::SanitizeError), + // #[error("Sanitize error {0:?}")] + // SanitizeError(#[from] solana_sdk::sanitize::SanitizeError), #[error("Instruction error {0:?}")] InstructionError(#[from] solana_sdk::instruction::InstructionError), #[error("Invalid ALT")] diff --git a/evm_loader/lib/src/solana_simulator/mod.rs b/evm_loader/lib/src/solana_simulator/mod.rs index ea431a323..96424943a 100644 --- a/evm_loader/lib/src/solana_simulator/mod.rs +++ b/evm_loader/lib/src/solana_simulator/mod.rs @@ -1,35 +1,65 @@ +use std::collections::HashMap; +use std::rc::Rc; use std::sync::Arc; -use solana_accounts_db::transaction_results::{ - TransactionExecutionDetails, TransactionExecutionResult, +pub use error::Error; +use evm_loader::solana_program::bpf_loader_upgradeable::UpgradeableLoaderState; +use evm_loader::solana_program::clock::Slot; +use evm_loader::solana_program::loader_v4; +use evm_loader::solana_program::loader_v4::{LoaderV4State, LoaderV4Status}; +use evm_loader::solana_program::message::SanitizedMessage; +use log::debug; +use solana_accounts_db::transaction_results::inner_instructions_list_from_instruction_trace; +use solana_bpf_loader_program::syscalls::create_program_runtime_environment_v1; +use solana_loader_v4_program::create_program_runtime_environment_v2; +use solana_program_runtime::compute_budget::ComputeBudget; +use solana_program_runtime::loaded_programs::{ + LoadProgramMetrics, LoadedProgram, LoadedProgramType, LoadedProgramsForTxBatch, + ProgramRuntimeEnvironments, }; -use solana_runtime::{ - bank::{Bank, TransactionSimulationResult}, - runtime_config::RuntimeConfig, +use solana_program_runtime::log_collector::LogCollector; +use solana_program_runtime::message_processor::MessageProcessor; +use solana_program_runtime::sysvar_cache::SysvarCache; +use solana_program_runtime::timings::ExecuteTimings; +use solana_runtime::accounts::construct_instructions_account; +use solana_runtime::builtins::BUILTINS; +use solana_runtime::{bank::TransactionSimulationResult, runtime_config::RuntimeConfig}; +use solana_sdk::account::{ + create_account_shared_data_with_fields, AccountSharedData, ReadableAccount, + DUMMY_INHERITABLE_ACCOUNT_FIELDS, PROGRAM_OWNERS, }; +use solana_sdk::account_utils::StateMut; +use solana_sdk::address_lookup_table::error::AddressLookupError; +use solana_sdk::address_lookup_table::state::AddressLookupTable; +use solana_sdk::clock::Clock; +use solana_sdk::feature_set::FeatureSet; +use solana_sdk::fee_calculator::DEFAULT_TARGET_LAMPORTS_PER_SIGNATURE; +use solana_sdk::message::v0::{LoadedAddresses, MessageAddressTableLookup}; +use solana_sdk::message::{AddressLoader, AddressLoaderError}; +use solana_sdk::rent::Rent; +use solana_sdk::transaction::TransactionError; +use solana_sdk::transaction_context::{ExecutionRecord, IndexOfAccount, TransactionContext}; use solana_sdk::{ account::Account, - address_lookup_table, bpf_loader, bpf_loader_upgradeable, + address_lookup_table, bpf_loader_upgradeable, hash::Hash, pubkey::Pubkey, signature::Keypair, sysvar::{Sysvar, SysvarId}, - transaction::{ - MessageHash, SanitizedTransaction, TransactionVerificationMode, VersionedTransaction, - }, + transaction::{SanitizedTransaction, VersionedTransaction}, }; +pub use utils::SyncState; use crate::rpc::Rpc; mod error; mod utils; -pub use error::Error; -pub use utils::SyncState; - pub struct SolanaSimulator { - bank: Bank, - runtime_config: Arc, + runtime_config: RuntimeConfig, + feature_set: Arc, + accounts_db: HashMap, + sysvar_cache: SysvarCache, payer: Keypair, } @@ -47,42 +77,29 @@ impl SolanaSimulator { runtime_config: RuntimeConfig, sync_state: SyncState, ) -> Result { - let runtime_config = Arc::new(runtime_config); - - let info = utils::genesis_config_info(rpc, sync_state, 1_000.0).await?; - let payer = info.mint_keypair; + let mut feature_set = FeatureSet::all_enabled(); - let genesis_bank = Arc::new(Bank::new_with_paths( - &info.genesis_config, - Arc::clone(&runtime_config), - Vec::default(), - None, - None, - solana_accounts_db::accounts_index::AccountSecondaryIndexes::default(), - solana_accounts_db::accounts_db::AccountShrinkThreshold::default(), - false, - None, - None, - Arc::default(), - )); + if sync_state == SyncState::Yes { + for feature in rpc.get_deactivated_solana_features().await? { + feature_set.deactivate(&feature); + } + } - genesis_bank.set_capitalization(); + let mut sysvar_cache = SysvarCache::default(); - genesis_bank.fill_bank_with_ticks_for_tests(); - let bank = Bank::new_from_parent( - Arc::clone(&genesis_bank), - genesis_bank.collector_id(), - genesis_bank.slot() + 1, - ); + sysvar_cache.set_rent(Rent::default()); + sysvar_cache.set_clock(Clock::default()); if sync_state == SyncState::Yes { - utils::sync_sysvar_accounts(rpc, &bank).await?; + utils::sync_sysvar_accounts(rpc, &mut sysvar_cache).await?; } Ok(Self { - bank, runtime_config, - payer, + feature_set: Arc::new(feature_set), + accounts_db: HashMap::new(), + sysvar_cache, + payer: Keypair::new(), }) } @@ -99,6 +116,9 @@ impl SolanaSimulator { if account.executable && bpf_loader_upgradeable::check_id(&account.owner) { let programdata_address = utils::program_data_address(account)?; + debug!( + "program_data_account: program={key} programdata=address{programdata_address}" + ); programdata_keys.push(programdata_address); } @@ -115,6 +135,7 @@ impl SolanaSimulator { continue; }; + debug!("program_data_account: key={key} account={account:?}"); utils::reset_program_data_slot(account)?; storable_accounts.push((key, account)); } @@ -124,72 +145,49 @@ impl SolanaSimulator { Ok(()) } - const fn bank(&self) -> &Bank { - &self.bank - } - + #[must_use] pub const fn payer(&self) -> &Keypair { &self.payer } + #[must_use] pub fn blockhash(&self) -> Hash { - self.bank().last_blockhash() + Hash::new_unique() } - pub fn slot(&self) -> u64 { - self.bank().slot() + pub fn slot(&self) -> Result { + let clock = self.sysvar_cache.get_clock()?; + Ok(clock.slot) } - pub fn replace_blockhash(&mut self, blockhash: &Hash) { - self.bank().register_recent_blockhash(blockhash); - } - - pub fn set_sysvar(&self, sysvar: &T) + fn replace_sysvar_account(&mut self, sysvar: &S) where - T: Sysvar + SysvarId, + S: Sysvar + SysvarId, { - self.bank().set_sysvar_for_tests(sysvar); - } + let old_account = self.accounts_db.get(&S::id()); + let inherit = old_account.map_or(DUMMY_INHERITABLE_ACCOUNT_FIELDS, |a| { + (a.lamports(), a.rent_epoch()) + }); - pub fn set_program_account(&mut self, pubkey: &Pubkey, data: Vec) { - let rent = self.bank().rent_collector().rent; - let lamports = rent.minimum_balance(data.len()); - - self.set_account( - pubkey, - &Account { - lamports, - data, - owner: bpf_loader::ID, - executable: true, - rent_epoch: 0, - }, - ); + let account = create_account_shared_data_with_fields(sysvar, inherit); + self.accounts_db.insert(S::id(), account); } - pub fn set_account(&mut self, pubkey: &Pubkey, account: &Account) { - self.bank().store_account(pubkey, account); + pub fn set_clock(&mut self, clock: Clock) { + self.replace_sysvar_account(&clock); + self.sysvar_cache.set_clock(clock); } pub fn set_multiple_accounts(&mut self, accounts: &[(&Pubkey, &Account)]) { - let include_slot_in_hash = if self - .bank() - .feature_set - .is_active(&solana_sdk::feature_set::account_hash_ignore_slot::id()) - { - solana_accounts_db::accounts_db::IncludeSlotInHash::RemoveSlot - } else { - solana_accounts_db::accounts_db::IncludeSlotInHash::IncludeSlot - }; - - let storable_accounts = (self.slot(), accounts, include_slot_in_hash); - self.bank().store_accounts(storable_accounts); + for (pubkey, account) in accounts { + self.accounts_db + .insert(**pubkey, AccountSharedData::from((*account).clone())); + } } - pub fn get_account(&self, pubkey: &Pubkey) -> Option { - self.bank() - .get_account_with_fixed_root(pubkey) - .map(Account::from) + #[must_use] + pub fn get_shared_account(&self, pubkey: &Pubkey) -> Option { + self.accounts_db.get(pubkey).cloned() } pub fn sanitize_transaction( @@ -197,73 +195,291 @@ impl SolanaSimulator { tx: VersionedTransaction, verify: bool, ) -> Result { - let bank = self.bank(); + let sanitized_tx = { + let size = bincode::serialized_size(&tx)?; + if verify && (size > solana_sdk::packet::PACKET_DATA_SIZE as u64) { + return Err(TransactionError::SanitizeFailure.into()); + } - let sanitized = if verify { - bank.verify_transaction(tx, TransactionVerificationMode::FullVerification)? - } else { - let hash = tx.message.hash(); - SanitizedTransaction::try_create(tx, hash, None, bank)? - }; + let message_hash = if verify { + tx.verify_and_hash_message()? + } else { + tx.message.hash() + }; + + SanitizedTransaction::try_create(tx, message_hash, None, self) + }?; - Ok(sanitized) + if verify { + sanitized_tx.verify_precompiles(&self.feature_set)?; + } + + Ok(sanitized_tx) } pub fn process_transaction( - &mut self, - tx: SanitizedTransaction, - ) -> Result { - let mut result = self.process_multiple_not_intersected_transactions(&[tx])?; + &self, + blockhash: Hash, + tx: &SanitizedTransaction, + ) -> Result { + let mut transaction_accounts = Vec::new(); + for key in tx.message().account_keys().iter() { + let account = if solana_sdk::sysvar::instructions::check_id(key) { + construct_instructions_account(tx.message()) + } else { + self.accounts_db.get(key).cloned().unwrap_or_default() + }; + transaction_accounts.push((*key, account)); + } - Ok(result.remove(0)) - } + let program_indices = Self::build_program_indices(tx, &mut transaction_accounts); + + let compute_budget = self.runtime_config.compute_budget.unwrap_or_default(); + let rent: Arc = self.sysvar_cache.get_rent()?; + let clock: Arc = self.sysvar_cache.get_clock()?; + + let lamports_before_tx = + transaction_accounts_lamports_sum(&transaction_accounts, tx.message()).unwrap_or(0); - pub fn process_multiple_not_intersected_transactions( - &mut self, - txs: &[SanitizedTransaction], - ) -> Result, Error> { - let bank = self.bank(); - - let batch = bank.prepare_sanitized_batch(txs); - - let ( - solana_accounts_db::transaction_results::TransactionResults { - execution_results, .. - }, - .., - ) = bank.load_execute_and_commit_transactions( - &batch, - solana_sdk::clock::MAX_PROCESSING_AGE, - false, // collect_balances - true, // enable_cpi_recording - true, // enable_log_recording - true, // enable_return_data_recording - &mut solana_program_runtime::timings::ExecuteTimings::default(), - self.runtime_config.log_messages_bytes_limit, + let mut transaction_context = TransactionContext::new( + transaction_accounts, + *rent, + compute_budget.max_invoke_stack_height, + compute_budget.max_instruction_trace_length, ); - let mut result = Vec::with_capacity(execution_results.len()); + let loaded_programs = self.load_programs(tx, &compute_budget, &clock); - for execution_result in execution_results { - match execution_result { - TransactionExecutionResult::Executed { details, .. } => result.push(details), - TransactionExecutionResult::NotExecuted(error) => return Err(error.into()), - } + let mut modified_programs = LoadedProgramsForTxBatch::new( + clock.slot, + loaded_programs.environments.clone(), + loaded_programs.upcoming_environments.clone(), + loaded_programs.latest_root_epoch, + ); + + let log_collector = + LogCollector::new_ref_with_limit(self.runtime_config.log_messages_bytes_limit); + + let mut units_consumed = 0u64; + + let mut status = MessageProcessor::process_message( + tx.message(), + &program_indices, + &mut transaction_context, + Some(Rc::clone(&log_collector)), + &loaded_programs, + &mut modified_programs, + Arc::clone(&self.feature_set), + compute_budget, + &mut ExecuteTimings::default(), + &self.sysvar_cache, + blockhash, + DEFAULT_TARGET_LAMPORTS_PER_SIGNATURE / 2, + &mut units_consumed, + ); + + let inner_instructions = Some(inner_instructions_list_from_instruction_trace( + &transaction_context, + )); + + let ExecutionRecord { + accounts, + return_data, + touched_account_count: _touched_account_count, + accounts_resize_delta: _accounts_resize_delta, + } = transaction_context.into(); + + if status.is_ok() + && transaction_accounts_lamports_sum(&accounts, tx.message()) + .filter(|lamports_after_tx| lamports_before_tx == *lamports_after_tx) + .is_none() + { + status = Err(TransactionError::UnbalancedTransaction); } - Ok(result) + let logs = Rc::try_unwrap(log_collector) + .map(|log_collector| log_collector.into_inner().into_messages()) + .ok() + .unwrap(); + + let return_data = if return_data.data.is_empty() { + None + } else { + Some(return_data) + }; + + Ok(TransactionSimulationResult { + result: status, + logs, + post_simulation_accounts: accounts, + units_consumed, + return_data, + inner_instructions, + }) } - pub fn simulate_transaction( + #[allow(clippy::cast_possible_truncation)] + fn build_program_indices( + tx: &SanitizedTransaction, + transaction_accounts: &mut Vec<(Pubkey, AccountSharedData)>, + ) -> Vec> { + let builtins_start_index = transaction_accounts.len(); + tx.message() + .instructions() + .iter() + .map(|instruction| { + let mut account_indices: Vec = Vec::with_capacity(2); + + let program_index = instruction.program_id_index as usize; + let (program_id, program_account) = &transaction_accounts[program_index]; + + if solana_sdk::native_loader::check_id(program_id) { + return account_indices; + } + + account_indices.insert(0, program_index as IndexOfAccount); + + let owner = program_account.owner(); + if solana_sdk::native_loader::check_id(owner) { + return account_indices; + } + + if let Some(owner_index) = transaction_accounts[builtins_start_index..] + .iter() + .position(|(key, _)| key == owner) + { + let owner_index = owner_index + builtins_start_index; + account_indices.insert(0, owner_index as IndexOfAccount); + } else { + let _builtin = BUILTINS + .iter() + .find(|builtin| builtin.program_id == *owner) + .unwrap(); + + let owner_account = + AccountSharedData::new(100, 100, &solana_sdk::native_loader::id()); + transaction_accounts.push((*owner, owner_account)); + + let owner_index = transaction_accounts.len() - 1; + account_indices.insert(0, owner_index as IndexOfAccount); + } + + account_indices + }) + .collect() + } + + fn load_programs( &self, - tx: VersionedTransaction, - ) -> Result { - let sanitized = - SanitizedTransaction::try_create(tx, MessageHash::Compute, None, self.bank())?; + tx: &SanitizedTransaction, + compute_budget: &ComputeBudget, + clock: &Arc, + ) -> LoadedProgramsForTxBatch { + let program_runtime_environments = ProgramRuntimeEnvironments { + program_runtime_v1: Arc::new( + create_program_runtime_environment_v1( + &self.feature_set, + compute_budget, + true, + true, + ) + .unwrap(), + ), + program_runtime_v2: Arc::new(create_program_runtime_environment_v2( + compute_budget, + true, + )), + }; + + let mut loaded_programs = LoadedProgramsForTxBatch::new( + clock.slot, + program_runtime_environments.clone(), + None, + clock.epoch, + ); - let simulation_result = self.bank().simulate_transaction_unchecked(sanitized); + tx.message().account_keys().iter().for_each(|key| { + if loaded_programs.find(key).is_none() { + let account = self.accounts_db.get(key).cloned().unwrap_or_default(); + if PROGRAM_OWNERS.iter().any(|owner| account.owner() == owner) { + let mut load_program_metrics = LoadProgramMetrics { + program_id: key.to_string(), + ..LoadProgramMetrics::default() + }; + let loaded_program = match self.load_program_accounts(account) { + ProgramAccountLoadResult::InvalidAccountData => { + LoadedProgram::new_tombstone(0, LoadedProgramType::Closed) + } + + ProgramAccountLoadResult::ProgramOfLoaderV1orV2(program_account) => { + LoadedProgram::new( + program_account.owner(), + program_runtime_environments.program_runtime_v1.clone(), + 0, + 0, + None, + program_account.data(), + program_account.data().len(), + &mut load_program_metrics, + ) + .unwrap() + } + + ProgramAccountLoadResult::ProgramOfLoaderV3( + program_account, + programdata_account, + _slot, + ) => { + let programdata = programdata_account + .data() + .get(UpgradeableLoaderState::size_of_programdata_metadata()..) + .unwrap(); + LoadedProgram::new( + program_account.owner(), + program_runtime_environments.program_runtime_v1.clone(), + 0, + 0, + None, + programdata, + program_account + .data() + .len() + .saturating_add(programdata_account.data().len()), + &mut load_program_metrics, + ) + .unwrap() + } + + ProgramAccountLoadResult::ProgramOfLoaderV4(program_account, _slot) => { + let elf_bytes = program_account + .data() + .get(LoaderV4State::program_data_offset()..) + .unwrap(); + LoadedProgram::new( + program_account.owner(), + program_runtime_environments.program_runtime_v2.clone(), + 0, + 0, + None, + elf_bytes, + program_account.data().len(), + &mut load_program_metrics, + ) + .unwrap() + } + }; + loaded_programs.replenish(*key, Arc::new(loaded_program)); + } + } + }); - Ok(simulation_result) + for builtin in BUILTINS { + // create_loadable_account_with_fields + let program = LoadedProgram::new_builtin(0, builtin.name.len(), builtin.entrypoint); + loaded_programs.replenish(builtin.program_id, Arc::new(program)); + } + + loaded_programs } pub fn simulate_legacy_transaction( @@ -271,6 +487,198 @@ impl SolanaSimulator { tx: solana_sdk::transaction::Transaction, ) -> Result { let versioned_transaction = VersionedTransaction::from(tx); - self.simulate_transaction(versioned_transaction) + self.process_transaction( + *versioned_transaction.message.recent_blockhash(), + &self.sanitize_transaction(versioned_transaction, false)?, + ) + } + + fn load_program_accounts( + &self, + program_account: AccountSharedData, + ) -> ProgramAccountLoadResult { + debug_assert!(solana_bpf_loader_program::check_loader_id( + program_account.owner() + )); + + if loader_v4::check_id(program_account.owner()) { + return solana_loader_v4_program::get_state(program_account.data()) + .ok() + .and_then(|state| { + (!matches!(state.status, LoaderV4Status::Retracted)).then_some(state.slot) + }) + .map_or(ProgramAccountLoadResult::InvalidAccountData, |slot| { + ProgramAccountLoadResult::ProgramOfLoaderV4(program_account, slot) + }); + } + + if !bpf_loader_upgradeable::check_id(program_account.owner()) { + return ProgramAccountLoadResult::ProgramOfLoaderV1orV2(program_account); + } + + if let Ok(UpgradeableLoaderState::Program { + programdata_address, + }) = program_account.state() + { + if let Some(programdata_account) = self.accounts_db.get(&programdata_address).cloned() { + if let Ok(UpgradeableLoaderState::ProgramData { + slot, + upgrade_authority_address: _, + }) = programdata_account.state() + { + return ProgramAccountLoadResult::ProgramOfLoaderV3( + program_account, + programdata_account, + slot, + ); + } + } + } + ProgramAccountLoadResult::InvalidAccountData + } +} + +enum ProgramAccountLoadResult { + InvalidAccountData, + ProgramOfLoaderV1orV2(AccountSharedData), + ProgramOfLoaderV3(AccountSharedData, AccountSharedData, Slot), + ProgramOfLoaderV4(AccountSharedData, Slot), +} + +fn transaction_accounts_lamports_sum( + accounts: &[(Pubkey, AccountSharedData)], + message: &SanitizedMessage, +) -> Option { + let mut lamports_sum = 0u128; + for i in 0..message.account_keys().len() { + let (_, account) = accounts.get(i)?; + lamports_sum = lamports_sum.checked_add(u128::from(account.lamports()))?; + } + Some(lamports_sum) +} + +impl AddressLoader for &SolanaSimulator { + fn load_addresses( + self, + lookups: &[MessageAddressTableLookup], + ) -> Result { + let loaded_addresses = lookups + .iter() + .map(|address_table_lookup| { + let table_account = self + .get_shared_account(&address_table_lookup.account_key) + .ok_or(AddressLookupError::LookupTableAccountNotFound)?; + + if table_account.owner() != &address_lookup_table::program::id() { + return Err(AddressLookupError::InvalidAccountOwner); + } + + let current_slot = self + .slot() + .map_err(|_| AddressLookupError::LookupTableAccountNotFound)?; + + let slot_hashes = self + .sysvar_cache + .get_slot_hashes() + .map_err(|_| AddressLookupError::LookupTableAccountNotFound)?; + + let lookup_table = AddressLookupTable::deserialize(table_account.data()) + .map_err(|_| AddressLookupError::InvalidAccountData)?; + + Ok(LoadedAddresses { + writable: lookup_table.lookup( + current_slot, + &address_table_lookup.writable_indexes, + &slot_hashes, + )?, + readonly: lookup_table.lookup( + current_slot, + &address_table_lookup.readonly_indexes, + &slot_hashes, + )?, + }) + }) + .collect::>()?; + + Ok(loaded_addresses) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn test_hex_encode_tx() { + let bytes = [ + 1, 58, 23, 68, 33, 87, 114, 44, 125, 7, 236, 250, 189, 152, 80, 109, 13, 162, 107, 101, + 124, 216, 66, 80, 213, 40, 53, 51, 182, 30, 255, 233, 81, 173, 129, 169, 64, 34, 99, + 244, 26, 97, 234, 36, 224, 159, 246, 251, 59, 49, 38, 37, 93, 186, 243, 244, 21, 130, + 128, 72, 105, 242, 160, 60, 7, 1, 0, 12, 17, 231, 21, 48, 207, 152, 236, 233, 187, 223, + 100, 82, 93, 7, 113, 26, 194, 124, 70, 245, 140, 6, 215, 63, 170, 178, 46, 130, 201, + 93, 40, 215, 178, 87, 173, 47, 151, 71, 81, 72, 73, 80, 156, 165, 181, 37, 178, 136, + 180, 35, 74, 234, 62, 83, 114, 123, 149, 139, 225, 217, 56, 147, 131, 206, 45, 105, + 208, 134, 80, 73, 140, 123, 117, 252, 233, 38, 133, 137, 99, 77, 55, 167, 149, 85, 24, + 36, 45, 148, 20, 106, 29, 21, 63, 99, 229, 104, 209, 135, 106, 102, 83, 227, 22, 170, + 173, 106, 135, 14, 233, 81, 75, 157, 216, 252, 53, 197, 36, 130, 119, 213, 126, 95, 12, + 254, 107, 149, 132, 193, 66, 216, 86, 105, 62, 222, 21, 157, 45, 17, 10, 178, 124, 189, + 91, 143, 219, 219, 104, 133, 196, 14, 129, 66, 215, 247, 28, 36, 71, 221, 69, 99, 94, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3, 6, 70, 111, 229, 33, 23, 50, 255, 236, 173, 186, 114, 195, 155, 231, 188, + 140, 229, 187, 197, 247, 18, 107, 44, 67, 155, 58, 64, 0, 0, 0, 7, 215, 243, 216, 48, + 133, 75, 3, 197, 149, 83, 168, 150, 114, 90, 186, 70, 253, 177, 48, 225, 211, 142, 191, + 241, 13, 77, 252, 188, 202, 215, 228, 40, 226, 52, 125, 171, 215, 127, 195, 1, 133, 3, + 55, 38, 152, 124, 161, 200, 77, 29, 38, 158, 98, 147, 173, 205, 87, 50, 86, 244, 38, + 253, 251, 60, 0, 57, 43, 120, 125, 56, 168, 83, 209, 36, 5, 118, 52, 196, 60, 113, 51, + 198, 18, 70, 29, 116, 254, 177, 127, 66, 72, 21, 82, 134, 192, 90, 72, 243, 77, 170, + 80, 23, 118, 170, 39, 23, 58, 58, 106, 22, 11, 26, 111, 175, 251, 186, 179, 49, 60, 52, + 157, 46, 126, 243, 174, 139, 107, 91, 173, 150, 43, 91, 46, 211, 20, 76, 212, 62, 196, + 7, 39, 240, 9, 4, 65, 17, 249, 203, 197, 140, 181, 38, 196, 213, 83, 115, 120, 145, 11, + 94, 103, 100, 49, 70, 40, 205, 74, 224, 203, 66, 252, 113, 38, 143, 168, 244, 184, 32, + 23, 8, 184, 93, 133, 24, 57, 107, 236, 123, 117, 13, 177, 115, 140, 234, 18, 14, 113, + 230, 247, 22, 144, 89, 29, 2, 140, 149, 150, 43, 254, 247, 11, 251, 18, 99, 69, 131, + 32, 152, 113, 83, 125, 6, 8, 196, 54, 180, 68, 255, 57, 153, 93, 12, 42, 185, 242, 64, + 126, 36, 91, 71, 227, 19, 94, 244, 179, 157, 76, 97, 249, 91, 53, 39, 250, 133, 28, + 197, 116, 21, 173, 61, 163, 236, 185, 166, 242, 81, 61, 9, 179, 63, 76, 24, 114, 82, + 18, 182, 138, 185, 121, 251, 101, 108, 251, 132, 89, 201, 201, 238, 34, 115, 103, 121, + 227, 23, 147, 27, 162, 42, 67, 149, 80, 211, 223, 101, 182, 167, 128, 216, 67, 155, 21, + 245, 228, 13, 178, 54, 172, 119, 171, 72, 106, 157, 37, 107, 127, 172, 209, 12, 110, + 173, 6, 145, 14, 187, 127, 145, 195, 53, 103, 119, 182, 129, 49, 170, 8, 237, 99, 87, + 32, 152, 64, 4, 6, 0, 9, 3, 2, 0, 0, 0, 0, 0, 0, 0, 6, 0, 5, 1, 0, 0, 4, 0, 6, 0, 5, 2, + 192, 92, 21, 0, 9, 15, 2, 0, 3, 4, 5, 7, 8, 1, 10, 11, 12, 13, 14, 15, 16, 122, 52, 14, + 0, 0, 0, 88, 49, 0, 0, 12, 0, 0, 0, 248, 107, 1, 132, 119, 53, 148, 0, 132, 9, 61, 92, + 128, 148, 163, 222, 235, 37, 106, 70, 13, 34, 201, 224, 71, 134, 58, 94, 231, 159, 237, + 188, 62, 73, 128, 132, 52, 103, 185, 80, 130, 1, 2, 160, 244, 180, 133, 103, 74, 93, + 21, 159, 64, 57, 219, 13, 44, 152, 135, 226, 169, 32, 159, 38, 122, 70, 119, 143, 47, + 187, 8, 70, 187, 84, 246, 50, 160, 37, 44, 189, 121, 39, 163, 64, 35, 212, 96, 114, + 159, 112, 19, 137, 242, 122, 153, 40, 66, 91, 58, 177, 212, 56, 211, 173, 170, 83, 13, + 176, 85, + ]; + eprintln!("{}", hex::encode(bytes)); + // assert_eq!(true, false); + } + + #[test] + fn test_hex_encode_v0_tx() { + let bytes = [ + 1, 195, 51, 167, 150, 247, 55, 53, 248, 87, 145, 226, 107, 103, 143, 215, 85, 62, 100, + 128, 254, 136, 249, 2, 68, 10, 226, 181, 117, 197, 116, 123, 10, 25, 188, 7, 130, 56, + 16, 164, 148, 238, 144, 40, 1, 29, 213, 36, 243, 153, 42, 247, 46, 74, 245, 246, 187, + 202, 223, 137, 176, 212, 204, 198, 6, 128, 1, 0, 3, 4, 129, 250, 211, 63, 136, 192, + 175, 63, 138, 71, 161, 34, 135, 75, 55, 3, 149, 61, 84, 23, 252, 239, 203, 80, 170, + 175, 222, 166, 136, 217, 173, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 6, 70, 111, 229, 33, 23, 50, 255, 236, + 173, 186, 114, 195, 155, 231, 188, 140, 229, 187, 197, 247, 18, 107, 44, 67, 155, 58, + 64, 0, 0, 0, 60, 0, 57, 43, 120, 125, 56, 168, 83, 209, 36, 5, 118, 52, 196, 60, 113, + 51, 198, 18, 70, 29, 116, 254, 177, 127, 66, 72, 21, 82, 134, 192, 120, 25, 149, 73, + 158, 141, 39, 109, 12, 97, 90, 180, 212, 130, 149, 30, 62, 56, 197, 80, 116, 62, 58, 5, + 27, 10, 213, 206, 39, 141, 199, 83, 4, 2, 0, 9, 3, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 5, 1, + 0, 0, 4, 0, 2, 0, 5, 2, 192, 92, 21, 0, 3, 32, 24, 0, 29, 17, 1, 6, 28, 26, 33, 16, 18, + 31, 8, 12, 11, 25, 13, 32, 30, 15, 14, 4, 10, 22, 9, 27, 23, 21, 5, 19, 20, 7, 5, 51, + 29, 0, 0, 0, 1, 35, 227, 136, 54, 194, 46, 23, 104, 208, 155, 167, 222, 101, 18, 44, + 98, 220, 121, 194, 180, 176, 19, 46, 226, 47, 225, 188, 124, 123, 18, 197, 81, 26, 0, + 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 20, 21, 22, 24, 25, 26, 27, + 28, 29, 4, 2, 3, 18, 23, + ]; + eprintln!("{}", hex::encode(bytes)); + // assert_eq!(true, false); } } diff --git a/evm_loader/lib/src/solana_simulator/utils.rs b/evm_loader/lib/src/solana_simulator/utils.rs index 162a29ea2..d30dbefe2 100644 --- a/evm_loader/lib/src/solana_simulator/utils.rs +++ b/evm_loader/lib/src/solana_simulator/utils.rs @@ -1,8 +1,6 @@ use super::error::Error; -use solana_runtime::{ - bank::Bank, - genesis_utils::{create_genesis_config_with_leader_ex, GenesisConfigInfo}, -}; +use log::debug; +use solana_program_runtime::sysvar_cache::SysvarCache; use solana_sdk::{ account::Account, account_utils::StateMut, @@ -11,11 +9,7 @@ use solana_sdk::{ state::{AddressLookupTable, LookupTableMeta}, }, bpf_loader_upgradeable::{self, UpgradeableLoaderState}, - fee_calculator::DEFAULT_TARGET_LAMPORTS_PER_SIGNATURE, - native_token::sol_to_lamports, pubkey::Pubkey, - signature::Keypair, - signer::Signer, sysvar, }; @@ -27,54 +21,10 @@ pub enum SyncState { Yes, } -pub async fn genesis_config_info( +pub async fn sync_sysvar_accounts( rpc: &impl Rpc, - sync: SyncState, - mint_sol: f64, -) -> Result { - let rent = sysvar::rent::Rent::default(); - let fee_rate_governor = solana_sdk::fee_calculator::FeeRateGovernor { - // Initialize with a non-zero fee - lamports_per_signature: DEFAULT_TARGET_LAMPORTS_PER_SIGNATURE / 2, - ..solana_sdk::fee_calculator::FeeRateGovernor::default() - }; - let validator_pubkey = Pubkey::new_unique(); - let validator_stake_lamports = rent - .minimum_balance(solana_sdk::vote::state::VoteState::size_of()) - + sol_to_lamports(1_000_000.0); - - let mint_keypair = Keypair::new(); - let voting_keypair = Keypair::new(); - - let mut genesis_config = create_genesis_config_with_leader_ex( - sol_to_lamports(mint_sol), - &mint_keypair.pubkey(), - &validator_pubkey, - &voting_keypair.pubkey(), - &Pubkey::new_unique(), - validator_stake_lamports, - 42, - fee_rate_governor, - rent, - solana_sdk::genesis_config::ClusterType::Development, - vec![], - ); - - if sync == SyncState::Yes { - for feature in rpc.get_deactivated_solana_features().await? { - genesis_config.accounts.remove(&feature); - } - } - - Ok(GenesisConfigInfo { - genesis_config, - mint_keypair, - voting_keypair, - validator_pubkey, - }) -} - -pub async fn sync_sysvar_accounts(rpc: &impl Rpc, bank: &Bank) -> Result<(), Error> { + sysvar_cache: &mut SysvarCache, +) -> Result<(), Error> { let keys = sysvar::ALL_IDS.clone(); let accounts = rpc.get_multiple_accounts(&keys).await?; for (key, account) in keys.into_iter().zip(accounts) { @@ -87,57 +37,57 @@ pub async fn sync_sysvar_accounts(rpc: &impl Rpc, bank: &Bank) -> Result<(), Err use sysvar::clock::Clock; let clock: Clock = bincode::deserialize(&account.data)?; - bank.set_sysvar_for_tests(&clock); + sysvar_cache.set_clock(clock); + } + sysvar::epoch_rewards::ID => { + use sysvar::epoch_rewards::EpochRewards; + + let epoch_rewards: EpochRewards = bincode::deserialize(&account.data)?; + sysvar_cache.set_epoch_rewards(epoch_rewards); } sysvar::epoch_schedule::ID => { use sysvar::epoch_schedule::EpochSchedule; let epoch_schedule: EpochSchedule = bincode::deserialize(&account.data)?; - bank.set_sysvar_for_tests(&epoch_schedule); + sysvar_cache.set_epoch_schedule(epoch_schedule); } sysvar::rent::ID => { use sysvar::rent::Rent; let rent: Rent = bincode::deserialize(&account.data)?; - bank.set_sysvar_for_tests(&rent); - } - sysvar::rewards::ID => { - use sysvar::rewards::Rewards; - - let rewards: Rewards = bincode::deserialize(&account.data)?; - bank.set_sysvar_for_tests(&rewards); + sysvar_cache.set_rent(rent); } sysvar::slot_hashes::ID => { use sysvar::slot_hashes::SlotHashes; let slot_hashes: SlotHashes = bincode::deserialize(&account.data)?; - bank.set_sysvar_for_tests(&slot_hashes); - } - sysvar::slot_history::ID => { - use sysvar::slot_history::SlotHistory; - - let slot_history: SlotHistory = bincode::deserialize(&account.data)?; - bank.set_sysvar_for_tests(&slot_history); + sysvar_cache.set_slot_hashes(slot_hashes); } sysvar::stake_history::ID => { use sysvar::stake_history::StakeHistory; let stake_history: StakeHistory = bincode::deserialize(&account.data)?; - bank.set_sysvar_for_tests(&stake_history); + sysvar_cache.set_stake_history(stake_history); } #[allow(deprecated)] id if sysvar::fees::check_id(&id) => { use sysvar::fees::Fees; let fees: Fees = bincode::deserialize(&account.data)?; - bank.set_sysvar_for_tests(&fees); + sysvar_cache.set_fees(fees); + } + sysvar::last_restart_slot::ID => { + use sysvar::last_restart_slot::LastRestartSlot; + + let last_restart_slot: LastRestartSlot = bincode::deserialize(&account.data)?; + sysvar_cache.set_last_restart_slot(last_restart_slot); } #[allow(deprecated)] id if sysvar::recent_blockhashes::check_id(&id) => { use sysvar::recent_blockhashes::RecentBlockhashes; let recent_blockhashes: RecentBlockhashes = bincode::deserialize(&account.data)?; - bank.set_sysvar_for_tests(&recent_blockhashes); + sysvar_cache.set_recent_blockhashes(recent_blockhashes); } _ => {} } @@ -148,7 +98,7 @@ pub async fn sync_sysvar_accounts(rpc: &impl Rpc, bank: &Bank) -> Result<(), Err pub fn program_data_address(account: &Account) -> Result { assert!(account.executable); - assert!(account.owner == bpf_loader_upgradeable::id()); + assert_eq!(account.owner, bpf_loader_upgradeable::id()); let UpgradeableLoaderState::Program { programdata_address, @@ -162,27 +112,35 @@ pub fn program_data_address(account: &Account) -> Result { } pub fn reset_program_data_slot(account: &mut Account) -> Result<(), Error> { - assert!(account.owner == bpf_loader_upgradeable::id()); + assert_eq!(account.owner, bpf_loader_upgradeable::id()); let UpgradeableLoaderState::ProgramData { + slot, upgrade_authority_address, - .. } = account.state()? else { return Err(Error::ProgramAccountError); }; + debug!( + "slot_before_update: slot={slot} upgrade_authority_address={upgrade_authority_address:?}" + ); + let new_state = UpgradeableLoaderState::ProgramData { slot: 0, upgrade_authority_address, }; account.set_state(&new_state)?; + debug!( + "slot_after_update: slot={slot} upgrade_authority_address={upgrade_authority_address:?}" + ); + Ok(()) } pub fn reset_alt_slot(account: &mut Account) -> Result<(), Error> { - assert!(account.owner == address_lookup_table::program::id()); + assert_eq!(account.owner, address_lookup_table::program::id()); let lookup_table = AddressLookupTable::deserialize(&account.data)?; let metadata = LookupTableMeta { diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index 79602587f..718ed4583 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -175,6 +175,7 @@ pub struct EmulateApiRequest { pub body: EmulateRequest, pub slot: Option, pub tx_index_in_block: Option, + pub id: Option, } #[derive(Deserialize, Serialize, Debug, Default, Copy, Clone, Eq, PartialEq)] @@ -203,6 +204,7 @@ pub struct GetBalanceRequest { #[serde_as(as = "OneOrMany<_>")] pub account: Vec, pub slot: Option, + pub id: Option, } #[serde_as] @@ -211,6 +213,7 @@ pub struct GetContractRequest { #[serde_as(as = "OneOrMany<_>")] pub contract: Vec
, pub slot: Option, + pub id: Option, } #[derive(Serialize, Deserialize, Debug, Default)] @@ -218,6 +221,7 @@ pub struct GetStorageAtRequest { pub contract: Address, pub index: U256, pub slot: Option, + pub id: Option, } #[derive(Deserialize, Serialize, Debug, Default)] @@ -250,6 +254,7 @@ pub struct GetHolderRequest { #[serde_as(as = "DisplayFromStr")] pub pubkey: Pubkey, pub slot: Option, + pub id: Option, } #[serde_as] @@ -263,6 +268,7 @@ pub struct SimulateSolanaRequest { pub blockhash: [u8; 32], #[serde_as(as = "Vec")] pub transactions: Vec>, + pub id: Option, } #[cfg(test)] diff --git a/evm_loader/lib/src/types/tracer_ch_common.rs b/evm_loader/lib/src/types/tracer_ch_common.rs index 16ab260e7..8e50def58 100644 --- a/evm_loader/lib/src/types/tracer_ch_common.rs +++ b/evm_loader/lib/src/types/tracer_ch_common.rs @@ -75,7 +75,7 @@ pub struct AccountRow { impl fmt::Debug for AccountRow { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut debug_struct = f.debug_struct("Account"); + let mut debug_struct = f.debug_struct("AccountRow"); debug_struct .field("owner", &bs58::encode(&self.owner).into_string()) diff --git a/evm_loader/lib/src/types/tracer_ch_db.rs b/evm_loader/lib/src/types/tracer_ch_db.rs index a61817420..673d3f9c1 100644 --- a/evm_loader/lib/src/types/tracer_ch_db.rs +++ b/evm_loader/lib/src/types/tracer_ch_db.rs @@ -122,7 +122,7 @@ impl ClickHouseDb { info!("get_branch_slots {{ slot: {slot:?} }}"); - let query = r#" + let query = r" SELECT DISTINCT ON (slot, parent) slot, parent, status FROM events.update_slot WHERE slot >= ( @@ -133,7 +133,7 @@ impl ClickHouseDb { ) AND isNotNull(parent) ORDER BY slot DESC, status DESC - "#; + "; let time_start = Instant::now(); let mut rows = self .client @@ -183,7 +183,7 @@ impl ClickHouseDb { async fn get_account_rooted_slot(&self, key: &str, slot: u64) -> ChResult> { info!("get_account_rooted_slot {{ key: {key}, slot: {slot} }}"); - let query = r#" + let query = r" SELECT DISTINCT uad.slot FROM events.update_account_distributed AS uad WHERE uad.pubkey = ? @@ -195,7 +195,7 @@ impl ClickHouseDb { ) >= 1 ORDER BY uad.slot DESC LIMIT 1 - "#; + "; let time_start = Instant::now(); let slot_opt = Self::row_opt( @@ -264,14 +264,14 @@ impl ClickHouseDb { let mut row = if branch.is_empty() { None } else { - let query = r#" + let query = r" SELECT owner, lamports, executable, rent_epoch, data, txn_signature FROM events.update_account_distributed WHERE pubkey = ? AND slot IN ? ORDER BY pubkey, slot DESC, write_version DESC LIMIT 1 - "#; + "; let time_start = Instant::now(); let row = Self::row_opt( @@ -325,7 +325,7 @@ impl ClickHouseDb { "get_account_at_index_in_block {{ pubkey: {pubkey}, slot: {slot}, tx_index_in_block: {tx_index_in_block} }}" ); - let query = r#" + let query = r" SELECT owner, lamports, executable, rent_epoch, data, txn_signature FROM events.update_account_distributed WHERE pubkey = ? @@ -333,7 +333,7 @@ impl ClickHouseDb { AND write_version <= ? ORDER BY write_version DESC LIMIT 1 - "#; + "; let time_start = Instant::now(); @@ -368,13 +368,13 @@ impl ClickHouseDb { pubkey: &str, slot: u64, ) -> ChResult> { - let query = r#" + let query = r" SELECT owner, lamports, executable, rent_epoch, data, txn_signature FROM events.older_account_distributed FINAL WHERE pubkey = ? AND slot <= ? ORDER BY slot DESC LIMIT 1 - "#; + "; Self::row_opt( self.client .query(query) @@ -390,7 +390,7 @@ impl ClickHouseDb { } async fn get_sol_sig_rooted_slot(&self, sol_sig: &[u8; 64]) -> ChResult> { - let query = r#" + let query = r" SELECT slot, parent FROM events.rooted_slots WHERE slot IN ( @@ -400,7 +400,7 @@ impl ClickHouseDb { ) ORDER BY slot DESC LIMIT 1 - "#; + "; Self::row_opt( self.client @@ -418,7 +418,7 @@ impl ClickHouseDb { async fn get_sol_sig_confirmed_slot(&self, sol_sig: &[u8; 64]) -> ChResult> { let (_, slot_vec) = self.get_branch_slots(None).await?; - let query = r#" + let query = r" SELECT slot, parent, status FROM events.update_slot WHERE slot IN ? @@ -429,7 +429,7 @@ impl ClickHouseDb { ) ORDER BY slot DESC LIMIT 1 - "#; + "; Self::row_opt( self.client @@ -476,13 +476,13 @@ impl ClickHouseDb { }; // Try to find account changes within the given slot. - let query = r#" + let query = r" SELECT DISTINCT ON (pubkey, txn_signature, write_version) owner, lamports, executable, rent_epoch, data, txn_signature FROM events.update_account_distributed WHERE slot = ? AND pubkey = ? ORDER BY write_version DESC - "#; + "; let pubkey_str = format!("{:?}", pubkey.to_bytes()); let time_start = Instant::now(); @@ -538,7 +538,7 @@ impl ClickHouseDb { } pub async fn get_neon_revision(&self, slot: Slot, pubkey: &Pubkey) -> ChResult { - let query = r#"SELECT data + let query = r"SELECT data FROM events.update_account_distributed WHERE pubkey = ? AND slot <= ? @@ -547,7 +547,7 @@ impl ClickHouseDb { slot ASC, write_version ASC LIMIT 1 - "#; + "; let pubkey_str = format!("{:?}", pubkey.to_bytes()); @@ -576,13 +576,13 @@ impl ClickHouseDb { } pub async fn get_neon_revisions(&self, pubkey: &Pubkey) -> ChResult { - let query = r#"SELECT slot, data + let query = r"SELECT slot, data FROM events.update_account_distributed WHERE pubkey = ? ORDER BY slot ASC, - write_version ASC"#; + write_version ASC"; let pubkey_str = format!("{:?}", pubkey.to_bytes()); let rows: Vec = self @@ -608,11 +608,11 @@ impl ClickHouseDb { } pub async fn get_slot_by_blockhash(&self, blockhash: &str) -> ChResult { - let query = r#"SELECT slot + let query = r"SELECT slot FROM events.notify_block_distributed WHERE hash = ? LIMIT 1 - "#; + "; let slot = Self::row_opt( self.client @@ -632,14 +632,14 @@ impl ClickHouseDb { } pub async fn get_sync_status(&self) -> ChResult { - let query_is_startup = r#"SELECT is_startup + let query_is_startup = r"SELECT is_startup FROM events.update_account_distributed WHERE slot = ( SELECT MAX(slot) FROM events.update_account_distributed ) LIMIT 1 - "#; + "; let is_startup = Self::row_opt( self.client @@ -649,7 +649,7 @@ impl ClickHouseDb { )?; if is_startup == Some(true) { - let query = r#"SELECT slot + let query = r"SELECT slot FROM ( (SELECT MIN(slot) as slot FROM events.notify_block_distributed) UNION ALL @@ -658,7 +658,7 @@ impl ClickHouseDb { (SELECT MAX(slot) as slot FROM events.notify_block_distributed) ) ORDER BY slot ASC - "#; + "; let data = Self::row_opt(self.client.query(query).fetch_one::().await)?; diff --git a/evm_loader/program-macro/src/config_parser.rs b/evm_loader/program-macro/src/config_parser.rs index 77ccf1922..62a05f15e 100644 --- a/evm_loader/program-macro/src/config_parser.rs +++ b/evm_loader/program-macro/src/config_parser.rs @@ -147,7 +147,7 @@ impl Parse for CommonConfig { r#type: Type::Verbatim(quote!(bool)), value: Lit::Bool(LitBool::new(v, input.span())), }), - toml::Value::Array(ref array) => match (array.get(0), array.get(1)) { + toml::Value::Array(ref array) => match (array.first(), array.get(1)) { (Some(toml::Value::Integer(v)), Some(toml::Value::String(t))) => { let s = v.to_string(); let v: LitInt = parse_str(&s)?; diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 424794ecb..072e93d3a 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -1,4 +1,4 @@ -# Note: This crate must be built using cargo build-bpf +# Note: This crate must be built using cargo build-sbf [package] name = "evm-loader" @@ -44,8 +44,8 @@ spl-token = { version = "~4.0", default-features = false, features = ["no-entryp spl-associated-token-account = { version = "~2.3", default-features = false, features = ["no-entrypoint"] } mpl-token-metadata = { version = "~4.1", default-features = false } thiserror = "1.0" -arrayref = "0.3.6" -hex = "0.4.2" +arrayref = "0.3.8" +hex = "0.4.3" ripemd = "0.1" rlp = "0.5" static_assertions = "1" @@ -60,11 +60,11 @@ maybe-async = "0.2.10" async-trait = { version = "0.1.81", optional = true } [target.'cfg(target_os = "solana")'.dependencies.maybe-async] -version = "0.2.7" +version = "0.2.10" features = ["is_sync"] [dev-dependencies] -tokio = { version = "1.0", features = ["full"] } +tokio = { version = "1.38", features = ["full"] } serde_json = { version = "1.0.120", features = ["preserve_order"] } solana-sdk.workspace = true diff --git a/evm_loader/program/src/account/mod.rs b/evm_loader/program/src/account/mod.rs index 134262179..bd55d2019 100644 --- a/evm_loader/program/src/account/mod.rs +++ b/evm_loader/program/src/account/mod.rs @@ -285,6 +285,7 @@ impl<'a> AccountsDB<'a> { } } +#[allow(clippy::into_iter_without_iter)] impl<'a, 'r> IntoIterator for &'r AccountsDB<'a> { type Item = &'r AccountInfo<'a>; type IntoIter = std::slice::Iter<'r, AccountInfo<'a>>; diff --git a/evm_loader/program/src/account/state.rs b/evm_loader/program/src/account/state.rs index 9fac9299b..8ff3a1f90 100644 --- a/evm_loader/program/src/account/state.rs +++ b/evm_loader/program/src/account/state.rs @@ -88,6 +88,7 @@ struct Data { pub steps_executed: u64, } +#[allow(clippy::struct_field_names)] #[repr(C, packed)] struct Header { pub evm_state_len: usize, diff --git a/evm_loader/rpc-client/Cargo.toml b/evm_loader/rpc-client/Cargo.toml index 773cd83be..d1d693393 100644 --- a/evm_loader/rpc-client/Cargo.toml +++ b/evm_loader/rpc-client/Cargo.toml @@ -11,9 +11,9 @@ serde_json = "1.0.120" neon-lib = { path = "../lib" } thiserror = "1.0.63" async-trait = "0.1.81" -jsonrpsee-core = "0.22.3" -jsonrpsee-http-client = "0.22.3" -jsonrpsee-types = "0.22.3" +jsonrpsee-core = "0.22.5" +jsonrpsee-http-client = "0.22.5" +jsonrpsee-types = "0.22.5" tokio = { version = "1", features = ["full"] } build-info = "0.0.37" diff --git a/evm_loader/rpc/Cargo.toml b/evm_loader/rpc/Cargo.toml index 7a4d13cd8..1cf1fb602 100644 --- a/evm_loader/rpc/Cargo.toml +++ b/evm_loader/rpc/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] actix-web = "4.8.0" -clap = "2.33.3" +clap = "2.34.0" jsonrpc-v2 = "0.13.0" neon-lib-interface = { path = "../lib-interface" } neon-lib = { path = "../lib" } diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 50fa4928b..7897a24d1 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.73" +channel = "1.75.0" From f86f8c8650f50a8c496396731922c88c7909ea59 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Jul 2024 18:20:14 +0200 Subject: [PATCH 278/318] Bump clickhouse from 0.11.6 to 0.12.0 in /evm_loader (#511) Bumps [clickhouse](https://github.com/loyd/clickhouse.rs) from 0.11.6 to 0.12.0. - [Changelog](https://github.com/loyd/clickhouse.rs/blob/master/CHANGELOG.md) - [Commits](https://github.com/loyd/clickhouse.rs/compare/v0.11.6...v0.12.0) --- updated-dependencies: - dependency-name: clickhouse dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 155 ++++++++++++++++++++++++++------------ evm_loader/lib/Cargo.toml | 2 +- 2 files changed, 109 insertions(+), 48 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index fda9508b1..932a002b2 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -98,7 +98,7 @@ dependencies = [ "flate2", "futures-core", "h2", - "http", + "http 0.2.12", "httparse", "httpdate", "itoa", @@ -145,7 +145,7 @@ checksum = "13d324164c51f63867b57e73ba5936ea151b8a41a1d23d1031eeb9f70d0236f8" dependencies = [ "bytestring", "cfg-if", - "http", + "http 0.2.12", "regex", "regex-lite", "serde", @@ -1255,17 +1255,19 @@ dependencies = [ [[package]] name = "clickhouse" -version = "0.11.6" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0875e527e299fc5f4faba42870bf199a39ab0bb2dbba1b8aef0a2151451130f" +checksum = "eab6d70c534d5e54680aae99712800fca8d048cdfad3fbd154daf823d444f08b" dependencies = [ "bstr", "bytes", "clickhouse-derive", "clickhouse-rs-cityhash-sys", "futures", - "hyper", - "hyper-tls", + "futures-channel", + "http-body-util", + "hyper 1.4.1", + "hyper-util", "lz4", "sealed", "serde", @@ -1277,14 +1279,14 @@ dependencies = [ [[package]] name = "clickhouse-derive" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18af5425854858c507eec70f7deb4d5d8cec4216fcb086283a78872387281ea5" +checksum = "d70f3e2893f7d3e017eeacdc9a708fbc29a10488e3ebca21f9df6a5d2b616dbb" dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 1.0.109", + "syn 2.0.72", ] [[package]] @@ -2375,7 +2377,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.12", "indexmap 2.2.6", "slab", "tokio", @@ -2434,7 +2436,7 @@ dependencies = [ "base64 0.21.7", "bytes", "headers-core", - "http", + "http 0.2.12", "httpdate", "mime", "sha1", @@ -2446,16 +2448,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" dependencies = [ - "http", -] - -[[package]] -name = "heck" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", + "http 0.2.12", ] [[package]] @@ -2560,6 +2553,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.6" @@ -2567,7 +2571,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.1.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", "pin-project-lite", ] @@ -2600,8 +2627,8 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", - "http-body", + "http 0.2.12", + "http-body 0.4.6", "httparse", "httpdate", "itoa", @@ -2613,6 +2640,25 @@ dependencies = [ "want", ] +[[package]] +name = "hyper" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + [[package]] name = "hyper-rustls" version = "0.24.2" @@ -2620,8 +2666,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", - "http", - "hyper", + "http 0.2.12", + "hyper 0.14.30", "log", "rustls", "rustls-native-certs", @@ -2636,12 +2682,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper", + "hyper 0.14.30", "native-tls", "tokio", "tokio-native-tls", ] +[[package]] +name = "hyper-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "hyper 1.4.1", + "pin-project-lite", + "socket2", + "tokio", + "tower", + "tower-service", + "tracing", +] + [[package]] name = "iana-time-zone" version = "0.1.60" @@ -2904,7 +2970,7 @@ dependencies = [ "async-trait", "beef", "futures-util", - "hyper", + "hyper 0.14.30", "jsonrpsee-types", "serde", "serde_json", @@ -2920,7 +2986,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ccf93fc4a0bfe05d851d37d7c32b7f370fe94336b52a2f0efc5f1981895c2e5" dependencies = [ "async-trait", - "hyper", + "hyper 0.14.30", "hyper-rustls", "jsonrpsee-core", "jsonrpsee-types", @@ -3395,7 +3461,7 @@ dependencies = [ "goblin 0.8.2", "hex", "hex-literal", - "hyper", + "hyper 0.14.30", "lazy_static", "log", "neon-lib-interface", @@ -4441,9 +4507,9 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", - "http-body", - "hyper", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.30", "hyper-rustls", "hyper-tls", "ipnet", @@ -4724,14 +4790,14 @@ dependencies = [ [[package]] name = "sealed" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b5e421024b5e5edfbaa8e60ecf90bda9dbffc602dbb230e6028763f85f0c68c" +checksum = "f4a8caec23b7800fb97971a1c6ae365b6239aaeddfb934d6265f8505e795699d" dependencies = [ - "heck 0.3.3", + "heck 0.4.1", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.72", ] [[package]] @@ -4824,13 +4890,13 @@ dependencies = [ [[package]] name = "serde_derive_internals" -version = "0.26.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.72", ] [[package]] @@ -6968,6 +7034,7 @@ dependencies = [ "futures-util", "pin-project", "pin-project-lite", + "tokio", "tower-layer", "tower-service", "tracing", @@ -7089,7 +7156,7 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http", + "http 0.2.12", "httparse", "log", "rand 0.8.5", @@ -7146,12 +7213,6 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "unicode-segmentation" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" - [[package]] name = "unicode-width" version = "0.1.13" diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 6577ed2ef..5d2990442 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -36,7 +36,7 @@ ethnum = { version = "1.5", default-features = false, features = ["serde"] } goblin = { version = "0.8.2" } scroll = "0.12.0" tokio = { version = "1", features = ["full"] } -clickhouse = "0.11.6" +clickhouse = "0.12.0" tracing = "0.1" async-trait = "0.1.81" build-info = "0.0.37" From b9967fd73635a4440e7ad49e218310ce7a14303e Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Thu, 25 Jul 2024 11:06:21 +0200 Subject: [PATCH 279/318] NDEV-3207: Fix OnceCell race condition (#513) --- evm_loader/lib/src/commands/get_config.rs | 39 +++++++++++++---------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/evm_loader/lib/src/commands/get_config.rs b/evm_loader/lib/src/commands/get_config.rs index de3c675b7..0cd59b5d5 100644 --- a/evm_loader/lib/src/commands/get_config.rs +++ b/evm_loader/lib/src/commands/get_config.rs @@ -1,22 +1,21 @@ #![allow(clippy::future_not_send)] +use std::collections::BTreeMap; + use async_trait::async_trait; use base64::Engine; use enum_dispatch::enum_dispatch; -use std::collections::BTreeMap; -use tokio::sync::OnceCell; - use serde::{Deserialize, Serialize}; +use serde_with::{serde_as, DisplayFromStr}; +use solana_client::rpc_config::RpcSimulateTransactionConfig; +use solana_sdk::signer::Signer; use solana_sdk::{instruction::Instruction, pubkey::Pubkey, transaction::Transaction}; +use tokio::sync::OnceCell; +use crate::rpc::{CallDbClient, CloneRpcClient}; use crate::solana_simulator::SolanaSimulator; use crate::NeonResult; -use crate::rpc::{CallDbClient, CloneRpcClient}; -use serde_with::{serde_as, DisplayFromStr}; -use solana_client::rpc_config::RpcSimulateTransactionConfig; -use solana_sdk::signature::Signer; - #[derive(Debug, Serialize, Deserialize)] pub enum Status { Ok, @@ -286,18 +285,24 @@ pub async fn read_chains( rpc: &impl BuildConfigSimulator, program_id: Pubkey, ) -> NeonResult> { - if rpc.use_cache() && CHAINS_CACHE.initialized() { - return Ok(CHAINS_CACHE.get().unwrap().clone()); - } - - let mut simulator = rpc.build_config_simulator(program_id).await?; - let chains = simulator.get_chains().await?; - if rpc.use_cache() { - CHAINS_CACHE.set(chains.clone()).unwrap(); + return CHAINS_CACHE + .get_or_try_init(|| get_chains(rpc, program_id)) + .await + .cloned(); } - Ok(chains) + get_chains(rpc, program_id).await +} + +async fn get_chains( + rpc: &(impl BuildConfigSimulator + Sized), + program_id: Pubkey, +) -> NeonResult> { + rpc.build_config_simulator(program_id) + .await? + .get_chains() + .await } pub async fn read_legacy_chain_id( From d9285f43026864bf1633322532d4ca6240b62d18 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 25 Jul 2024 17:47:49 +0200 Subject: [PATCH 280/318] Bump tokio from 1.38.1 to 1.39.1 in /evm_loader (#512) Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.38.1 to 1.39.1. - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.38.1...tokio-1.39.1) --- updated-dependencies: - dependency-name: tokio dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 27 +++++++++++++++++++-------- evm_loader/program/Cargo.toml | 2 +- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 932a002b2..0d2df0475 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -173,7 +173,7 @@ dependencies = [ "actix-utils", "futures-core", "futures-util", - "mio", + "mio 0.8.11", "socket2", "tokio", "tracing", @@ -3315,6 +3315,18 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "mio" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.52.0", +] + [[package]] name = "mockall" version = "0.11.4" @@ -6871,28 +6883,27 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.38.1" +version = "1.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb2caba9f80616f438e09748d5acda951967e1ea58508ef53d9c6402485a46df" +checksum = "d040ac2b29ab03b09d4129c2f5bbd012a3ac2f79d38ff506a4bf8dd34b0eac8a" dependencies = [ "backtrace", "bytes", "libc", - "mio", - "num_cpus", + "mio 1.0.1", "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 072e93d3a..f573e6ea9 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -64,7 +64,7 @@ version = "0.2.10" features = ["is_sync"] [dev-dependencies] -tokio = { version = "1.38", features = ["full"] } +tokio = { version = "1.39", features = ["full"] } serde_json = { version = "1.0.120", features = ["preserve_order"] } solana-sdk.workspace = true From 4f1c1549f7a61c8cf9923364527c740b4d2808ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 26 Jul 2024 08:52:40 +0200 Subject: [PATCH 281/318] Bump toml from 0.8.15 to 0.8.16 in /evm_loader (#514) Bumps [toml](https://github.com/toml-rs/toml) from 0.8.15 to 0.8.16. - [Commits](https://github.com/toml-rs/toml/compare/toml-v0.8.15...toml-v0.8.16) --- updated-dependencies: - dependency-name: toml dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 0d2df0475..82708f890 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -2035,7 +2035,7 @@ dependencies = [ "quote", "serde", "syn 2.0.72", - "toml 0.8.15", + "toml 0.8.16", ] [[package]] @@ -4925,9 +4925,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" dependencies = [ "serde", ] @@ -6981,21 +6981,21 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.15" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac2caab0bf757388c6c0ae23b3293fdb463fee59434529014f85e3263b995c28" +checksum = "81967dd0dd2c1ab0bc3468bd7caecc32b8a4aa47d0c8c695d8c2b2108168d62c" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.16", + "toml_edit 0.22.17", ] [[package]] name = "toml_datetime" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +checksum = "f8fb9f64314842840f1d940ac544da178732128f1c78c21772e876579e0da1db" dependencies = [ "serde", ] @@ -7024,9 +7024,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.16" +version = "0.22.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "278f3d518e152219c994ce877758516bca5e118eaed6996192a774fb9fbf0788" +checksum = "8d9f8729f5aea9562aac1cc0441f5d6de3cff1ee0c5d67293eeca5eb36ee7c16" dependencies = [ "indexmap 2.2.6", "serde", From 37d05086f43b21b49b9a2b6893084b70b6aab143 Mon Sep 17 00:00:00 2001 From: Irina Guberman Date: Fri, 26 Jul 2024 21:08:39 -0500 Subject: [PATCH 282/318] Ndev 3198 rocksdb chdb (#509) Refactor TracerDb into optional and configurable Clickhouse or RocksDb implementation of TracerDb trait. --- .github/workflows/deploy.py | 4 +- .github/workflows/pipeline.yml | 1 + Dockerfile | 18 +- ci/solana-run-neon.sh | 1 + evm_loader/Cargo.lock | 2114 +++++++++-------- evm_loader/Cargo.toml | 23 +- evm_loader/api/Cargo.toml | 4 +- evm_loader/cli/Cargo.toml | 4 +- evm_loader/cli/src/main.rs | 17 +- evm_loader/lib-interface/Cargo.toml | 2 +- evm_loader/lib/Cargo.toml | 21 +- evm_loader/lib/src/abi/state.rs | 8 +- evm_loader/lib/src/account_data.rs | 35 +- evm_loader/lib/src/account_storage.rs | 16 +- evm_loader/lib/src/commands/emulate.rs | 8 +- evm_loader/lib/src/commands/get_config.rs | 3 +- .../lib/src/commands/simulate_solana.rs | 29 +- evm_loader/lib/src/commands/trace.rs | 7 +- .../lib/src/commands/transaction_executor.rs | 1 + evm_loader/lib/src/config.rs | 50 +- evm_loader/lib/src/rpc/db_call_client.rs | 13 +- evm_loader/lib/src/rpc/emulator_client.rs | 7 +- evm_loader/lib/src/rpc/validator_client.rs | 13 + evm_loader/lib/src/solana_simulator/error.rs | 16 +- evm_loader/lib/src/solana_simulator/mod.rs | 689 ++++-- evm_loader/lib/src/solana_simulator/utils.rs | 114 +- evm_loader/lib/src/types/mod.rs | 79 +- evm_loader/lib/src/types/tracer_ch_common.rs | 2 +- evm_loader/lib/src/types/tracer_ch_db.rs | 419 ++-- evm_loader/lib/src/types/tracer_rocks_db.rs | 82 +- evm_loader/program-macro/src/config_parser.rs | 11 +- evm_loader/program-macro/src/lib.rs | 13 + evm_loader/program/Cargo.toml | 12 +- evm_loader/program/config/default.toml | 3 + evm_loader/program/config/devnet.toml | 7 + evm_loader/program/config/govertest.toml | 3 + evm_loader/program/config/mainnet.toml | 7 + evm_loader/program/config/rollup.toml | 3 + evm_loader/program/config/testnet.toml | 3 + evm_loader/program/src/account/mod.rs | 1 + evm_loader/program/src/account/state.rs | 9 + evm_loader/rpc-client/Cargo.toml | 10 +- evm_loader/rpc/Cargo.toml | 2 +- rust-toolchain.toml | 2 +- 44 files changed, 2320 insertions(+), 1566 deletions(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index 23b131ccc..75d30904c 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -32,8 +32,8 @@ IMAGE_NAME = os.environ.get("IMAGE_NAME") RUN_LINK_REPO = os.environ.get("RUN_LINK_REPO") DOCKERHUB_ORG_NAME = os.environ.get("DOCKERHUB_ORG_NAME") -SOLANA_NODE_VERSION = 'v1.17.34' -SOLANA_BPF_VERSION = 'v1.17.34' +SOLANA_NODE_VERSION = 'v1.18.18' +SOLANA_BPF_VERSION = 'v1.18.18' VERSION_BRANCH_TEMPLATE = r"[vt]{1}\d{1,2}\.\d{1,2}\.x.*" docker_client = docker.APIClient() diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index d0ca7826f..c1adf0ec6 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -19,6 +19,7 @@ env: DOCKERHUB_ORG_NAME: ${{vars.DOCKERHUB_ORG_NAME}} RUN_LINK_REPO: "neonlabsorg/neon-proxy.py" BUILD_URL: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + TRACER_DB_TYPE: clickhouse concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/Dockerfile b/Dockerfile index 348d27084..88a6f2055 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ ARG SOLANA_IMAGE # Install BPF SDK -FROM solanalabs/rust:1.73.0 AS builder +FROM solanalabs/rust:1.75.0 AS builder RUN cargo install rustfilt WORKDIR /opt ARG SOLANA_BPF_VERSION @@ -20,14 +20,14 @@ RUN cargo fmt --check && \ # check cargo clippy --release && \ cargo build --release && \ cargo test --release && \ - cargo build-bpf --manifest-path program/Cargo.toml --features devnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-devnet.so && \ - cargo build-bpf --manifest-path program/Cargo.toml --features testnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-testnet.so && \ - cargo build-bpf --manifest-path program/Cargo.toml --features govertest && cp target/deploy/evm_loader.so target/deploy/evm_loader-govertest.so && \ - cargo build-bpf --manifest-path program/Cargo.toml --features govertest,emergency && cp target/deploy/evm_loader.so target/deploy/evm_loader-govertest-emergency.so && \ - cargo build-bpf --manifest-path program/Cargo.toml --features mainnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-mainnet.so && \ - cargo build-bpf --manifest-path program/Cargo.toml --features mainnet,emergency && cp target/deploy/evm_loader.so target/deploy/evm_loader-mainnet-emergency.so && \ - cargo build-bpf --manifest-path program/Cargo.toml --features rollup && cp target/deploy/evm_loader.so target/deploy/evm_loader-rollup.so && \ - cargo build-bpf --manifest-path program/Cargo.toml --features ci --dump + cargo build-sbf --manifest-path program/Cargo.toml --features devnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-devnet.so && \ + cargo build-sbf --manifest-path program/Cargo.toml --features testnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-testnet.so && \ + cargo build-sbf --manifest-path program/Cargo.toml --features govertest && cp target/deploy/evm_loader.so target/deploy/evm_loader-govertest.so && \ + cargo build-sbf --manifest-path program/Cargo.toml --features govertest,emergency && cp target/deploy/evm_loader.so target/deploy/evm_loader-govertest-emergency.so && \ + cargo build-sbf --manifest-path program/Cargo.toml --features mainnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-mainnet.so && \ + cargo build-sbf --manifest-path program/Cargo.toml --features mainnet,emergency && cp target/deploy/evm_loader.so target/deploy/evm_loader-mainnet-emergency.so && \ + cargo build-sbf --manifest-path program/Cargo.toml --features rollup && cp target/deploy/evm_loader.so target/deploy/evm_loader-rollup.so && \ + cargo build-sbf --manifest-path program/Cargo.toml --features ci --dump # Add neon_test_invoke_program to the genesis diff --git a/ci/solana-run-neon.sh b/ci/solana-run-neon.sh index b7b35527b..78033faf5 100755 --- a/ci/solana-run-neon.sh +++ b/ci/solana-run-neon.sh @@ -20,6 +20,7 @@ VALIDATOR_ARGS=( --ticks-per-slot 16 --upgradeable-program ${EVM_LOADER} ${EVM_LOADER_PATH} ${EVM_LOADER_AUTHORITY_KEYPAIR} --bpf-program ${METAPLEX} ${METAPLEX_PATH} + --limit-ledger-size 400000000 ) LIST_OF_TEST_PROGRAMS=("test_invoke_program" "counter" "cross_program_invocation" "transfer_sol" "transfer_tokens") diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index dc608d595..7b7ff925e 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -62,11 +62,11 @@ dependencies = [ [[package]] name = "actix-codec" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8" +checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "bytes", "futures-core", "futures-sink", @@ -79,18 +79,18 @@ dependencies = [ [[package]] name = "actix-http" -version = "3.7.0" +version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb9843d84c775696c37d9a418bbb01b932629d01870722c0f13eb3f95e2536d" +checksum = "3ae682f693a9cd7b058f2b0b5d9a6d7728a8555779bedbbc35dd88528611d020" dependencies = [ "actix-codec", "actix-rt", "actix-service", "actix-utils", - "ahash 0.8.5", + "ahash 0.8.11", "base64 0.22.1", - "bitflags 2.4.0", - "brotli 6.0.0", + "bitflags 2.6.0", + "brotli", "bytes", "bytestring", "derive_more", @@ -98,7 +98,7 @@ dependencies = [ "flate2", "futures-core", "h2", - "http", + "http 0.2.12", "httparse", "httpdate", "itoa", @@ -113,7 +113,7 @@ dependencies = [ "tokio", "tokio-util", "tracing", - "zstd 0.13.0", + "zstd 0.13.2", ] [[package]] @@ -123,7 +123,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -145,7 +145,7 @@ checksum = "13d324164c51f63867b57e73ba5936ea151b8a41a1d23d1031eeb9f70d0236f8" dependencies = [ "bytestring", "cfg-if", - "http", + "http 0.2.12", "regex", "regex-lite", "serde", @@ -154,9 +154,9 @@ dependencies = [ [[package]] name = "actix-rt" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28f32d40287d3f402ae0028a9d54bef51af15c8769492826a69d28f81893151d" +checksum = "24eda4e2a6e042aa4e55ac438a2ae052d3b5da0ecf83d7411e1a368946925208" dependencies = [ "futures-core", "tokio", @@ -164,9 +164,9 @@ dependencies = [ [[package]] name = "actix-server" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eb13e7eef0423ea6eab0e59f6c72e7cb46d33691ad56a726b3cd07ddec2c2d4" +checksum = "b02303ce8d4e8be5b855af6cf3c3a08f3eff26880faad82bab679c22d3650cb5" dependencies = [ "actix-rt", "actix-service", @@ -174,7 +174,7 @@ dependencies = [ "futures-core", "futures-util", "mio", - "socket2 0.5.4", + "socket2", "tokio", "tracing", ] @@ -215,7 +215,7 @@ dependencies = [ "actix-service", "actix-utils", "actix-web-codegen", - "ahash 0.8.5", + "ahash 0.8.11", "bytes", "bytestring", "cfg-if", @@ -236,7 +236,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "smallvec", - "socket2 0.5.4", + "socket2", "time", "url", ] @@ -250,14 +250,14 @@ dependencies = [ "actix-router", "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] name = "addr2line" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "gimli", ] @@ -306,23 +306,23 @@ dependencies = [ [[package]] name = "ahash" -version = "0.7.6" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom 0.2.12", + "getrandom 0.2.15", "once_cell", "version_check", ] [[package]] name = "ahash" -version = "0.8.5" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7d5a2cecb58716e47d67d5703a249964b14c7be1ec3cad3affc295b2d1c35d" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom 0.2.12", + "getrandom 0.2.15", "once_cell", "version_check", "zerocopy", @@ -330,9 +330,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.1" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -388,6 +388,20 @@ version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +[[package]] +name = "aquamarine" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1da02abba9f9063d786eab1509833ebb2fac0f966862ca59439c76b9c566760" +dependencies = [ + "include_dir", + "itertools 0.10.5", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "ark-bn254" version = "0.4.0" @@ -429,7 +443,7 @@ dependencies = [ "derivative", "digest 0.10.7", "itertools 0.10.5", - "num-bigint 0.4.4", + "num-bigint 0.4.6", "num-traits", "paste", "rustc_version", @@ -452,7 +466,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" dependencies = [ - "num-bigint 0.4.4", + "num-bigint 0.4.6", "num-traits", "proc-macro2", "quote", @@ -481,7 +495,7 @@ dependencies = [ "ark-serialize-derive", "ark-std", "digest 0.10.7", - "num-bigint 0.4.4", + "num-bigint 0.4.6", ] [[package]] @@ -507,9 +521,9 @@ dependencies = [ [[package]] name = "arrayref" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" +checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" [[package]] name = "arrayvec" @@ -593,11 +607,11 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.2" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d495b6dc0184693324491a5ac05f559acc97bf937ab31d7a1c33dd0016be6d2b" +checksum = "fec134f64e2bc57411226dfc4e52dec859ddfc7e711fc5e07b612584f000e4aa" dependencies = [ - "brotli 3.3.4", + "brotli", "flate2", "futures-core", "memchr", @@ -634,13 +648,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.80" +version = "0.1.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -656,15 +670,15 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" dependencies = [ "addr2line", "cc", @@ -731,9 +745,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" dependencies = [ "serde", ] @@ -818,6 +832,16 @@ dependencies = [ "hashbrown 0.13.2", ] +[[package]] +name = "borsh" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed" +dependencies = [ + "borsh-derive 1.5.1", + "cfg_aliases 0.2.1", +] + [[package]] name = "borsh-derive" version = "0.9.3" @@ -844,6 +868,20 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "borsh-derive" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b" +dependencies = [ + "once_cell", + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.72", + "syn_derive", +] + [[package]] name = "borsh-derive-internal" version = "0.9.3" @@ -888,17 +926,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "brotli" -version = "3.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor 2.3.4", -] - [[package]] name = "brotli" version = "6.0.0" @@ -907,24 +934,14 @@ checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", - "brotli-decompressor 4.0.0", + "brotli-decompressor", ] [[package]] name = "brotli-decompressor" -version = "2.3.4" +version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", -] - -[[package]] -name = "brotli-decompressor" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6221fe77a248b9117d431ad93761222e1cf8ff282d9d1d5d9f53d6299a1cf76" +checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -947,9 +964,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.4.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d4260bcc2e8fc9df1eac4919a720effeb63a3f0952f5bf4944adfa18897f09" +checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" dependencies = [ "memchr", ] @@ -982,7 +999,7 @@ dependencies = [ "pretty_assertions", "rustc_version", "serde_json", - "zstd 0.13.0", + "zstd 0.13.2", ] [[package]] @@ -1008,21 +1025,21 @@ dependencies = [ "bincode", "build-info-common", "chrono", - "num-bigint 0.4.4", + "num-bigint 0.4.6", "num-traits", "proc-macro-error", "proc-macro2", "quote", "serde_json", - "syn 2.0.71", - "zstd 0.13.0", + "syn 2.0.72", + "zstd 0.13.2", ] [[package]] name = "bumpalo" -version = "3.12.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bv" @@ -1042,35 +1059,35 @@ checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" [[package]] name = "bytemuck" -version = "1.14.3" +version = "1.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2ef034f05691a48569bd920a96c81b9d91bbad1ab5ac7c4616c1f6ef36cb79f" +checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.4.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192" +checksum = "1ee891b04274a59bd38b412188e24b849617b2e45a0fd8d057deb63e7403761b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952" [[package]] name = "bytestring" @@ -1104,9 +1121,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" dependencies = [ "serde", ] @@ -1123,9 +1140,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.4" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12024c4645c97566567129c204f65d5815a8c9aecf30fcbe682b2fe034996d36" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" dependencies = [ "serde", ] @@ -1155,9 +1172,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.83" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f" dependencies = [ "jobserver", "libc", @@ -1169,11 +1186,23 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chrono" -version = "0.4.34" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", @@ -1181,7 +1210,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.52.3", + "windows-targets 0.52.6", ] [[package]] @@ -1210,9 +1239,9 @@ dependencies = [ [[package]] name = "clap" -version = "3.2.23" +version = "3.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" dependencies = [ "atty", "bitflags 1.3.2", @@ -1221,7 +1250,7 @@ dependencies = [ "once_cell", "strsim 0.10.0", "termcolor", - "textwrap 0.16.0", + "textwrap 0.16.1", ] [[package]] @@ -1235,17 +1264,19 @@ dependencies = [ [[package]] name = "clickhouse" -version = "0.11.6" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0875e527e299fc5f4faba42870bf199a39ab0bb2dbba1b8aef0a2151451130f" +checksum = "eab6d70c534d5e54680aae99712800fca8d048cdfad3fbd154daf823d444f08b" dependencies = [ "bstr", "bytes", "clickhouse-derive", "clickhouse-rs-cityhash-sys", "futures", - "hyper", - "hyper-tls", + "futures-channel", + "http-body-util", + "hyper 1.4.1", + "hyper-util", "lz4", "sealed", "serde", @@ -1257,14 +1288,14 @@ dependencies = [ [[package]] name = "clickhouse-derive" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18af5425854858c507eec70f7deb4d5d8cec4216fcb086283a78872387281ea5" +checksum = "d70f3e2893f7d3e017eeacdc9a708fbc29a10488e3ebca21f9df6a5d2b616dbb" dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 1.0.109", + "syn 2.0.72", ] [[package]] @@ -1276,16 +1307,6 @@ dependencies = [ "cc", ] -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - [[package]] name = "combine" version = "3.8.1" @@ -1301,24 +1322,24 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "2.2.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ "crossbeam-utils", ] [[package]] name = "console" -version = "0.15.7" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" dependencies = [ "encode_unicode", "lazy_static", "libc", "unicode-width", - "windows-sys 0.45.0", + "windows-sys 0.52.0", ] [[package]] @@ -1398,9 +1419,9 @@ dependencies = [ [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -1408,9 +1429,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "core_extensions" @@ -1429,18 +1450,18 @@ checksum = "69f3b219d28b6e3b4ac87bc1fc522e0803ab22e055da177bff0068c4150c61a6" [[package]] name = "cpufeatures" -version = "0.2.6" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "280a9f2d8b3a38871a3c8a46fb80db65e5e5ed97da80c4d08bf27fb63e35e181" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] @@ -1460,46 +1481,37 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.8" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" dependencies = [ - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.14" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "autocfg", - "cfg-if", "crossbeam-utils", - "memoffset 0.8.0", - "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.15" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" -dependencies = [ - "cfg-if", -] +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -1538,12 +1550,12 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.4.1" +version = "3.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e95fbd621905b854affdc67943b043a0fbb6ed7385fd5a25650d19a8a6cfdf" +checksum = "672465ae37dc1bc6380a6547a8883d5dd397b0f1faaad4f265726cc7042a5345" dependencies = [ - "nix 0.27.1", - "windows-sys 0.48.0", + "nix 0.28.0", + "windows-sys 0.52.0", ] [[package]] @@ -1560,55 +1572,11 @@ dependencies = [ "zeroize", ] -[[package]] -name = "cxx" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn 2.0.71", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.71", -] - [[package]] name = "darling" -version = "0.20.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" dependencies = [ "darling_core", "darling_macro", @@ -1616,45 +1584,48 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", - "strsim 0.10.0", - "syn 2.0.71", + "strsim 0.11.1", + "syn 2.0.72", ] [[package]] name = "darling_macro" -version = "0.20.3" +version = "0.20.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] name = "dashmap" -version = "4.0.2" +version = "5.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", - "num_cpus", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", "rayon", ] [[package]] name = "data-encoding" -version = "2.3.3" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "der" @@ -1674,7 +1645,7 @@ dependencies = [ "asn1-rs", "displaydoc", "nom", - "num-bigint 0.4.4", + "num-bigint 0.4.6", "num-traits", "rusticata-macros", ] @@ -1708,15 +1679,15 @@ dependencies = [ [[package]] name = "derive_more" -version = "0.99.17" +version = "0.99.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ "convert_case", "proc-macro2", "quote", "rustc_version", - "syn 1.0.109", + "syn 2.0.72", ] [[package]] @@ -1737,6 +1708,12 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +[[package]] +name = "difflib" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" + [[package]] name = "digest" version = "0.9.0" @@ -1759,9 +1736,9 @@ dependencies = [ [[package]] name = "dir-diff" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2860407d7d7e2e004bb2128510ad9e8d669e76fa005ccf567977b5d71b8b4a0b" +checksum = "a7ad16bf5f84253b50d6557681c58c3ab67c47c77d39fed9aeb56e947290bd10" dependencies = [ "walkdir", ] @@ -1789,13 +1766,13 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.72", ] [[package]] @@ -1818,9 +1795,15 @@ checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] +[[package]] +name = "downcast" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" + [[package]] name = "eager" version = "0.1.0" @@ -1864,9 +1847,9 @@ dependencies = [ [[package]] name = "either" -version = "1.10.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "elsa" @@ -1885,31 +1868,31 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.32" +version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" dependencies = [ "cfg-if", ] [[package]] name = "enum-iterator" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7add3873b5dd076766ee79c8e406ad1a472c385476b9e38849f8eec24f1be689" +checksum = "9fd242f399be1da0a5354aa462d57b4ab2b4ee0683cc552f7c007d2d12d36e94" dependencies = [ "enum-iterator-derive", ] [[package]] name = "enum-iterator-derive" -version = "1.2.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eecf8589574ce9b895052fa12d69af7a233f99e6107f5cb8dd1044f2a17bfdcb" +checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -1921,7 +1904,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -1954,9 +1937,9 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys 0.52.0", @@ -1974,7 +1957,7 @@ dependencies = [ "regex", "serde", "serde_json", - "sha3 0.10.7", + "sha3 0.10.8", "thiserror", "uint", ] @@ -2060,8 +2043,8 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.71", - "toml 0.8.2", + "syn 2.0.72", + "toml 0.8.15", ] [[package]] @@ -2075,9 +2058,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "feature-probe" @@ -2096,14 +2079,14 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.22" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.3.5", - "windows-sys 0.48.0", + "redox_syscall 0.4.1", + "windows-sys 0.52.0", ] [[package]] @@ -2120,14 +2103,23 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.27" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" dependencies = [ "crc32fast", "miniz_oxide", ] +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +dependencies = [ + "num-traits", +] + [[package]] name = "fnv" version = "1.0.7" @@ -2159,13 +2151,10 @@ dependencies = [ ] [[package]] -name = "fs-err" -version = "2.11.0" +name = "fragile" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" -dependencies = [ - "autocfg", -] +checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "fuchsia-cprng" @@ -2181,9 +2170,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", @@ -2196,9 +2185,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", @@ -2206,15 +2195,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", @@ -2223,44 +2212,44 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-timer" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-channel", "futures-core", @@ -2328,9 +2317,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "js-sys", @@ -2341,9 +2330,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "git2" @@ -2351,7 +2340,7 @@ version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b903b73e45dc0c6c596f2d37eccece7c1c8bb6e4407b001096387c63d0d93724" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.6.0", "libc", "libgit2-sys", "log", @@ -2372,18 +2361,18 @@ checksum = "a7666983ed0dd8d21a6f6576ee00053ca0926fb281a5522577a4dbd0f1b54143" dependencies = [ "log", "plain", - "scroll", + "scroll 0.11.0", ] [[package]] name = "goblin" -version = "0.6.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6b4de4a8eb6c46a8c77e1d3be942cb9a8bf073c22374578e5ba4b08ed0ff68" +checksum = "1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47" dependencies = [ "log", "plain", - "scroll", + "scroll 0.12.0", ] [[package]] @@ -2397,8 +2386,8 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", - "indexmap 2.2.3", + "http 0.2.12", + "indexmap 2.2.6", "slab", "tokio", "tokio-util", @@ -2420,7 +2409,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" dependencies = [ - "ahash 0.7.6", + "ahash 0.7.8", ] [[package]] @@ -2429,7 +2418,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash 0.7.6", + "ahash 0.7.8", ] [[package]] @@ -2438,14 +2427,14 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash 0.8.5", + "ahash 0.8.11", ] [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "headers" @@ -2456,7 +2445,7 @@ dependencies = [ "base64 0.21.7", "bytes", "headers-core", - "http", + "http 0.2.12", "httpdate", "mime", "sha1", @@ -2468,16 +2457,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" dependencies = [ - "http", -] - -[[package]] -name = "heck" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", + "http 0.2.12", ] [[package]] @@ -2503,9 +2483,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.1" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hex" @@ -2524,14 +2504,15 @@ checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" [[package]] name = "hidapi" -version = "2.4.1" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "723777263b0dcc5730aec947496bd8c3940ba63c15f5633b288cc615f4f6af79" +checksum = "9e58251020fe88fe0dae5ebcc1be92b4995214af84725b375d08354d0311c23c" dependencies = [ "cc", + "cfg-if", "libc", "pkg-config", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -2572,9 +2553,20 @@ dependencies = [ [[package]] name = "http" -version = "0.2.9" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" dependencies = [ "bytes", "fnv", @@ -2583,26 +2575,49 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.1.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", "pin-project-lite", ] [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "humantime" @@ -2612,37 +2627,56 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.27" +version = "0.14.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" dependencies = [ "bytes", "futures-channel", "futures-core", "futures-util", "h2", - "http", - "http-body", + "http 0.2.12", + "http-body 0.4.6", "httparse", "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.9", + "socket2", "tokio", "tower-service", "tracing", "want", ] +[[package]] +name = "hyper" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + [[package]] name = "hyper-rustls" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ "futures-util", - "http", - "hyper", + "http 0.2.12", + "hyper 0.14.30", "log", "rustls", "rustls-native-certs", @@ -2657,34 +2691,53 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper", + "hyper 0.14.30", "native-tls", "tokio", "tokio-native-tls", ] +[[package]] +name = "hyper-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "hyper 1.4.1", + "pin-project-lite", + "socket2", + "tokio", + "tower", + "tower-service", + "tracing", +] + [[package]] name = "iana-time-zone" -version = "0.1.56" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows", + "windows-core", ] [[package]] name = "iana-time-zone-haiku" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ - "cxx", - "cxx-build", + "cc", ] [[package]] @@ -2767,11 +2820,30 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "include_dir" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd" +dependencies = [ + "include_dir_macros", +] + +[[package]] +name = "include_dir_macros" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "index_list" -version = "0.2.7" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9d968042a4902e08810946fc7cd5851eb75e80301342305af755ca06cb82ce" +checksum = "2cb725b6505e51229de32027e0cfcd9db29da4d89156f9747b0a5195643fa3e1" [[package]] name = "indexmap" @@ -2786,12 +2858,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.3" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "serde", ] @@ -2810,18 +2882,18 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ "cfg-if", ] [[package]] name = "ipnet" -version = "2.7.2" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "itertools" @@ -2843,24 +2915,24 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jobserver" -version = "0.1.26" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -2919,7 +2991,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b005c793122d03217da09af68ba9383363caa950b90d3436106df8cabce935" dependencies = [ "futures-util", - "http", + "http 0.2.12", "jsonrpsee-core 0.20.3", "pin-project", "rustls-native-certs", @@ -2944,7 +3016,7 @@ dependencies = [ "beef", "futures-timer", "futures-util", - "hyper", + "hyper 0.14.30", "jsonrpsee-types 0.20.3", "parking_lot", "rand 0.8.5", @@ -2959,16 +3031,16 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.22.3" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71962a1c49af43adf81d337e4ebc93f3c915faf6eccaa14d74e255107dfd7723" +checksum = "b4b257e1ec385e07b0255dde0b933f948b5c8b8c28d42afda9587c3a967b896d" dependencies = [ "anyhow", "async-trait", "beef", "futures-util", - "hyper", - "jsonrpsee-types 0.22.3", + "hyper 0.14.30", + "jsonrpsee-types 0.22.5", "serde", "serde_json", "thiserror", @@ -2978,15 +3050,15 @@ dependencies = [ [[package]] name = "jsonrpsee-http-client" -version = "0.22.3" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c13987da51270bda2c1c9b40c19be0fe9b225c7a0553963d8f17e683a50ce84" +checksum = "1ccf93fc4a0bfe05d851d37d7c32b7f370fe94336b52a2f0efc5f1981895c2e5" dependencies = [ "async-trait", - "hyper", + "hyper 0.14.30", "hyper-rustls", - "jsonrpsee-core 0.22.3", - "jsonrpsee-types 0.22.3", + "jsonrpsee-core 0.22.5", + "jsonrpsee-types 0.22.5", "serde", "serde_json", "thiserror", @@ -3016,8 +3088,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82c39a00449c9ef3f50b84fc00fc4acba20ef8f559f07902244abf4c15c5ab9c" dependencies = [ "futures-util", - "http", - "hyper", + "http 0.2.12", + "hyper 0.14.30", "jsonrpsee-core 0.20.3", "jsonrpsee-types 0.20.3", "route-recognizer", @@ -3048,9 +3120,9 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.22.3" +version = "0.22.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e53c72de6cd2ad6ac1aa6e848206ef8b736f92ed02354959130373dfa5b3cbd" +checksum = "150d6168405890a7a3231a3c74843f58b8959471f6df76078db2619ddee1d07d" dependencies = [ "anyhow", "beef", @@ -3065,7 +3137,7 @@ version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bca9cb3933ccae417eb6b08c3448eb1cb46e39834e5b503e395e5e5bd08546c0" dependencies = [ - "http", + "http 0.2.12", "jsonrpsee-client-transport", "jsonrpsee-core 0.20.3", "jsonrpsee-types 0.20.3", @@ -3074,9 +3146,9 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3afef3b6eff9ce9d8ff9b3601125eec7f0c8cbac7abd14f355d053fa56c98768" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" dependencies = [ "cpufeatures", ] @@ -3095,9 +3167,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libgit2-sys" @@ -3121,6 +3193,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.6.0", + "libc", +] + [[package]] name = "libsecp256k1" version = "0.6.0" @@ -3171,9 +3253,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.12" +version = "1.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97137b25e321a73eef1418d1d5d2eda4d77e12813f8e6dead84bc52c5870a7b" +checksum = "c15da26e5af7e25c90b37a2d75cdbf940cf4a55316de9d84c679c9b8bfabf82e" dependencies = [ "cc", "libc", @@ -3189,19 +3271,10 @@ checksum = "3c9a85a9752c549ceb7578064b4ed891179d20acd85f27318573b64d2d7ee7ee" dependencies = [ "ark-bn254", "ark-ff", - "num-bigint 0.4.4", + "num-bigint 0.4.6", "thiserror", ] -[[package]] -name = "link-cplusplus" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" -dependencies = [ - "cc", -] - [[package]] name = "linked_list_allocator" version = "0.10.5" @@ -3210,9 +3283,9 @@ checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286" [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "local-channel" @@ -3233,9 +3306,9 @@ checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -3258,9 +3331,9 @@ dependencies = [ [[package]] name = "lz4" -version = "1.24.0" +version = "1.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e9e2dd86df36ce760a60f6ff6ad526f7ba1f14ba0356f8254fb6905e6494df1" +checksum = "958b4caa893816eea05507c20cfe47574a43d9a697138a7872990bba8a0ece68" dependencies = [ "libc", "lz4-sys", @@ -3268,9 +3341,9 @@ dependencies = [ [[package]] name = "lz4-sys" -version = "1.9.4" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d27b317e207b10f69f5e75494119e391a96f48861ae870d1da6edac98ca900" +checksum = "109de74d5d2353660401699a4174a4ff23fcc649caf553df71933c7fb45ad868" dependencies = [ "cc", "libc", @@ -3293,14 +3366,14 @@ checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" @@ -3322,18 +3395,9 @@ dependencies = [ [[package]] name = "memoffset" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" -dependencies = [ - "autocfg", -] - -[[package]] -name = "memoffset" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" dependencies = [ "autocfg", ] @@ -3364,9 +3428,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", ] @@ -3383,6 +3447,33 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "mockall" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c84490118f2ee2d74570d114f3d0493cbf02790df303d2707606c3e14e07c96" +dependencies = [ + "cfg-if", + "downcast", + "fragile", + "lazy_static", + "mockall_derive", + "predicates", + "predicates-tree", +] + +[[package]] +name = "mockall_derive" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "modular-bitfield" version = "0.11.2" @@ -3406,9 +3497,9 @@ dependencies = [ [[package]] name = "mpl-token-metadata" -version = "4.1.1" +version = "4.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b2de608098eb2ef2a5392069dea83084967e25a4d69d0380a6bb02454fc0fe" +checksum = "caf0f61b553e424a6234af1268456972ee66c2222e1da89079242251fa7479e5" dependencies = [ "borsh 0.10.3", "num-derive 0.3.3", @@ -3419,11 +3510,10 @@ dependencies = [ [[package]] name = "native-tls" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" dependencies = [ - "lazy_static", "libc", "log", "openssl", @@ -3500,27 +3590,30 @@ dependencies = [ "enum_dispatch", "ethnum", "evm-loader", - "goblin 0.6.1", + "goblin 0.8.2", "hex", "hex-literal", - "hyper", + "hyper 0.14.30", "jsonrpsee", "lazy_static", "log", "neon-lib-interface", "rand 0.8.5", - "scroll", + "scroll 0.12.0", "serde", "serde_json", - "serde_with 3.8.3", + "serde_with 3.9.0", "solana-account-decoder", "solana-accounts-db", + "solana-bpf-loader-program", "solana-cli", "solana-cli-config", "solana-client", + "solana-loader-v4-program", "solana-program-runtime", "solana-runtime", "solana-sdk", + "solana-transaction-status", "spl-associated-token-account", "spl-token", "strum 0.26.3", @@ -3571,9 +3664,9 @@ dependencies = [ "async-trait", "build-info", "build-info-build", - "jsonrpsee-core 0.22.3", + "jsonrpsee-core 0.22.5", "jsonrpsee-http-client", - "jsonrpsee-types 0.22.3", + "jsonrpsee-types 0.22.5", "neon-lib", "serde", "serde_json", @@ -3596,12 +3689,13 @@ dependencies = [ [[package]] name = "nix" -version = "0.27.1" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.6.0", "cfg-if", + "cfg_aliases 0.1.1", "libc", ] @@ -3615,6 +3709,12 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "normalize-line-endings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -3652,11 +3752,10 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ - "autocfg", "num-integer", "num-traits", ] @@ -3690,30 +3789,29 @@ dependencies = [ [[package]] name = "num-derive" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfb77679af88f8b125209d354a202862602672222e7f2313fdd6dc349bad4712" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-iter" -version = "0.1.43" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ "autocfg", "num-integer", @@ -3734,9 +3832,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] @@ -3747,7 +3845,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.1", + "hermit-abi 0.3.9", "libc", ] @@ -3762,11 +3860,11 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683751d591e6d81200c39fb0d1032608b77724f34114db54f571ff1317b337c0" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" dependencies = [ - "num_enum_derive 0.7.1", + "num_enum_derive 0.7.2", ] [[package]] @@ -3778,19 +3876,19 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] name = "num_enum_derive" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c11e44798ad209ccdd91fc192f0526a369a01234f7373e1b141c96d7cee4f0e" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" dependencies = [ - "proc-macro-crate 1.3.1", + "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -3801,9 +3899,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "object" -version = "0.32.2" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" dependencies = [ "memchr", ] @@ -3825,17 +3923,17 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opaque-debug" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.64" +version = "0.10.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" +checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.6.0", "cfg-if", "foreign-types", "libc", @@ -3852,7 +3950,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -3863,9 +3961,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.101" +version = "0.9.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff" +checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" dependencies = [ "cc", "libc", @@ -3875,9 +3973,9 @@ dependencies = [ [[package]] name = "os_str_bytes" -version = "6.5.0" +version = "6.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" [[package]] name = "ouroboros" @@ -3910,9 +4008,9 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "parity-scale-codec" -version = "3.6.4" +version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8e946cc0cc711189c0b0249fb8b599cbeeab9784d83c415719368bb8d4ac64" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" dependencies = [ "arrayvec", "bitvec", @@ -3924,11 +4022,11 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.6.4" +version = "3.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a296c3079b5fefbc499e1de58dc26c09b1b9a5952d26694ee89f04a43ebbb3e" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" dependencies = [ - "proc-macro-crate 1.3.1", + "proc-macro-crate 3.1.0", "proc-macro2", "quote", "syn 1.0.109", @@ -3936,9 +4034,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -3946,22 +4044,22 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.7" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.2.16", + "redox_syscall 0.5.3", "smallvec", - "windows-sys 0.45.0", + "windows-targets 0.52.6", ] [[package]] name = "paste" -version = "1.0.12" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pbkdf2" @@ -4007,29 +4105,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.3" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.3" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -4050,9 +4148,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.26" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "plain" @@ -4074,9 +4172,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.4.3" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31114a898e107c51bb1609ffaf55a0e011cf6a4d7f1170d0015a165082c0338b" +checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" [[package]] name = "powerfmt" @@ -4090,6 +4188,36 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "predicates" +version = "2.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd" +dependencies = [ + "difflib", + "float-cmp", + "itertools 0.10.5", + "normalize-line-endings", + "predicates-core", + "regex", +] + +[[package]] +name = "predicates-core" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" + +[[package]] +name = "predicates-tree" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +dependencies = [ + "predicates-core", + "termtree", +] + [[package]] name = "pretty-hex" version = "0.3.0" @@ -4135,7 +4263,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ "once_cell", - "toml_edit 0.19.8", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit 0.21.1", ] [[package]] @@ -4188,7 +4325,7 @@ checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -4234,7 +4371,7 @@ checksum = "055b4e778e8feb9f93c4e439f71dc2156ef13360b432b799e179a8c4cdf0b1d7" dependencies = [ "bytes", "libc", - "socket2 0.5.4", + "socket2", "tracing", "windows-sys 0.48.0", ] @@ -4341,7 +4478,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.12", + "getrandom 0.2.15", ] [[package]] @@ -4364,9 +4501,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.7.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", @@ -4374,14 +4511,12 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.11.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ - "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "num_cpus", ] [[package]] @@ -4407,43 +4542,43 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.16" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "redox_syscall" -version = "0.3.5" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", ] [[package]] name = "redox_users" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ - "getrandom 0.2.12", - "redox_syscall 0.2.16", + "getrandom 0.2.15", + "libredox", "thiserror", ] [[package]] name = "regex" -version = "1.10.3" +version = "1.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.5", - "regex-syntax 0.8.2", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", ] [[package]] @@ -4457,20 +4592,20 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.5" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.2", + "regex-syntax 0.8.4", ] [[package]] name = "regex-lite" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b661b2f27137bdbc16f00eda72866a92bb28af1753ffbd56744fb6e2e9cd8e" +checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" [[package]] name = "regex-syntax" @@ -4480,9 +4615,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "repr_offset" @@ -4495,9 +4630,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.20" +version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ "async-compression", "base64 0.21.7", @@ -4506,9 +4641,9 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", - "http-body", - "hyper", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.30", "hyper-rustls", "hyper-tls", "ipnet", @@ -4524,6 +4659,8 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", + "sync_wrapper", + "system-configuration", "tokio", "tokio-native-tls", "tokio-rustls", @@ -4533,7 +4670,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 0.25.2", + "webpki-roots 0.25.4", "winreg", ] @@ -4560,7 +4697,7 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.12", + "getrandom 0.2.15", "libc", "spin 0.9.8", "untrusted 0.9.0", @@ -4594,30 +4731,30 @@ checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" [[package]] name = "rpassword" -version = "7.2.0" +version = "7.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6678cf63ab3491898c0d021b493c94c9b221d91295294a2a5746eacbe5928322" +checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f" dependencies = [ "libc", "rtoolbox", - "winapi", + "windows-sys 0.48.0", ] [[package]] name = "rtoolbox" -version = "0.0.1" +version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "034e22c514f5c0cb8a10ff341b9b048b5ceb21591f31c8f44c43b960f9b3524a" +checksum = "c247d24e63230cdb56463ae328478bd5eac8b8faa8c69461a77e8e323afac90e" dependencies = [ "libc", - "winapi", + "windows-sys 0.48.0", ] [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" @@ -4651,11 +4788,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.31" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", @@ -4676,9 +4813,9 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" dependencies = [ "openssl-probe", "rustls-pemfile", @@ -4688,9 +4825,9 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ "base64 0.21.7", ] @@ -4707,15 +4844,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.14" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" @@ -4728,11 +4865,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.21" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" dependencies = [ - "windows-sys 0.42.0", + "windows-sys 0.52.0", ] [[package]] @@ -4742,51 +4879,65 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] -name = "scratch" -version = "1.0.5" +name = "scroll" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" +checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" +dependencies = [ + "scroll_derive 0.11.1", +] [[package]] name = "scroll" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" +checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6" dependencies = [ - "scroll_derive", + "scroll_derive 0.12.0", ] [[package]] name = "scroll_derive" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdbda6ac5cd1321e724fa9cee216f3a61885889b896f073b8f82322789c5250e" +checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.72", +] + +[[package]] +name = "scroll_derive" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", ] [[package]] name = "sct" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring 0.16.20", - "untrusted 0.7.1", + "ring 0.17.8", + "untrusted 0.9.0", ] [[package]] name = "sealed" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b5e421024b5e5edfbaa8e60ecf90bda9dbffc602dbb230e6028763f85f0c68c" +checksum = "f4a8caec23b7800fb97971a1c6ae365b6239aaeddfb934d6265f8505e795699d" dependencies = [ - "heck 0.3.3", + "heck 0.4.1", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.72", ] [[package]] @@ -4809,11 +4960,11 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.8.2" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "core-foundation", "core-foundation-sys", "libc", @@ -4822,9 +4973,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.8.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" +checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" dependencies = [ "core-foundation-sys", "libc", @@ -4839,6 +4990,15 @@ dependencies = [ "serde", ] +[[package]] +name = "seqlock" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5c67b6f14ecc5b86c66fa63d76b5092352678545a8a3cdae80aef5128371910" +dependencies = [ + "parking_lot", +] + [[package]] name = "serde" version = "1.0.204" @@ -4865,18 +5025,18 @@ checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] name = "serde_derive_internals" -version = "0.26.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.72", ] [[package]] @@ -4885,7 +5045,7 @@ version = "1.0.120" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" dependencies = [ - "indexmap 2.2.3", + "indexmap 2.2.6", "itoa", "ryu", "serde", @@ -4893,9 +5053,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.3" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" dependencies = [ "serde", ] @@ -4924,19 +5084,19 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.8.3" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e73139bc5ec2d45e6c5fd85be5a46949c1c39a4c18e56915f5eb4c12f975e377" +checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.2.3", + "indexmap 2.2.6", "serde", "serde_derive", "serde_json", - "serde_with_macros 3.8.3", + "serde_with_macros 3.9.0", "time", ] @@ -4949,28 +5109,28 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] name = "serde_with_macros" -version = "3.8.3" +version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b80d3d6b56b64335c0180e5ffde23b3c5e08c14c585b51a15bd0e95393f46703" +checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] name = "serde_yaml" -version = "0.9.25" +version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a49e178e4452f45cb61d0cd8cebc1b0fafd3e41929e996cef79aa3aca91f574" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.2.3", + "indexmap 2.2.6", "itoa", "ryu", "serde", @@ -5039,9 +5199,9 @@ dependencies = [ [[package]] name = "sha3" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54c2bb1a323307527314a36bfb73f24febb08ce2b8a554bf4ffd6f51ad15198c" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ "digest 0.10.7", "keccak", @@ -5049,9 +5209,9 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] @@ -5064,9 +5224,9 @@ checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" [[package]] name = "signal-hook-registry" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ "libc", ] @@ -5095,9 +5255,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] @@ -5110,22 +5270,12 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "socket2" -version = "0.5.4" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -5137,7 +5287,7 @@ dependencies = [ "base64 0.13.1", "bytes", "futures", - "http", + "http 0.2.12", "httparse", "log", "rand 0.8.5", @@ -5146,9 +5296,9 @@ dependencies = [ [[package]] name = "solana-account-decoder" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a9721ff8b83683cb7dd856079cde8a8010bfd282d482699a867ad50ea9e727e" +checksum = "b4a1297281b114406a9165c6f55ff9f8706f6244545194c7aa837f9b25dee16e" dependencies = [ "Inflector", "base64 0.21.7", @@ -5171,9 +5321,9 @@ dependencies = [ [[package]] name = "solana-accounts-db" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cdae5f9d2562360bd07fde58976f6ff8f7d90c8311bc5a4959edd7ba61ccec4" +checksum = "ff031129c39c32d0176be1e3bb9352dc83c521187058d6c16febfee2aedddca0" dependencies = [ "arrayref", "bincode", @@ -5186,7 +5336,6 @@ dependencies = [ "dashmap", "flate2", "fnv", - "fs-err", "im", "index_list", "itertools 0.10.5", @@ -5195,10 +5344,10 @@ dependencies = [ "lz4", "memmap2", "modular-bitfield", - "num-derive 0.3.3", + "num-derive 0.4.2", "num-traits", "num_cpus", - "num_enum 0.6.1", + "num_enum 0.7.2", "ouroboros", "percentage", "qualifier_attr", @@ -5206,14 +5355,17 @@ dependencies = [ "rayon", "regex", "rustc_version", + "seqlock", "serde", "serde_derive", + "smallvec", "solana-bucket-map", "solana-config-program", "solana-frozen-abi", "solana-frozen-abi-macro", "solana-measure", "solana-metrics", + "solana-nohash-hasher", "solana-program-runtime", "solana-rayon-threadlimit", "solana-sdk", @@ -5230,14 +5382,14 @@ dependencies = [ [[package]] name = "solana-address-lookup-table-program" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c471a3f150762652b5d77f83432b8574738e621fae4885c47132cfe33676d27c" +checksum = "622d95db00595a3dd2abd2ee22c37cf3744ba3df8f531d5c79faa3c155e2814b" dependencies = [ "bincode", "bytemuck", "log", - "num-derive 0.3.3", + "num-derive 0.4.2", "num-traits", "rustc_version", "serde", @@ -5251,9 +5403,9 @@ dependencies = [ [[package]] name = "solana-bpf-loader-program" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a99a75cdd7d4e40b51d8de8125f3d44db3f7735d96f4e3f31ee79d3110a8f4d" +checksum = "9934493a6034c8cf05913ba6812c057f6cd4792ad75c335e8d971adf63ce01c7" dependencies = [ "bincode", "byteorder", @@ -5270,16 +5422,16 @@ dependencies = [ [[package]] name = "solana-bucket-map" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9830a7dbea75c0cbd62a4ca31bcd9b8832fbdb915c949740a44a496630fb5eb6" +checksum = "0da941e0bde672cd33696961450efa2efb8b46322c4f814c1894c9c264122d1b" dependencies = [ "bv", "bytemuck", "log", "memmap2", "modular-bitfield", - "num_enum 0.6.1", + "num_enum 0.7.2", "rand 0.8.5", "solana-measure", "solana-sdk", @@ -5288,9 +5440,9 @@ dependencies = [ [[package]] name = "solana-clap-utils" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4af0fe4584d7692f24e573b17a5245cfc0d99a4e351b0185dfe02baf52f99864" +checksum = "811569ed647c15e97afd142297b0ad14a87149c51e11df740014daa81f297f8b" dependencies = [ "chrono", "clap 2.34.0", @@ -5305,9 +5457,9 @@ dependencies = [ [[package]] name = "solana-cli" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50775240fd486edb16add2664efeda82e4fdb78850ae70b1b2219dcbbf04ef30" +checksum = "d5a9e83ff7d553663d3d68405b425f2701412f60c72820a325ce4d907a834974" dependencies = [ "bincode", "bs58 0.4.0", @@ -5356,9 +5508,9 @@ dependencies = [ [[package]] name = "solana-cli-config" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "914499b160f7562cbec40d5a688a81028760870e35d22b3061596ebe677409a8" +checksum = "3cb4459594cbdbc6f3cd199bbca486f0ef7f1ecf107dce9cffa3f9d69df31dc7" dependencies = [ "dirs-next", "lazy_static", @@ -5372,9 +5524,9 @@ dependencies = [ [[package]] name = "solana-cli-output" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a32a72324bc9a47a0c72af93bba2fb7530cffab019a67eb24b2b22d81c8de1ce" +checksum = "eb454e8df10d664ef0e1137c69af0f2d9fa0de713c1b608656318a76a2f5d3cc" dependencies = [ "Inflector", "base64 0.21.7", @@ -5399,16 +5551,16 @@ dependencies = [ [[package]] name = "solana-client" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "250ffcda91bc30c2adcc290c9b7c796f59884f1043ae3bcf3245f05158c7986c" +checksum = "792ed1869858f35b4359f696771517b4848cd3ff6e2d58155c4bcb292f30166b" dependencies = [ "async-trait", "bincode", "dashmap", "futures", "futures-util", - "indexmap 2.2.3", + "indexmap 2.2.6", "indicatif", "log", "quinn", @@ -5432,9 +5584,9 @@ dependencies = [ [[package]] name = "solana-compute-budget-program" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8703a92306dfdc4760e18db14b2f8b36c9769e5c47f0656bc77355875674e079" +checksum = "3dde13cdf503b7269435ceee5a94f8c42313e9257df00e6c2aa06466345dd3fc" dependencies = [ "solana-program-runtime", "solana-sdk", @@ -5442,9 +5594,9 @@ dependencies = [ [[package]] name = "solana-config-program" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16fd2daba039bad58277ec88143b1fe624f2352d8ccb2a80bba3693de61df440" +checksum = "e6db8509d749ff1396a0b538ade995908361563b4f2c875b09cf096ba4ba0fae" dependencies = [ "bincode", "chrono", @@ -5456,15 +5608,15 @@ dependencies = [ [[package]] name = "solana-connection-cache" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "868e7fb550af97ad6fc283a5628f8ffb6dafd590dc30254163e7c9003f13ceb0" +checksum = "257511b6c2b54c28eae24c5a9b7bab74522439fcd721d09e63092768333ba7b7" dependencies = [ "async-trait", "bincode", "crossbeam-channel", "futures-util", - "indexmap 2.2.3", + "indexmap 2.2.6", "log", "rand 0.8.5", "rayon", @@ -5478,9 +5630,9 @@ dependencies = [ [[package]] name = "solana-cost-model" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3b79a349b86d02948720e4416463d50fd4f828b6a63512e47b497613df0d720" +checksum = "c391b492eb79c24756ee149b19f5504f7a2554612a8d2860fb9701df4e202a8b" dependencies = [ "lazy_static", "log", @@ -5502,9 +5654,9 @@ dependencies = [ [[package]] name = "solana-faucet" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64540db924b65d0ffeeaac031eb1a6a99892333714f740f01a5ef718cff01ef1" +checksum = "fdd43150e893ba19b5cb222cb0539feb232da55b89a1591cda63daf85cf7bd5d" dependencies = [ "bincode", "byteorder", @@ -5526,17 +5678,13 @@ dependencies = [ [[package]] name = "solana-frozen-abi" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219c484f952f006e37a1a2598aebcc4dcfd48478c03fc2ce2d99787a5c78f248" +checksum = "3f498a2b290abca1cf77feacef01b904be725fd46a7aea5ba121cce8c1269dcf" dependencies = [ - "ahash 0.8.5", - "blake3", "block-buffer 0.10.4", "bs58 0.4.0", "bv", - "byteorder", - "cc", "either", "generic-array", "im", @@ -5547,7 +5695,6 @@ dependencies = [ "serde", "serde_bytes", "serde_derive", - "serde_json", "sha2 0.10.8", "solana-frozen-abi-macro", "subtle", @@ -5556,21 +5703,21 @@ dependencies = [ [[package]] name = "solana-frozen-abi-macro" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe4e1dc5fd61ac10c304b3eb8ddb49737b13e975281d623a6083cf5cf0a8616" +checksum = "e4ab48d1be18021f5c13f94671e766699511044f81aab3376313f6a2392f8fab" dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] name = "solana-loader-v4-program" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad035401037e6e7d1dc19c0ae4b613b36632b60443d28716355a4e0041892fa2" +checksum = "6d5e1fcf36f771e210db47d9e4db1e88821d334b313e6fb3c19cf6a987617ffb" dependencies = [ "log", "solana-measure", @@ -5581,9 +5728,9 @@ dependencies = [ [[package]] name = "solana-logger" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64b4f281f2263de6d9cc65680b90b6bd2c93ba7de573db83fc86e2d05ca7ea8c" +checksum = "ed08bcdd54232d2017071a6f5d664b34649ef0110801ac310a01418215f22ff7" dependencies = [ "env_logger", "lazy_static", @@ -5592,9 +5739,9 @@ dependencies = [ [[package]] name = "solana-measure" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a3ed981230b6a3a8aebf9f03424f5c1ff98be75cc7f0ecb153879e8e439aea" +checksum = "5db05e4bba8562a2419cb980301152fc7f60f643065c3aba4b3b5d6e3bd66e45" dependencies = [ "log", "solana-sdk", @@ -5602,9 +5749,9 @@ dependencies = [ [[package]] name = "solana-metrics" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efb65329e6716dc0ce5b1d719d6e0052e7ff1179ab361916f256054d6b846ee1" +checksum = "f7a77735beed78eb221e123e0d46a991dc91db9e199d5c5fdbea22a55149d162" dependencies = [ "crossbeam-channel", "gethostname", @@ -5617,19 +5764,19 @@ dependencies = [ [[package]] name = "solana-net-utils" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8345ffe2bd2a25a02e5dea046bbbf58f81f6b44ee97224474eae1c0ea03b520a" +checksum = "4f76d98286bdb149ce5375c3c7d7301e5d1bf7bf2576789d3fd488cf93d32471" dependencies = [ "bincode", - "clap 3.2.23", + "clap 3.2.25", "crossbeam-channel", "log", "nix 0.26.4", "rand 0.8.5", "serde", "serde_derive", - "socket2 0.5.4", + "socket2", "solana-logger", "solana-sdk", "solana-version", @@ -5637,13 +5784,19 @@ dependencies = [ "url", ] +[[package]] +name = "solana-nohash-hasher" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b8a731ed60e89177c8a7ab05fe0f1511cedd3e70e773f288f9de33a9cfdc21e" + [[package]] name = "solana-perf" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0326bd89c2453bf2a408ff676cff4ed0080bff2a5c6543db5f62423bc23ad6e8" +checksum = "3b0a1b27503716c3f5362c61215d2ccf88a3ecf95fce51b2b59951c38a9ad94c" dependencies = [ - "ahash 0.8.5", + "ahash 0.8.11", "bincode", "bv", "caps", @@ -5668,9 +5821,9 @@ dependencies = [ [[package]] name = "solana-program" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93dc0f422549c23c4464eaa9383f4b09cd92b50dea750731dd3c31d3ee2d310f" +checksum = "d97cec6d3d60ef58168c8b3e97fd88e8903fa059eff6635361427c61c946ec1e" dependencies = [ "ark-bn254", "ark-ec", @@ -5678,10 +5831,11 @@ dependencies = [ "ark-serialize", "base64 0.21.7", "bincode", - "bitflags 2.4.0", + "bitflags 2.6.0", "blake3", "borsh 0.10.3", "borsh 0.9.3", + "borsh 1.5.1", "bs58 0.4.0", "bv", "bytemuck", @@ -5689,7 +5843,7 @@ dependencies = [ "console_error_panic_hook", "console_log", "curve25519-dalek", - "getrandom 0.2.12", + "getrandom 0.2.15", "itertools 0.10.5", "js-sys", "lazy_static", @@ -5697,9 +5851,9 @@ dependencies = [ "libsecp256k1", "light-poseidon", "log", - "memoffset 0.9.0", - "num-bigint 0.4.4", - "num-derive 0.3.3", + "memoffset 0.9.1", + "num-bigint 0.4.6", + "num-derive 0.4.2", "num-traits", "parking_lot", "rand 0.8.5", @@ -5710,7 +5864,7 @@ dependencies = [ "serde_derive", "serde_json", "sha2 0.10.8", - "sha3 0.10.7", + "sha3 0.10.8", "solana-frozen-abi", "solana-frozen-abi-macro", "solana-sdk-macro", @@ -5722,9 +5876,9 @@ dependencies = [ [[package]] name = "solana-program-runtime" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b407440b708ffda97e25b8cb977f72d1bb7466c28ea5f58751613df0af8d576" +checksum = "d4b76599d73401663bc1fde39f9fa5e538bd74451ea4a8d4e3ac14541be0a5de" dependencies = [ "base64 0.21.7", "bincode", @@ -5733,7 +5887,7 @@ dependencies = [ "itertools 0.10.5", "libc", "log", - "num-derive 0.3.3", + "num-derive 0.4.2", "num-traits", "percentage", "rand 0.8.5", @@ -5750,9 +5904,9 @@ dependencies = [ [[package]] name = "solana-pubsub-client" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f82da20e0c0bb39f9123cf61a6e3c76a8e30b0f09e5215decfb7f6b54734f04" +checksum = "09aacbdbeaa5722b2ab1f843673f66c317609741f494a6ef11e2e8928cc7449e" dependencies = [ "crossbeam-channel", "futures-util", @@ -5775,9 +5929,9 @@ dependencies = [ [[package]] name = "solana-quic-client" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8478a6b4f2c2b8fa330d54ff22386a1792498cb6e84ce3893840337a992e47c6" +checksum = "b2eeabd12e1039aa62cad34179fc1f139fca5c7bfeb7683057643bebff3506b0" dependencies = [ "async-mutex", "async-trait", @@ -5802,9 +5956,9 @@ dependencies = [ [[package]] name = "solana-rayon-threadlimit" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df0aac27af8e94f907f6a65305e0a7909800336e7108bd3ce1dc1f3ef011a20" +checksum = "8ad791cc224c84d69498eeeaeadfc5af2cf710ec2719e48b51f2e2b6e67d8163" dependencies = [ "lazy_static", "num_cpus", @@ -5812,15 +5966,15 @@ dependencies = [ [[package]] name = "solana-remote-wallet" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a97d60701d3fe0fde4871c5856da9e52ba733fbcfb030482278c3af4ffa0bf3" +checksum = "fca3c68439865c87d5a01c26dc0dcbcce2d45331adf8f0bf92a7c7d44853fefb" dependencies = [ "console", "dialoguer", "hidapi", "log", - "num-derive 0.3.3", + "num-derive 0.4.2", "num-traits", "parking_lot", "qstring", @@ -5832,9 +5986,9 @@ dependencies = [ [[package]] name = "solana-rpc-client" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b750c49be9dd90981f3c12c8357d0b0c847bf5b8c638c3eff3c09f6ea199393" +checksum = "c1c9bdb88ebcea8b13103019ed0d39b7d4391dc84a0d614dc8ba2e1ca43468e9" dependencies = [ "async-trait", "base64 0.21.7", @@ -5858,9 +6012,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-api" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "314d0f87fc7bab16b1b4674c03d4e92c7008fa181b67210780542c0e6cbfce38" +checksum = "e5bb93738a111d44dfeec6ccdd6a49f0478550a25a60e38badb2bd713599de44" dependencies = [ "base64 0.21.7", "bs58 0.4.0", @@ -5880,9 +6034,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-nonce-utils" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acf79164ae52ee1ee85cd7aeb1bb715a9f3b90678ee00501896d173dbc31731" +checksum = "e066df081489cd10c91648f1e87d2b945fac2fcdfb34a715234a0b079a4c4375" dependencies = [ "clap 2.34.0", "solana-clap-utils", @@ -5893,10 +6047,11 @@ dependencies = [ [[package]] name = "solana-runtime" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3dfd09f3cd529ab56b33a1b389b449ddc31b338f062822c7cc30375a2f234b" +checksum = "4c8e16747198f45ab41f146d1ab1782d83016fb9ed1ce7612b9174018f907bd5" dependencies = [ + "aquamarine", "arrayref", "base64 0.21.7", "bincode", @@ -5910,7 +6065,6 @@ dependencies = [ "dir-diff", "flate2", "fnv", - "fs-err", "im", "index_list", "itertools 0.10.5", @@ -5919,11 +6073,12 @@ dependencies = [ "lru", "lz4", "memmap2", + "mockall", "modular-bitfield", - "num-derive 0.3.3", + "num-derive 0.4.2", "num-traits", "num_cpus", - "num_enum 0.6.1", + "num_enum 0.7.2", "ouroboros", "percentage", "qualifier_attr", @@ -5934,7 +6089,6 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "siphasher", "solana-accounts-db", "solana-address-lookup-table-program", "solana-bpf-loader-program", @@ -5970,15 +6124,15 @@ dependencies = [ [[package]] name = "solana-sdk" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3892ee0e2acdfbeae7315db6c7c56356384631deb943377de5957074bd2dc4d1" +checksum = "1c335bdf35728ea876506babffcfd85fa4dd66af6438f9472afc91b278946909" dependencies = [ "assert_matches", "base64 0.21.7", "bincode", - "bitflags 2.4.0", - "borsh 0.10.3", + "bitflags 2.6.0", + "borsh 1.5.1", "bs58 0.4.0", "bytemuck", "byteorder", @@ -5995,9 +6149,9 @@ dependencies = [ "libsecp256k1", "log", "memmap2", - "num-derive 0.3.3", + "num-derive 0.4.2", "num-traits", - "num_enum 0.6.1", + "num_enum 0.7.2", "pbkdf2 0.11.0", "qstring", "qualifier_attr", @@ -6011,7 +6165,8 @@ dependencies = [ "serde_json", "serde_with 2.3.3", "sha2 0.10.8", - "sha3 0.10.7", + "sha3 0.10.8", + "siphasher", "solana-frozen-abi", "solana-frozen-abi-macro", "solana-logger", @@ -6024,15 +6179,15 @@ dependencies = [ [[package]] name = "solana-sdk-macro" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8019cc997f6c07f09b23dfeb2c45530fa94df2e2fb9d654f3c772c9766a1511f" +checksum = "4ba67050b90454a8638913a7d5775703c0557157def04ddcc8b59c964cda8535" dependencies = [ "bs58 0.4.0", "proc-macro2", "quote", "rustversion", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -6043,9 +6198,9 @@ checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" [[package]] name = "solana-stake-program" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11c21a028ed8abed4a7a52b8410875d799b31b58489653e05ae885e2ba799463" +checksum = "c2ef08f7b2485af8578bfd4e23689286e5360b50d3cc9f350dfe3ad9fdabc679" dependencies = [ "bincode", "log", @@ -6058,16 +6213,16 @@ dependencies = [ [[package]] name = "solana-streamer" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "067d167db6be6f25c21e4c615607757ae7161b20e08197ec2d1a63360e522069" +checksum = "27e8269eaa4aef1a9697fe8b9f659402272746c3fdd374fbffa96f68fe6745a6" dependencies = [ "async-channel", "bytes", "crossbeam-channel", "futures-util", "histogram", - "indexmap 2.2.3", + "indexmap 2.2.6", "itertools 0.10.5", "libc", "log", @@ -6091,9 +6246,9 @@ dependencies = [ [[package]] name = "solana-system-program" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4fa662731817f995cd114ce44d780be2814982a7674540be8d1c596a2d1ca43" +checksum = "22c8b55398485962ea6127fe84c5768a5ae4a4ecdbd80a0917eb6945593481f9" dependencies = [ "bincode", "log", @@ -6105,9 +6260,9 @@ dependencies = [ [[package]] name = "solana-thin-client" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0815c6d64a4bd71fd92ce33e82c24f5e8a5b105b26619521c4a8a43ab7573a9a" +checksum = "e5c174c724bbe19a53862156e1a5d2cf6cdf1bd5d5d9853b4696b2d9d836123b" dependencies = [ "bincode", "log", @@ -6120,14 +6275,14 @@ dependencies = [ [[package]] name = "solana-tpu-client" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "576431a39a612dac9387fecb5e80fe58989b740337a07bca41f0d02695e415f9" +checksum = "4dcdf9d7109d25900d0532539b00f53e820fb7200f6dc18f90e9d2be20c3d466" dependencies = [ "async-trait", "bincode", "futures-util", - "indexmap 2.2.3", + "indexmap 2.2.6", "indicatif", "log", "rayon", @@ -6144,9 +6299,9 @@ dependencies = [ [[package]] name = "solana-transaction-status" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0d8e2d97a8569afba70a105b402057b253fd9caee92c7ed2c3e1c3e0173fe91" +checksum = "7595aef5a9ddfdecd0966cc12ad0006713e4f8d87eafb4cb7b60fb18d98eff3a" dependencies = [ "Inflector", "base64 0.21.7", @@ -6169,9 +6324,9 @@ dependencies = [ [[package]] name = "solana-udp-client" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8297b04cb335ffac5b4a2c727dd82a2f72c8a96e3d5e1c159e01866b74a17e50" +checksum = "9a59c49a3766232005385bd70f15b0fce756fa6e73fb6397ce9ed34113f090e2" dependencies = [ "async-trait", "solana-connection-cache", @@ -6184,9 +6339,9 @@ dependencies = [ [[package]] name = "solana-version" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84a9f9ff3feebfaa960ac5387b133c6ef2c266779cb4932aed6acac5b83cb7b" +checksum = "73ece37d745e1fb3455acd69b8ba6ecea3ebcefde29e0f40ee8e6467acc4dc04" dependencies = [ "log", "rustc_version", @@ -6200,9 +6355,9 @@ dependencies = [ [[package]] name = "solana-vote" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8a2355a2b40d7b0b3a9ec5a5bd2196494c620a287ce6e4234cc4722fcb0cbb5" +checksum = "67ca2744cf5509c7680a90d6704d00fbab899aa586542c4257fb23d4712b380c" dependencies = [ "crossbeam-channel", "itertools 0.10.5", @@ -6219,13 +6374,13 @@ dependencies = [ [[package]] name = "solana-vote-program" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab0fe8455b2f06016cddefe7e3a7b9c0a57661d44816a4105c81f1088cfc1ac" +checksum = "6944bb3f8f34cc815017f6a50027331f5e7f48321e7998f1572cc898438b6a8a" dependencies = [ "bincode", "log", - "num-derive 0.3.3", + "num-derive 0.4.2", "num-traits", "rustc_version", "serde", @@ -6241,12 +6396,12 @@ dependencies = [ [[package]] name = "solana-zk-token-proof-program" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad624adcac620e41d052b29705f30c003b2e396ebca0145c1d296a1ef13f5aa7" +checksum = "51bd480f4b1b87dea1cdca14f3c6ba8e778e88756dc44ac090e797aab9c8759d" dependencies = [ "bytemuck", - "num-derive 0.3.3", + "num-derive 0.4.2", "num-traits", "solana-program-runtime", "solana-sdk", @@ -6255,9 +6410,9 @@ dependencies = [ [[package]] name = "solana-zk-token-sdk" -version = "1.17.34" +version = "1.18.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a06e103ed5adf1664f9cca3d1c64edad8b5b603255d8a5dd21a4ac5d86b89c" +checksum = "616130045004bccc9dd016fe03ac458db38bd61456f1d16f126acb60f968dcae" dependencies = [ "aes-gcm-siv", "base64 0.21.7", @@ -6269,7 +6424,7 @@ dependencies = [ "itertools 0.10.5", "lazy_static", "merlin", - "num-derive 0.3.3", + "num-derive 0.4.2", "num-traits", "rand 0.7.3", "serde", @@ -6296,7 +6451,7 @@ dependencies = [ "log", "rand 0.8.5", "rustc-demangle", - "scroll", + "scroll 0.11.0", "thiserror", "winapi", ] @@ -6331,7 +6486,7 @@ checksum = "992d9c64c2564cc8f63a4b508bf3ebcdf2254b0429b13cd1d31adb6162432a5f" dependencies = [ "assert_matches", "borsh 0.10.3", - "num-derive 0.4.1", + "num-derive 0.4.2", "num-traits", "solana-program", "spl-token", @@ -6352,25 +6507,25 @@ dependencies = [ [[package]] name = "spl-discriminator-derive" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fadbefec4f3c678215ca72bd71862697bb06b41fd77c0088902dd3203354387b" +checksum = "07fd7858fc4ff8fb0e34090e41d7eb06a823e1057945c26d480bfc21d2338a93" dependencies = [ "quote", "spl-discriminator-syn", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] name = "spl-discriminator-syn" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e5f2044ca42c8938d54d1255ce599c79a1ffd86b677dfab695caa20f9ffc3f2" +checksum = "18fea7be851bd98d10721782ea958097c03a0c2a07d8d4997041d0ece6319a63" dependencies = [ "proc-macro2", "quote", "sha2 0.10.8", - "syn 2.0.71", + "syn 2.0.72", "thiserror", ] @@ -6402,7 +6557,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "249e0318493b6bcf27ae9902600566c689b7dfba9f1bdff5893e92253374e78c" dependencies = [ - "num-derive 0.4.1", + "num-derive 0.4.2", "num-traits", "solana-program", "spl-program-error-derive", @@ -6411,21 +6566,21 @@ dependencies = [ [[package]] name = "spl-program-error-derive" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5269c8e868da17b6552ef35a51355a017bd8e0eae269c201fef830d35fa52c" +checksum = "1845dfe71fd68f70382232742e758557afe973ae19e6c06807b2c30f5d5cb474" dependencies = [ "proc-macro2", "quote", "sha2 0.10.8", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] name = "spl-tlv-account-resolution" -version = "0.5.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f335787add7fa711819f9e7c573f8145a5358a709446fe2d24bf2a88117c90" +checksum = "615d381f48ddd2bb3c57c7f7fb207591a2a05054639b18a62e785117dd7a8683" dependencies = [ "bytemuck", "solana-program", @@ -6458,9 +6613,9 @@ checksum = "d697fac19fd74ff472dfcc13f0b442dd71403178ce1de7b5d16f83a33561c059" dependencies = [ "arrayref", "bytemuck", - "num-derive 0.4.1", + "num-derive 0.4.2", "num-traits", - "num_enum 0.7.1", + "num_enum 0.7.2", "solana-program", "solana-security-txt", "solana-zk-token-sdk", @@ -6554,6 +6709,12 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "strum" version = "0.24.1" @@ -6592,7 +6753,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -6620,15 +6781,33 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.71" +version = "2.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "syn_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.72", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "synstructure" version = "0.12.6" @@ -6641,6 +6820,27 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tap" version = "1.0.1" @@ -6649,9 +6849,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tar" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" +checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" dependencies = [ "filetime", "libc", @@ -6672,13 +6872,19 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.2.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] +[[package]] +name = "termtree" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" + [[package]] name = "textwrap" version = "0.11.0" @@ -6690,28 +6896,28 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" [[package]] name = "thiserror" -version = "1.0.62" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2675633b1499176c2dff06b0856a27976a8f9d436737b4cf4f312d4d91d8bbb" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.62" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d20468752b09f49e909e55a5d338caa8bedf615594e9d80bc4c565d30faf798c" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -6722,9 +6928,9 @@ checksum = "bcbb6aa301e5d3b0b5ef639c9a9c7e2f1c944f177b460c04dc24c69b1fa2bd99" [[package]] name = "thread_local" -version = "1.1.7" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ "cfg-if", "once_cell", @@ -6791,9 +6997,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -6806,11 +7012,10 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.29.1" +version = "1.38.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" +checksum = "eb2caba9f80616f438e09748d5acda951967e1ea58508ef53d9c6402485a46df" dependencies = [ - "autocfg", "backtrace", "bytes", "libc", @@ -6819,20 +7024,20 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.4.9", + "socket2", "tokio-macros", "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -6857,9 +7062,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" dependencies = [ "futures-core", "pin-project-lite", @@ -6878,14 +7083,14 @@ dependencies = [ "tokio", "tokio-rustls", "tungstenite", - "webpki-roots 0.25.2", + "webpki-roots 0.25.4", ] [[package]] name = "tokio-util" -version = "0.7.7" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" dependencies = [ "bytes", "futures-core", @@ -6893,7 +7098,6 @@ dependencies = [ "futures-sink", "pin-project-lite", "tokio", - "tracing", ] [[package]] @@ -6907,47 +7111,58 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.2" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" +checksum = "ac2caab0bf757388c6c0ae23b3293fdb463fee59434529014f85e3263b995c28" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.20.2", + "toml_edit 0.22.16", ] [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.19.8" +version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 1.9.3", + "indexmap 2.2.6", "toml_datetime", - "winnow 0.4.1", + "winnow 0.5.40", ] [[package]] name = "toml_edit" -version = "0.20.2" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ - "indexmap 2.2.3", + "indexmap 2.2.6", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "278f3d518e152219c994ce877758516bca5e118eaed6996192a774fb9fbf0788" +dependencies = [ + "indexmap 2.2.6", "serde", "serde_spanned", "toml_datetime", - "winnow 0.5.15", + "winnow 0.6.15", ] [[package]] @@ -6960,6 +7175,7 @@ dependencies = [ "futures-util", "pin-project", "pin-project-lite", + "tokio", "tower-layer", "tower-service", "tracing", @@ -7009,7 +7225,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -7053,15 +7269,15 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tstr" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cca3264971090dec0feef3b455a3c178f02762f7550cf4592991ac64b3be2d7e" +checksum = "7f8e0294f14baae476d0dd0a2d780b2e24d66e349a9de876f5126777a37bdba7" dependencies = [ "tstr_proc_macros", ] @@ -7081,7 +7297,7 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http", + "http 0.2.12", "httparse", "log", "rand 0.8.5", @@ -7101,9 +7317,9 @@ checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" [[package]] name = "typenum" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "uint" @@ -7119,36 +7335,30 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] -[[package]] -name = "unicode-segmentation" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" - [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "unicode-xid" @@ -7177,9 +7387,9 @@ dependencies = [ [[package]] name = "unsafe-libyaml" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" [[package]] name = "untrusted" @@ -7205,9 +7415,9 @@ dependencies = [ [[package]] name = "url" -version = "2.5.0" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", "idna 0.5.0", @@ -7222,11 +7432,11 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] name = "uuid" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" dependencies = [ - "getrandom 0.2.12", + "getrandom 0.2.15", ] [[package]] @@ -7261,9 +7471,9 @@ checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" [[package]] name = "walkdir" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", @@ -7271,11 +7481,10 @@ dependencies = [ [[package]] name = "want" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "log", "try-lock", ] @@ -7293,9 +7502,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -7303,24 +7512,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.34" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ "cfg-if", "js-sys", @@ -7330,9 +7539,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -7340,28 +7549,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "web-sys" -version = "0.3.61" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", @@ -7426,9 +7635,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.25.2" +version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "winapi" @@ -7448,11 +7657,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -7462,36 +7671,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets 0.48.0", -] - -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" +name = "windows-core" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.42.2", + "windows-targets 0.52.6", ] [[package]] @@ -7500,7 +7685,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.48.0", + "windows-targets 0.48.5", ] [[package]] @@ -7509,194 +7694,144 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.3", + "windows-targets 0.52.6", ] [[package]] name = "windows-targets" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] name = "windows-targets" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" -dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", -] - -[[package]] -name = "windows-targets" -version = "0.52.3" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.3", - "windows_aarch64_msvc 0.52.3", - "windows_i686_gnu 0.52.3", - "windows_i686_msvc 0.52.3", - "windows_x86_64_gnu 0.52.3", - "windows_x86_64_gnullvm 0.52.3", - "windows_x86_64_msvc 0.52.3", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.3" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] -name = "windows_i686_msvc" -version = "0.42.2" +name = "windows_i686_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.3" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.3" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.4.1" +version = "0.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" dependencies = [ "memchr", ] [[package]] name = "winnow" -version = "0.5.15" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" +checksum = "557404e450152cd6795bb558bca69e43c585055f4606e3bcae5894fc6dac9ba0" dependencies = [ "memchr", ] @@ -7740,11 +7875,13 @@ dependencies = [ [[package]] name = "xattr" -version = "1.0.1" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4686009f71ff3e5c4dbcf1a282d0a44db3f021ba69350cd42086b3e5f1c6985" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" dependencies = [ "libc", + "linux-raw-sys", + "rustix", ] [[package]] @@ -7764,22 +7901,22 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -7799,7 +7936,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.72", ] [[package]] @@ -7813,11 +7950,11 @@ dependencies = [ [[package]] name = "zstd" -version = "0.13.0" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bffb3309596d527cfcba7dfc6ed6052f1d39dfbd7c867aa2e865e4a449c10110" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" dependencies = [ - "zstd-safe 7.0.0", + "zstd-safe 7.2.0", ] [[package]] @@ -7832,20 +7969,19 @@ dependencies = [ [[package]] name = "zstd-safe" -version = "7.0.0" +version = "7.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43747c7422e2924c11144d5229878b98180ef8b06cca4ab5af37afc8a8d8ea3e" +checksum = "fa556e971e7b568dc775c136fc9de8c779b1c2fc3a63defaafadffdbd3181afa" dependencies = [ "zstd-sys", ] [[package]] name = "zstd-sys" -version = "2.0.8+zstd.1.5.5" +version = "2.0.12+zstd.1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c" +checksum = "0a4e40c320c3cb459d9a9ff6de98cff88f4751ee9275d140e2be94a2b74e4c13" dependencies = [ "cc", - "libc", "pkg-config", ] diff --git a/evm_loader/Cargo.toml b/evm_loader/Cargo.toml index 92c51938f..d91765a5d 100644 --- a/evm_loader/Cargo.toml +++ b/evm_loader/Cargo.toml @@ -12,16 +12,19 @@ members = [ ] [workspace.dependencies] -solana-clap-utils = "=1.17.34" -solana-cli = "=1.17.34" -solana-cli-config = "=1.17.34" -solana-client = "=1.17.34" -solana-account-decoder = "=1.17.34" -solana-program = { version = "=1.17.34", default-features = false } -solana-sdk = "=1.17.34" -solana-program-runtime = "=1.17.34" -solana-runtime = "=1.17.34" -solana-accounts-db = "=1.17.34" +solana-clap-utils = "=1.18.18" +solana-cli = "=1.18.18" +solana-cli-config = "=1.18.18" +solana-client = "=1.18.18" +solana-account-decoder = "=1.18.18" +solana-program = { version = "=1.18.18", default-features = false } +solana-sdk = "=1.18.18" +solana-program-runtime = "=1.18.18" +solana-runtime = { version = "=1.18.18", features = ["dev-context-only-utils"] } +solana-accounts-db = "=1.18.18" +solana-bpf-loader-program = "=1.18.18" +solana-loader-v4-program = "=1.18.18" +solana-transaction-status = "=1.18.18" [profile.test] debug = true diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 0bbcc12c1..256822c3c 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -clap = "2.33.3" +clap = "2.34.0" evm-loader = { path = "../program", default-features = false, features = ["log"] } solana-sdk.workspace = true solana-client.workspace = true @@ -20,7 +20,7 @@ tracing-appender = "0.2.3" neon-lib = { path = "../lib" } actix-web = "4.8.0" actix-request-identifier = "4.2.0" -hex = "0.4.2" +hex = "0.4.3" build-info = "0.0.37" [build-dependencies] diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index bd62f0f8e..8cf6ca5a2 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -6,13 +6,13 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -clap = "2.33.3" +clap = "2.34.0" evm-loader = { path = "../program", default-features = false, features = ["log"] } solana-sdk.workspace = true solana-client.workspace = true solana-clap-utils.workspace = true solana-cli-config.workspace = true -hex = "0.4.2" +hex = "0.4.3" serde = "1.0.204" serde_json = { version = "1.0.120", features = ["preserve_order"] } log = "0.4.22" diff --git a/evm_loader/cli/src/main.rs b/evm_loader/cli/src/main.rs index a05cb2877..68cb20995 100644 --- a/evm_loader/cli/src/main.rs +++ b/evm_loader/cli/src/main.rs @@ -32,7 +32,7 @@ use evm_loader::types::Address; use neon_lib::errors::NeonError; use neon_lib::rpc::{CallDbClient, RpcEnum}; use neon_lib::tracing::tracers::TracerTypeEnum; -use neon_lib::types::TracerDb; +use neon_lib::types::TracerDbType; use solana_clap_utils::keypair::signer_from_path; use solana_sdk::signature::Signer; @@ -154,15 +154,14 @@ async fn build_rpc(options: &ArgMatches<'_>, config: &Config) -> Result Self { + let tracer_db = TracerDbType::from_config(&config.db_config).await; Self { - tracer_db: RocksDb::new(&(config.db_config)).await, + tracer_db, rpc_client: CloneRpcClient::new_from_api_config(&config), config, } diff --git a/evm_loader/lib/src/account_data.rs b/evm_loader/lib/src/account_data.rs index 376218121..9c1535d62 100644 --- a/evm_loader/lib/src/account_data.rs +++ b/evm_loader/lib/src/account_data.rs @@ -1,14 +1,18 @@ -pub use evm_loader::account_storage::{AccountStorage, SyncedAccountStorage}; -// use solana_sdk::account::{ReadableAccount, WritableAccount}; +use std::fmt; + +use solana_sdk::account_info::IntoAccountInfo; +use solana_sdk::entrypoint::MAX_PERMITTED_DATA_INCREASE; use solana_sdk::system_program; -// use solana_sdk::clock::Epoch; use solana_sdk::{ account::{Account, ReadableAccount}, account_info::AccountInfo, pubkey::Pubkey, }; -#[derive(Clone, Debug)] +pub use evm_loader::account_storage::{AccountStorage, SyncedAccountStorage}; +use evm_loader::solana_program::debug_account_data::debug_account_data; + +#[derive(Clone)] #[repr(C)] pub struct AccountData { original_length: u32, @@ -20,8 +24,24 @@ pub struct AccountData { pub rent_epoch: u64, } -use solana_sdk::account_info::IntoAccountInfo; -use solana_sdk::entrypoint::MAX_PERMITTED_DATA_INCREASE; +impl fmt::Debug for AccountData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut debug_struct = f.debug_struct("AccountData"); + + debug_struct + .field("original_length", &self.original_length) + .field("pubkey", &bs58::encode(&self.pubkey).into_string()) + .field("lamports", &self.lamports) + .field("owner", &bs58::encode(&self.owner).into_string()) + .field("executable", &self.executable) + .field("rent_epoch", &self.rent_epoch) + .field("data_len", &self.data.len()); + + debug_account_data(&self.data, &mut debug_struct); + + debug_struct.finish() + } +} impl AccountData { #[must_use] @@ -157,9 +177,10 @@ impl<'a> From<&'a AccountData> for Account { #[cfg(test)] mod tests { - use super::*; use std::str::FromStr; + use super::*; + #[tokio::test] async fn test_account_data() { let mut account_data = AccountData::new(Pubkey::default()); diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index 3fd6be96b..92d247dfa 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -332,6 +332,11 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { let mut response = self.rpc.get_multiple_accounts(&missing_keys).await?; + debug!( + "get_multiple_accounts: missing_keys={:?} response={response:?}", + missing_keys + ); + let mut j = 0_usize; for i in 0..pubkeys.len() { if exists[i] { @@ -543,6 +548,7 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { self._add_legacy_storage(&legacy_storage, &info, pubkey) .await } + evm_loader::account::TAG_EMPTY => Ok(self.add_empty_account(pubkey)), _ => { unimplemented!(); } @@ -559,6 +565,7 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { fn add_empty_account(&self, pubkey: Pubkey) -> &RefCell { let account_data = AccountData::new(pubkey); self.mark_account(pubkey, false); + info!("add_empty_account(pubkey={pubkey}, account_data={account_data:?})"); self.accounts .insert(pubkey, Box::new(RefCell::new(account_data))) } @@ -568,6 +575,8 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { pubkey: Pubkey, is_writable: bool, ) -> NeonResult<&RefCell> { + info!("use_account(pubkey={pubkey}, is_writable={is_writable})"); + if pubkey == self.operator() { return Err(EvmLoaderError::InvalidAccountForCall(pubkey).into()); } @@ -580,8 +589,10 @@ impl<'a, T: Rpc> EmulatorAccountStorage<'_, T> { let account = self._get_account_from_rpc(pubkey).await?; if let Some(account) = account { + info!("found account for pubkey={pubkey} in RPC account={account:?}"); self.add_account(pubkey, account).await } else { + info!("account not found in RPC, adding empty account for pubkey={pubkey}"); Ok(self.add_empty_account(pubkey)) } } @@ -1340,7 +1351,7 @@ impl SyncedAccountStorage for EmulatorAccountStorage<'_, T> { .await .map_err(|e| EvmLoaderError::Custom(e.to_string()))?; - solana_simulator.set_sysvar(&Clock { + solana_simulator.set_clock(Clock { slot: self.block_number, epoch_start_timestamp: self.block_timestamp, epoch: 0, @@ -1379,10 +1390,9 @@ impl SyncedAccountStorage for EmulatorAccountStorage<'_, T> { .await .map_err(|e| EvmLoaderError::Custom(e.to_string()))?; - let trx = Transaction::new_unsigned(Message::new_with_blockhash( + let trx = Transaction::new_unsigned(Message::new( &[instruction.clone()], Some(&solana_simulator.payer().pubkey()), - &solana_simulator.blockhash(), )); let result = solana_simulator diff --git a/evm_loader/lib/src/commands/emulate.rs b/evm_loader/lib/src/commands/emulate.rs index ef16d54dc..a7f2b48df 100644 --- a/evm_loader/lib/src/commands/emulate.rs +++ b/evm_loader/lib/src/commands/emulate.rs @@ -15,7 +15,7 @@ use evm_loader::{ executor::SyncedExecutorState, gasometer::LAMPORTS_PER_SIGNATURE, }; -use log::{debug, info}; +use log::{debug, error, info}; use serde::{Deserialize, Serialize}; use serde_json::Value; use serde_with::{hex::Hex, serde_as, DisplayFromStr}; @@ -176,11 +176,15 @@ async fn emulate_trx( let mut backend = SyncedExecutorState::new(storage); let mut evm = match Machine::new(&tx, origin, &mut backend, tracer).await { Ok(evm) => evm, - Err(e) => return Ok((EmulateResponse::revert(&e, &backend), None)), + Err(e) => { + error!("EVM creation failed {e:?}"); + return Ok((EmulateResponse::revert(&e, &backend), None)); + } }; let (exit_status, steps_executed, tracer) = evm.execute(step_limit, &mut backend).await?; if exit_status == ExitStatus::StepLimit { + error!("Step_limit={step_limit} exceeded"); return Ok(( EmulateResponse::revert(&NeonError::TooManySteps, &backend), None, diff --git a/evm_loader/lib/src/commands/get_config.rs b/evm_loader/lib/src/commands/get_config.rs index faca62327..de3c675b7 100644 --- a/evm_loader/lib/src/commands/get_config.rs +++ b/evm_loader/lib/src/commands/get_config.rs @@ -3,7 +3,6 @@ use async_trait::async_trait; use base64::Engine; use enum_dispatch::enum_dispatch; -use solana_sdk::signer::Signer; use std::collections::BTreeMap; use tokio::sync::OnceCell; @@ -16,6 +15,7 @@ use crate::NeonResult; use crate::rpc::{CallDbClient, CloneRpcClient}; use serde_with::{serde_as, DisplayFromStr}; use solana_client::rpc_config::RpcSimulateTransactionConfig; +use solana_sdk::signature::Signer; #[derive(Debug, Serialize, Deserialize)] pub enum Status { @@ -44,6 +44,7 @@ pub struct GetConfigResponse { pub config: BTreeMap, } +#[allow(clippy::large_enum_variant)] pub enum ConfigSimulator<'r> { CloneRpcClient { program_id: Pubkey, diff --git a/evm_loader/lib/src/commands/simulate_solana.rs b/evm_loader/lib/src/commands/simulate_solana.rs index 44bee35fc..64fc69763 100644 --- a/evm_loader/lib/src/commands/simulate_solana.rs +++ b/evm_loader/lib/src/commands/simulate_solana.rs @@ -1,6 +1,13 @@ use std::collections::HashSet; +use crate::{ + rpc::Rpc, + solana_simulator::{SolanaSimulator, SyncState}, + types::SimulateSolanaRequest, + NeonResult, +}; use bincode::Options; +use log::info; use serde::{Deserialize, Serialize}; use serde_with::serde_as; use solana_program_runtime::compute_budget::ComputeBudget; @@ -9,13 +16,7 @@ use solana_sdk::{ pubkey::Pubkey, transaction::{SanitizedTransaction, Transaction, VersionedTransaction}, }; - -use crate::{ - rpc::Rpc, - solana_simulator::{SolanaSimulator, SyncState}, - types::SimulateSolanaRequest, - NeonResult, -}; +use solana_transaction_status::EncodableWithMeta; #[serde_as] #[derive(Deserialize, Serialize, Debug, Default)] @@ -101,6 +102,10 @@ pub async fn execute( let mut transactions: Vec = vec![]; for data in request.transactions { let tx = decode_transaction(&data)?; + info!( + "Encoded transaction: {}", + serde_json::to_string(&tx.json_encode()).unwrap() + ); transactions.push(tx); } @@ -119,16 +124,14 @@ pub async fn execute( let accounts = account_keys(&sanitized_transactions); simulator.sync_accounts(rpc, &accounts).await?; - simulator.replace_blockhash(&request.blockhash.into()); - // Process transactions let mut results = Vec::new(); for tx in sanitized_transactions { - let r = simulator.process_transaction(tx)?; + let r = simulator.process_transaction(request.blockhash.into(), &tx)?; results.push(SimulateSolanaTransactionResult { - error: r.status.err(), - logs: r.log_messages.unwrap_or_default(), - executed_units: r.executed_units, + error: r.result.err(), + logs: r.logs, + executed_units: r.units_consumed, }); } diff --git a/evm_loader/lib/src/commands/trace.rs b/evm_loader/lib/src/commands/trace.rs index 77beb7d21..1a243421e 100644 --- a/evm_loader/lib/src/commands/trace.rs +++ b/evm_loader/lib/src/commands/trace.rs @@ -1,6 +1,7 @@ #![allow(clippy::missing_errors_doc)] use crate::commands::emulate::EmulateResponse; +use log::info; use serde_json::Value; use solana_sdk::pubkey::Pubkey; @@ -23,5 +24,9 @@ pub async fn trace_transaction( let tracer = new_tracer(&emulate_request.tx, trace_config)?; - super::emulate::execute(rpc, program_id, emulate_request, Some(tracer)).await + let response = super::emulate::execute(rpc, program_id, emulate_request, Some(tracer)).await?; + + info!("response: {:?}", response); + + Ok(response) } diff --git a/evm_loader/lib/src/commands/transaction_executor.rs b/evm_loader/lib/src/commands/transaction_executor.rs index 158b89874..75f190f95 100644 --- a/evm_loader/lib/src/commands/transaction_executor.rs +++ b/evm_loader/lib/src/commands/transaction_executor.rs @@ -21,6 +21,7 @@ use { }; #[derive(Default, Debug, Serialize, Deserialize)] +#[allow(clippy::struct_field_names)] pub struct Stats { pub total_objects: u32, pub corrected_objects: u32, diff --git a/evm_loader/lib/src/config.rs b/evm_loader/lib/src/config.rs index 17fe2bff1..bfbbf879c 100644 --- a/evm_loader/lib/src/config.rs +++ b/evm_loader/lib/src/config.rs @@ -1,6 +1,6 @@ +use crate::types::{ChDbConfig, DbConfig, RocksDbConfig}; use std::{env, str::FromStr}; -use crate::types::RocksDbConfig; use serde::{Deserialize, Serialize}; use solana_sdk::{commitment_config::CommitmentConfig, pubkey::Pubkey, signature::Keypair}; @@ -13,7 +13,7 @@ pub struct Config { pub fee_payer: Option, pub commitment: CommitmentConfig, pub solana_cli_config: solana_cli_config::Config, - pub db_config: Option, + pub db_config: Option, pub json_rpc_url: String, pub keypair_path: String, } @@ -27,7 +27,7 @@ pub struct APIOptions { pub solana_max_retries: usize, pub evm_loader: Pubkey, pub key_for_config: Pubkey, - pub db_config: RocksDbConfig, + pub db_config: DbConfig, } /// # Errors @@ -78,7 +78,49 @@ pub fn load_api_config_from_environment() -> APIOptions { } } -pub fn load_db_config_from_environment() -> RocksDbConfig { +#[must_use] +pub fn load_db_config_from_environment() -> DbConfig { + env::var("TRACER_DB_TYPE") + .ok() + .and_then(|db_type| match db_type.to_lowercase().as_str() { + "rocksdb" => Option::from(DbConfig { + rocksdb_config: Option::from(load_rocks_db_config_from_environment()), + chdb_config: None, + }), + "clickhouse" => Option::from(DbConfig { + rocksdb_config: None, + chdb_config: Option::from(load_ch_db_config_from_environment()), + }), + _ => None, + }) + .expect("TRACER_DB_TYPE variable must be either 'clickhouse' or 'rocksdb'") +} + +pub fn load_ch_db_config_from_environment() -> ChDbConfig { + let clickhouse_url = env::var("NEON_DB_CLICKHOUSE_URLS") + .map(|urls| { + urls.split(';') + .map(std::borrow::ToOwned::to_owned) + .collect::>() + }) + .expect("neon clickhouse db urls valiable must be set"); + + let clickhouse_user = env::var("NEON_DB_CLICKHOUSE_USER") + .map(Some) + .unwrap_or(None); + + let clickhouse_password = env::var("NEON_DB_CLICKHOUSE_PASSWORD") + .map(Some) + .unwrap_or(None); + + ChDbConfig { + clickhouse_url, + clickhouse_user, + clickhouse_password, + } +} + +pub fn load_rocks_db_config_from_environment() -> RocksDbConfig { let rocksdb_host = env::var("ROCKSDB_HOST") .as_deref() .unwrap_or("127.0.0.1") diff --git a/evm_loader/lib/src/rpc/db_call_client.rs b/evm_loader/lib/src/rpc/db_call_client.rs index 302a654c5..56f2f133d 100644 --- a/evm_loader/lib/src/rpc/db_call_client.rs +++ b/evm_loader/lib/src/rpc/db_call_client.rs @@ -1,8 +1,9 @@ use super::{e, Rpc}; -use crate::types::TracerDb; +use crate::types::{TracerDb, TracerDbType}; use crate::NeonError; use crate::NeonError::RocksDb; use async_trait::async_trait; +use log::debug; use solana_client::{ client_error::Result as ClientResult, client_error::{ClientError, ClientErrorKind}, @@ -12,17 +13,16 @@ use solana_sdk::{ clock::{Slot, UnixTimestamp}, pubkey::Pubkey, }; -use tracing::debug; pub struct CallDbClient { - tracer_db: TracerDb, + tracer_db: TracerDbType, slot: u64, tx_index_in_block: Option, } impl CallDbClient { pub async fn new( - tracer_db: TracerDb, + tracer_db: TracerDbType, slot: u64, tx_index_in_block: Option, ) -> Result { @@ -30,6 +30,7 @@ impl CallDbClient { .get_earliest_rooted_slot() .await .map_err(RocksDb)?; + if slot < earliest_rooted_slot { return Err(NeonError::EarlySlot(slot, earliest_rooted_slot)); } @@ -63,9 +64,7 @@ impl Rpc for CallDbClient { for key in pubkeys { result.push(self.get_account_at(key).await?); } - - debug!("db_call_client.get_multiple_accounts result: {result:?}"); - + debug!("get_multiple_accounts: pubkeys={pubkeys:?} result={result:?}"); Ok(result) } diff --git a/evm_loader/lib/src/rpc/emulator_client.rs b/evm_loader/lib/src/rpc/emulator_client.rs index 63d247c3a..a3288aeab 100644 --- a/evm_loader/lib/src/rpc/emulator_client.rs +++ b/evm_loader/lib/src/rpc/emulator_client.rs @@ -1,12 +1,12 @@ use async_trait::async_trait; use evm_loader::account_storage::AccountStorage; +use log::debug; use solana_client::client_error::Result as ClientResult; use solana_sdk::{ account::Account, clock::{Slot, UnixTimestamp}, pubkey::Pubkey, }; -use tracing::debug; use crate::account_storage::{fake_operator, EmulatorAccountStorage}; @@ -31,6 +31,7 @@ impl<'rpc, T: Rpc> Rpc for EmulatorAccountStorage<'rpc, T> { &self, pubkeys: &[Pubkey], ) -> ClientResult>> { + debug!("get_multiple_accounts: pubkeys={:?}", pubkeys); if pubkeys.is_empty() { return Ok(Vec::new()); } @@ -47,6 +48,7 @@ impl<'rpc, T: Rpc> Rpc for EmulatorAccountStorage<'rpc, T> { } if let Some(account_data) = self.accounts_get(pubkey) { + debug!("cached account pubkey={pubkey} account_data={account_data:?}"); accounts[i] = Some(Account::from(&*account_data)); continue; } @@ -57,7 +59,8 @@ impl<'rpc, T: Rpc> Rpc for EmulatorAccountStorage<'rpc, T> { let response = self._get_multiple_accounts_from_rpc(&missing_keys).await?; - debug!("emulator_client.get_multiple_accounts response: {response:?}"); + debug!("get_multiple_accounts: missing_keys={missing_keys:?} response={response:?}",); + let mut j = 0_usize; for i in 0..pubkeys.len() { if exists[i] { diff --git a/evm_loader/lib/src/rpc/validator_client.rs b/evm_loader/lib/src/rpc/validator_client.rs index f3322d72b..1c64a8623 100644 --- a/evm_loader/lib/src/rpc/validator_client.rs +++ b/evm_loader/lib/src/rpc/validator_client.rs @@ -17,6 +17,7 @@ use solana_sdk::{ }; use std::{error::Error, ops::Deref, time::Duration}; use std::{future::Future, sync::Arc}; +use tracing::debug; fn should_retry(e: &ClientError) -> bool { let ClientErrorKind::Reqwest(reqwest_error) = e.kind() else { @@ -142,6 +143,10 @@ impl Rpc for CloneRpcClient { if pubkeys.len() == 1 { let account = Rpc::get_account(self, &pubkeys[0]).await?; + debug!( + "get_multiple_accounts: single account pubkey={} account={:?}", + pubkeys[0], account + ); return Ok(vec![account]); } @@ -150,6 +155,10 @@ impl Rpc for CloneRpcClient { let request = || self.rpc.get_multiple_accounts(chunk); let mut accounts = with_retries(self.max_retries, request).await?; + debug!( + "get_multiple_accounts: chunk pubkey={:?} account={:?}", + chunk, accounts + ); result.append(&mut accounts); } @@ -201,6 +210,10 @@ impl Rpc for CloneRpcClient { } } + for feature in &result { + debug!("Deactivated feature: {}", feature); + } + cache.replace(Cache { data: result.clone(), timestamp: Instant::now(), diff --git a/evm_loader/lib/src/solana_simulator/error.rs b/evm_loader/lib/src/solana_simulator/error.rs index f863ea2fa..6bd4ac33e 100644 --- a/evm_loader/lib/src/solana_simulator/error.rs +++ b/evm_loader/lib/src/solana_simulator/error.rs @@ -1,21 +1,21 @@ #[derive(Debug, thiserror::Error)] pub enum Error { - #[error("Unexpected response")] - UnexpectedResponse, + // #[error("Unexpected response")] + // UnexpectedResponse, #[error("Program Account error")] ProgramAccountError, #[error("Rpc Client error {0:?}")] RpcClientError(#[from] solana_client::client_error::ClientError), - #[error("IO error {0:?}")] - IoError(#[from] std::io::Error), + // #[error("IO error {0:?}")] + // IoError(#[from] std::io::Error), #[error("Bincode error {0:?}")] BincodeError(#[from] bincode::Error), - #[error("TryFromIntError error {0:?}")] - TryFromIntError(#[from] std::num::TryFromIntError), + // #[error("TryFromIntError error {0:?}")] + // TryFromIntError(#[from] std::num::TryFromIntError), #[error("Transaction error {0:?}")] TransactionError(#[from] solana_sdk::transaction::TransactionError), - #[error("Sanitize error {0:?}")] - SanitizeError(#[from] solana_sdk::sanitize::SanitizeError), + // #[error("Sanitize error {0:?}")] + // SanitizeError(#[from] solana_sdk::sanitize::SanitizeError), #[error("Instruction error {0:?}")] InstructionError(#[from] solana_sdk::instruction::InstructionError), #[error("Invalid ALT")] diff --git a/evm_loader/lib/src/solana_simulator/mod.rs b/evm_loader/lib/src/solana_simulator/mod.rs index 049a9f5a2..96424943a 100644 --- a/evm_loader/lib/src/solana_simulator/mod.rs +++ b/evm_loader/lib/src/solana_simulator/mod.rs @@ -1,36 +1,65 @@ +use std::collections::HashMap; +use std::rc::Rc; use std::sync::Arc; -use solana_accounts_db::transaction_results::{ - TransactionExecutionDetails, TransactionExecutionResult, +pub use error::Error; +use evm_loader::solana_program::bpf_loader_upgradeable::UpgradeableLoaderState; +use evm_loader::solana_program::clock::Slot; +use evm_loader::solana_program::loader_v4; +use evm_loader::solana_program::loader_v4::{LoaderV4State, LoaderV4Status}; +use evm_loader::solana_program::message::SanitizedMessage; +use log::debug; +use solana_accounts_db::transaction_results::inner_instructions_list_from_instruction_trace; +use solana_bpf_loader_program::syscalls::create_program_runtime_environment_v1; +use solana_loader_v4_program::create_program_runtime_environment_v2; +use solana_program_runtime::compute_budget::ComputeBudget; +use solana_program_runtime::loaded_programs::{ + LoadProgramMetrics, LoadedProgram, LoadedProgramType, LoadedProgramsForTxBatch, + ProgramRuntimeEnvironments, }; -use solana_runtime::{ - bank::{Bank, TransactionSimulationResult}, - runtime_config::RuntimeConfig, +use solana_program_runtime::log_collector::LogCollector; +use solana_program_runtime::message_processor::MessageProcessor; +use solana_program_runtime::sysvar_cache::SysvarCache; +use solana_program_runtime::timings::ExecuteTimings; +use solana_runtime::accounts::construct_instructions_account; +use solana_runtime::builtins::BUILTINS; +use solana_runtime::{bank::TransactionSimulationResult, runtime_config::RuntimeConfig}; +use solana_sdk::account::{ + create_account_shared_data_with_fields, AccountSharedData, ReadableAccount, + DUMMY_INHERITABLE_ACCOUNT_FIELDS, PROGRAM_OWNERS, }; +use solana_sdk::account_utils::StateMut; +use solana_sdk::address_lookup_table::error::AddressLookupError; +use solana_sdk::address_lookup_table::state::AddressLookupTable; +use solana_sdk::clock::Clock; +use solana_sdk::feature_set::FeatureSet; +use solana_sdk::fee_calculator::DEFAULT_TARGET_LAMPORTS_PER_SIGNATURE; +use solana_sdk::message::v0::{LoadedAddresses, MessageAddressTableLookup}; +use solana_sdk::message::{AddressLoader, AddressLoaderError}; +use solana_sdk::rent::Rent; +use solana_sdk::transaction::TransactionError; +use solana_sdk::transaction_context::{ExecutionRecord, IndexOfAccount, TransactionContext}; use solana_sdk::{ account::Account, - address_lookup_table, bpf_loader, bpf_loader_upgradeable, + address_lookup_table, bpf_loader_upgradeable, hash::Hash, pubkey::Pubkey, signature::Keypair, sysvar::{Sysvar, SysvarId}, - transaction::{ - MessageHash, SanitizedTransaction, TransactionVerificationMode, VersionedTransaction, - }, + transaction::{SanitizedTransaction, VersionedTransaction}, }; -use tracing::debug; +pub use utils::SyncState; use crate::rpc::Rpc; mod error; mod utils; -pub use error::Error; -pub use utils::SyncState; - pub struct SolanaSimulator { - bank: Bank, - runtime_config: Arc, + runtime_config: RuntimeConfig, + feature_set: Arc, + accounts_db: HashMap, + sysvar_cache: SysvarCache, payer: Keypair, } @@ -48,42 +77,29 @@ impl SolanaSimulator { runtime_config: RuntimeConfig, sync_state: SyncState, ) -> Result { - let runtime_config = Arc::new(runtime_config); - - let info = utils::genesis_config_info(rpc, sync_state, 1_000.0).await?; - let payer = info.mint_keypair; + let mut feature_set = FeatureSet::all_enabled(); - let genesis_bank = Arc::new(Bank::new_with_paths( - &info.genesis_config, - Arc::clone(&runtime_config), - Vec::default(), - None, - None, - solana_accounts_db::accounts_index::AccountSecondaryIndexes::default(), - solana_accounts_db::accounts_db::AccountShrinkThreshold::default(), - false, - None, - None, - Arc::default(), - )); + if sync_state == SyncState::Yes { + for feature in rpc.get_deactivated_solana_features().await? { + feature_set.deactivate(&feature); + } + } - genesis_bank.set_capitalization(); + let mut sysvar_cache = SysvarCache::default(); - genesis_bank.fill_bank_with_ticks_for_tests(); - let bank = Bank::new_from_parent( - Arc::clone(&genesis_bank), - genesis_bank.collector_id(), - genesis_bank.slot() + 1, - ); + sysvar_cache.set_rent(Rent::default()); + sysvar_cache.set_clock(Clock::default()); if sync_state == SyncState::Yes { - utils::sync_sysvar_accounts(rpc, &bank).await?; + utils::sync_sysvar_accounts(rpc, &mut sysvar_cache).await?; } Ok(Self { - bank, runtime_config, - payer, + feature_set: Arc::new(feature_set), + accounts_db: HashMap::new(), + sysvar_cache, + payer: Keypair::new(), }) } @@ -92,8 +108,6 @@ impl SolanaSimulator { let mut programdata_keys = vec![]; - debug!("SYNC_ACCOUNTS: {keys:?}"); - let mut accounts = rpc.get_multiple_accounts(keys).await?; for (key, account) in keys.iter().zip(&mut accounts) { let Some(account) = account else { @@ -102,6 +116,9 @@ impl SolanaSimulator { if account.executable && bpf_loader_upgradeable::check_id(&account.owner) { let programdata_address = utils::program_data_address(account)?; + debug!( + "program_data_account: program={key} programdata=address{programdata_address}" + ); programdata_keys.push(programdata_address); } @@ -118,6 +135,7 @@ impl SolanaSimulator { continue; }; + debug!("program_data_account: key={key} account={account:?}"); utils::reset_program_data_slot(account)?; storable_accounts.push((key, account)); } @@ -127,72 +145,49 @@ impl SolanaSimulator { Ok(()) } - const fn bank(&self) -> &Bank { - &self.bank - } - + #[must_use] pub const fn payer(&self) -> &Keypair { &self.payer } + #[must_use] pub fn blockhash(&self) -> Hash { - self.bank().last_blockhash() + Hash::new_unique() } - pub fn slot(&self) -> u64 { - self.bank().slot() + pub fn slot(&self) -> Result { + let clock = self.sysvar_cache.get_clock()?; + Ok(clock.slot) } - pub fn replace_blockhash(&mut self, blockhash: &Hash) { - self.bank().register_recent_blockhash(blockhash); - } - - pub fn set_sysvar(&self, sysvar: &T) + fn replace_sysvar_account(&mut self, sysvar: &S) where - T: Sysvar + SysvarId, + S: Sysvar + SysvarId, { - self.bank().set_sysvar_for_tests(sysvar); - } + let old_account = self.accounts_db.get(&S::id()); + let inherit = old_account.map_or(DUMMY_INHERITABLE_ACCOUNT_FIELDS, |a| { + (a.lamports(), a.rent_epoch()) + }); - pub fn set_program_account(&mut self, pubkey: &Pubkey, data: Vec) { - let rent = self.bank().rent_collector().rent; - let lamports = rent.minimum_balance(data.len()); - - self.set_account( - pubkey, - &Account { - lamports, - data, - owner: bpf_loader::ID, - executable: true, - rent_epoch: 0, - }, - ); + let account = create_account_shared_data_with_fields(sysvar, inherit); + self.accounts_db.insert(S::id(), account); } - pub fn set_account(&mut self, pubkey: &Pubkey, account: &Account) { - self.bank().store_account(pubkey, account); + pub fn set_clock(&mut self, clock: Clock) { + self.replace_sysvar_account(&clock); + self.sysvar_cache.set_clock(clock); } pub fn set_multiple_accounts(&mut self, accounts: &[(&Pubkey, &Account)]) { - let include_slot_in_hash = if self - .bank() - .feature_set - .is_active(&solana_sdk::feature_set::account_hash_ignore_slot::id()) - { - solana_accounts_db::accounts_db::IncludeSlotInHash::RemoveSlot - } else { - solana_accounts_db::accounts_db::IncludeSlotInHash::IncludeSlot - }; - - let storable_accounts = (self.slot(), accounts, include_slot_in_hash); - self.bank().store_accounts(storable_accounts); + for (pubkey, account) in accounts { + self.accounts_db + .insert(**pubkey, AccountSharedData::from((*account).clone())); + } } - pub fn get_account(&self, pubkey: &Pubkey) -> Option { - self.bank() - .get_account_with_fixed_root(pubkey) - .map(Account::from) + #[must_use] + pub fn get_shared_account(&self, pubkey: &Pubkey) -> Option { + self.accounts_db.get(pubkey).cloned() } pub fn sanitize_transaction( @@ -200,73 +195,291 @@ impl SolanaSimulator { tx: VersionedTransaction, verify: bool, ) -> Result { - let bank = self.bank(); + let sanitized_tx = { + let size = bincode::serialized_size(&tx)?; + if verify && (size > solana_sdk::packet::PACKET_DATA_SIZE as u64) { + return Err(TransactionError::SanitizeFailure.into()); + } - let sanitized = if verify { - bank.verify_transaction(tx, TransactionVerificationMode::FullVerification)? - } else { - let hash = tx.message.hash(); - SanitizedTransaction::try_create(tx, hash, None, bank)? - }; + let message_hash = if verify { + tx.verify_and_hash_message()? + } else { + tx.message.hash() + }; + + SanitizedTransaction::try_create(tx, message_hash, None, self) + }?; + + if verify { + sanitized_tx.verify_precompiles(&self.feature_set)?; + } - Ok(sanitized) + Ok(sanitized_tx) } pub fn process_transaction( - &mut self, - tx: SanitizedTransaction, - ) -> Result { - let mut result = self.process_multiple_not_intersected_transactions(&[tx])?; + &self, + blockhash: Hash, + tx: &SanitizedTransaction, + ) -> Result { + let mut transaction_accounts = Vec::new(); + for key in tx.message().account_keys().iter() { + let account = if solana_sdk::sysvar::instructions::check_id(key) { + construct_instructions_account(tx.message()) + } else { + self.accounts_db.get(key).cloned().unwrap_or_default() + }; + transaction_accounts.push((*key, account)); + } - Ok(result.remove(0)) - } + let program_indices = Self::build_program_indices(tx, &mut transaction_accounts); + + let compute_budget = self.runtime_config.compute_budget.unwrap_or_default(); + let rent: Arc = self.sysvar_cache.get_rent()?; + let clock: Arc = self.sysvar_cache.get_clock()?; - pub fn process_multiple_not_intersected_transactions( - &mut self, - txs: &[SanitizedTransaction], - ) -> Result, Error> { - let bank = self.bank(); - - let batch = bank.prepare_sanitized_batch(txs); - - let ( - solana_accounts_db::transaction_results::TransactionResults { - execution_results, .. - }, - .., - ) = bank.load_execute_and_commit_transactions( - &batch, - solana_sdk::clock::MAX_PROCESSING_AGE, - false, // collect_balances - true, // enable_cpi_recording - true, // enable_log_recording - true, // enable_return_data_recording - &mut solana_program_runtime::timings::ExecuteTimings::default(), - self.runtime_config.log_messages_bytes_limit, + let lamports_before_tx = + transaction_accounts_lamports_sum(&transaction_accounts, tx.message()).unwrap_or(0); + + let mut transaction_context = TransactionContext::new( + transaction_accounts, + *rent, + compute_budget.max_invoke_stack_height, + compute_budget.max_instruction_trace_length, ); - let mut result = Vec::with_capacity(execution_results.len()); + let loaded_programs = self.load_programs(tx, &compute_budget, &clock); - for execution_result in execution_results { - match execution_result { - TransactionExecutionResult::Executed { details, .. } => result.push(details), - TransactionExecutionResult::NotExecuted(error) => return Err(error.into()), - } + let mut modified_programs = LoadedProgramsForTxBatch::new( + clock.slot, + loaded_programs.environments.clone(), + loaded_programs.upcoming_environments.clone(), + loaded_programs.latest_root_epoch, + ); + + let log_collector = + LogCollector::new_ref_with_limit(self.runtime_config.log_messages_bytes_limit); + + let mut units_consumed = 0u64; + + let mut status = MessageProcessor::process_message( + tx.message(), + &program_indices, + &mut transaction_context, + Some(Rc::clone(&log_collector)), + &loaded_programs, + &mut modified_programs, + Arc::clone(&self.feature_set), + compute_budget, + &mut ExecuteTimings::default(), + &self.sysvar_cache, + blockhash, + DEFAULT_TARGET_LAMPORTS_PER_SIGNATURE / 2, + &mut units_consumed, + ); + + let inner_instructions = Some(inner_instructions_list_from_instruction_trace( + &transaction_context, + )); + + let ExecutionRecord { + accounts, + return_data, + touched_account_count: _touched_account_count, + accounts_resize_delta: _accounts_resize_delta, + } = transaction_context.into(); + + if status.is_ok() + && transaction_accounts_lamports_sum(&accounts, tx.message()) + .filter(|lamports_after_tx| lamports_before_tx == *lamports_after_tx) + .is_none() + { + status = Err(TransactionError::UnbalancedTransaction); } - Ok(result) + let logs = Rc::try_unwrap(log_collector) + .map(|log_collector| log_collector.into_inner().into_messages()) + .ok() + .unwrap(); + + let return_data = if return_data.data.is_empty() { + None + } else { + Some(return_data) + }; + + Ok(TransactionSimulationResult { + result: status, + logs, + post_simulation_accounts: accounts, + units_consumed, + return_data, + inner_instructions, + }) + } + + #[allow(clippy::cast_possible_truncation)] + fn build_program_indices( + tx: &SanitizedTransaction, + transaction_accounts: &mut Vec<(Pubkey, AccountSharedData)>, + ) -> Vec> { + let builtins_start_index = transaction_accounts.len(); + tx.message() + .instructions() + .iter() + .map(|instruction| { + let mut account_indices: Vec = Vec::with_capacity(2); + + let program_index = instruction.program_id_index as usize; + let (program_id, program_account) = &transaction_accounts[program_index]; + + if solana_sdk::native_loader::check_id(program_id) { + return account_indices; + } + + account_indices.insert(0, program_index as IndexOfAccount); + + let owner = program_account.owner(); + if solana_sdk::native_loader::check_id(owner) { + return account_indices; + } + + if let Some(owner_index) = transaction_accounts[builtins_start_index..] + .iter() + .position(|(key, _)| key == owner) + { + let owner_index = owner_index + builtins_start_index; + account_indices.insert(0, owner_index as IndexOfAccount); + } else { + let _builtin = BUILTINS + .iter() + .find(|builtin| builtin.program_id == *owner) + .unwrap(); + + let owner_account = + AccountSharedData::new(100, 100, &solana_sdk::native_loader::id()); + transaction_accounts.push((*owner, owner_account)); + + let owner_index = transaction_accounts.len() - 1; + account_indices.insert(0, owner_index as IndexOfAccount); + } + + account_indices + }) + .collect() } - pub fn simulate_transaction( + fn load_programs( &self, - tx: VersionedTransaction, - ) -> Result { - let sanitized = - SanitizedTransaction::try_create(tx, MessageHash::Compute, None, self.bank())?; + tx: &SanitizedTransaction, + compute_budget: &ComputeBudget, + clock: &Arc, + ) -> LoadedProgramsForTxBatch { + let program_runtime_environments = ProgramRuntimeEnvironments { + program_runtime_v1: Arc::new( + create_program_runtime_environment_v1( + &self.feature_set, + compute_budget, + true, + true, + ) + .unwrap(), + ), + program_runtime_v2: Arc::new(create_program_runtime_environment_v2( + compute_budget, + true, + )), + }; + + let mut loaded_programs = LoadedProgramsForTxBatch::new( + clock.slot, + program_runtime_environments.clone(), + None, + clock.epoch, + ); - let simulation_result = self.bank().simulate_transaction_unchecked(sanitized); + tx.message().account_keys().iter().for_each(|key| { + if loaded_programs.find(key).is_none() { + let account = self.accounts_db.get(key).cloned().unwrap_or_default(); + if PROGRAM_OWNERS.iter().any(|owner| account.owner() == owner) { + let mut load_program_metrics = LoadProgramMetrics { + program_id: key.to_string(), + ..LoadProgramMetrics::default() + }; + let loaded_program = match self.load_program_accounts(account) { + ProgramAccountLoadResult::InvalidAccountData => { + LoadedProgram::new_tombstone(0, LoadedProgramType::Closed) + } + + ProgramAccountLoadResult::ProgramOfLoaderV1orV2(program_account) => { + LoadedProgram::new( + program_account.owner(), + program_runtime_environments.program_runtime_v1.clone(), + 0, + 0, + None, + program_account.data(), + program_account.data().len(), + &mut load_program_metrics, + ) + .unwrap() + } + + ProgramAccountLoadResult::ProgramOfLoaderV3( + program_account, + programdata_account, + _slot, + ) => { + let programdata = programdata_account + .data() + .get(UpgradeableLoaderState::size_of_programdata_metadata()..) + .unwrap(); + LoadedProgram::new( + program_account.owner(), + program_runtime_environments.program_runtime_v1.clone(), + 0, + 0, + None, + programdata, + program_account + .data() + .len() + .saturating_add(programdata_account.data().len()), + &mut load_program_metrics, + ) + .unwrap() + } + + ProgramAccountLoadResult::ProgramOfLoaderV4(program_account, _slot) => { + let elf_bytes = program_account + .data() + .get(LoaderV4State::program_data_offset()..) + .unwrap(); + LoadedProgram::new( + program_account.owner(), + program_runtime_environments.program_runtime_v2.clone(), + 0, + 0, + None, + elf_bytes, + program_account.data().len(), + &mut load_program_metrics, + ) + .unwrap() + } + }; + loaded_programs.replenish(*key, Arc::new(loaded_program)); + } + } + }); - Ok(simulation_result) + for builtin in BUILTINS { + // create_loadable_account_with_fields + let program = LoadedProgram::new_builtin(0, builtin.name.len(), builtin.entrypoint); + loaded_programs.replenish(builtin.program_id, Arc::new(program)); + } + + loaded_programs } pub fn simulate_legacy_transaction( @@ -274,6 +487,198 @@ impl SolanaSimulator { tx: solana_sdk::transaction::Transaction, ) -> Result { let versioned_transaction = VersionedTransaction::from(tx); - self.simulate_transaction(versioned_transaction) + self.process_transaction( + *versioned_transaction.message.recent_blockhash(), + &self.sanitize_transaction(versioned_transaction, false)?, + ) + } + + fn load_program_accounts( + &self, + program_account: AccountSharedData, + ) -> ProgramAccountLoadResult { + debug_assert!(solana_bpf_loader_program::check_loader_id( + program_account.owner() + )); + + if loader_v4::check_id(program_account.owner()) { + return solana_loader_v4_program::get_state(program_account.data()) + .ok() + .and_then(|state| { + (!matches!(state.status, LoaderV4Status::Retracted)).then_some(state.slot) + }) + .map_or(ProgramAccountLoadResult::InvalidAccountData, |slot| { + ProgramAccountLoadResult::ProgramOfLoaderV4(program_account, slot) + }); + } + + if !bpf_loader_upgradeable::check_id(program_account.owner()) { + return ProgramAccountLoadResult::ProgramOfLoaderV1orV2(program_account); + } + + if let Ok(UpgradeableLoaderState::Program { + programdata_address, + }) = program_account.state() + { + if let Some(programdata_account) = self.accounts_db.get(&programdata_address).cloned() { + if let Ok(UpgradeableLoaderState::ProgramData { + slot, + upgrade_authority_address: _, + }) = programdata_account.state() + { + return ProgramAccountLoadResult::ProgramOfLoaderV3( + program_account, + programdata_account, + slot, + ); + } + } + } + ProgramAccountLoadResult::InvalidAccountData + } +} + +enum ProgramAccountLoadResult { + InvalidAccountData, + ProgramOfLoaderV1orV2(AccountSharedData), + ProgramOfLoaderV3(AccountSharedData, AccountSharedData, Slot), + ProgramOfLoaderV4(AccountSharedData, Slot), +} + +fn transaction_accounts_lamports_sum( + accounts: &[(Pubkey, AccountSharedData)], + message: &SanitizedMessage, +) -> Option { + let mut lamports_sum = 0u128; + for i in 0..message.account_keys().len() { + let (_, account) = accounts.get(i)?; + lamports_sum = lamports_sum.checked_add(u128::from(account.lamports()))?; + } + Some(lamports_sum) +} + +impl AddressLoader for &SolanaSimulator { + fn load_addresses( + self, + lookups: &[MessageAddressTableLookup], + ) -> Result { + let loaded_addresses = lookups + .iter() + .map(|address_table_lookup| { + let table_account = self + .get_shared_account(&address_table_lookup.account_key) + .ok_or(AddressLookupError::LookupTableAccountNotFound)?; + + if table_account.owner() != &address_lookup_table::program::id() { + return Err(AddressLookupError::InvalidAccountOwner); + } + + let current_slot = self + .slot() + .map_err(|_| AddressLookupError::LookupTableAccountNotFound)?; + + let slot_hashes = self + .sysvar_cache + .get_slot_hashes() + .map_err(|_| AddressLookupError::LookupTableAccountNotFound)?; + + let lookup_table = AddressLookupTable::deserialize(table_account.data()) + .map_err(|_| AddressLookupError::InvalidAccountData)?; + + Ok(LoadedAddresses { + writable: lookup_table.lookup( + current_slot, + &address_table_lookup.writable_indexes, + &slot_hashes, + )?, + readonly: lookup_table.lookup( + current_slot, + &address_table_lookup.readonly_indexes, + &slot_hashes, + )?, + }) + }) + .collect::>()?; + + Ok(loaded_addresses) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn test_hex_encode_tx() { + let bytes = [ + 1, 58, 23, 68, 33, 87, 114, 44, 125, 7, 236, 250, 189, 152, 80, 109, 13, 162, 107, 101, + 124, 216, 66, 80, 213, 40, 53, 51, 182, 30, 255, 233, 81, 173, 129, 169, 64, 34, 99, + 244, 26, 97, 234, 36, 224, 159, 246, 251, 59, 49, 38, 37, 93, 186, 243, 244, 21, 130, + 128, 72, 105, 242, 160, 60, 7, 1, 0, 12, 17, 231, 21, 48, 207, 152, 236, 233, 187, 223, + 100, 82, 93, 7, 113, 26, 194, 124, 70, 245, 140, 6, 215, 63, 170, 178, 46, 130, 201, + 93, 40, 215, 178, 87, 173, 47, 151, 71, 81, 72, 73, 80, 156, 165, 181, 37, 178, 136, + 180, 35, 74, 234, 62, 83, 114, 123, 149, 139, 225, 217, 56, 147, 131, 206, 45, 105, + 208, 134, 80, 73, 140, 123, 117, 252, 233, 38, 133, 137, 99, 77, 55, 167, 149, 85, 24, + 36, 45, 148, 20, 106, 29, 21, 63, 99, 229, 104, 209, 135, 106, 102, 83, 227, 22, 170, + 173, 106, 135, 14, 233, 81, 75, 157, 216, 252, 53, 197, 36, 130, 119, 213, 126, 95, 12, + 254, 107, 149, 132, 193, 66, 216, 86, 105, 62, 222, 21, 157, 45, 17, 10, 178, 124, 189, + 91, 143, 219, 219, 104, 133, 196, 14, 129, 66, 215, 247, 28, 36, 71, 221, 69, 99, 94, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3, 6, 70, 111, 229, 33, 23, 50, 255, 236, 173, 186, 114, 195, 155, 231, 188, + 140, 229, 187, 197, 247, 18, 107, 44, 67, 155, 58, 64, 0, 0, 0, 7, 215, 243, 216, 48, + 133, 75, 3, 197, 149, 83, 168, 150, 114, 90, 186, 70, 253, 177, 48, 225, 211, 142, 191, + 241, 13, 77, 252, 188, 202, 215, 228, 40, 226, 52, 125, 171, 215, 127, 195, 1, 133, 3, + 55, 38, 152, 124, 161, 200, 77, 29, 38, 158, 98, 147, 173, 205, 87, 50, 86, 244, 38, + 253, 251, 60, 0, 57, 43, 120, 125, 56, 168, 83, 209, 36, 5, 118, 52, 196, 60, 113, 51, + 198, 18, 70, 29, 116, 254, 177, 127, 66, 72, 21, 82, 134, 192, 90, 72, 243, 77, 170, + 80, 23, 118, 170, 39, 23, 58, 58, 106, 22, 11, 26, 111, 175, 251, 186, 179, 49, 60, 52, + 157, 46, 126, 243, 174, 139, 107, 91, 173, 150, 43, 91, 46, 211, 20, 76, 212, 62, 196, + 7, 39, 240, 9, 4, 65, 17, 249, 203, 197, 140, 181, 38, 196, 213, 83, 115, 120, 145, 11, + 94, 103, 100, 49, 70, 40, 205, 74, 224, 203, 66, 252, 113, 38, 143, 168, 244, 184, 32, + 23, 8, 184, 93, 133, 24, 57, 107, 236, 123, 117, 13, 177, 115, 140, 234, 18, 14, 113, + 230, 247, 22, 144, 89, 29, 2, 140, 149, 150, 43, 254, 247, 11, 251, 18, 99, 69, 131, + 32, 152, 113, 83, 125, 6, 8, 196, 54, 180, 68, 255, 57, 153, 93, 12, 42, 185, 242, 64, + 126, 36, 91, 71, 227, 19, 94, 244, 179, 157, 76, 97, 249, 91, 53, 39, 250, 133, 28, + 197, 116, 21, 173, 61, 163, 236, 185, 166, 242, 81, 61, 9, 179, 63, 76, 24, 114, 82, + 18, 182, 138, 185, 121, 251, 101, 108, 251, 132, 89, 201, 201, 238, 34, 115, 103, 121, + 227, 23, 147, 27, 162, 42, 67, 149, 80, 211, 223, 101, 182, 167, 128, 216, 67, 155, 21, + 245, 228, 13, 178, 54, 172, 119, 171, 72, 106, 157, 37, 107, 127, 172, 209, 12, 110, + 173, 6, 145, 14, 187, 127, 145, 195, 53, 103, 119, 182, 129, 49, 170, 8, 237, 99, 87, + 32, 152, 64, 4, 6, 0, 9, 3, 2, 0, 0, 0, 0, 0, 0, 0, 6, 0, 5, 1, 0, 0, 4, 0, 6, 0, 5, 2, + 192, 92, 21, 0, 9, 15, 2, 0, 3, 4, 5, 7, 8, 1, 10, 11, 12, 13, 14, 15, 16, 122, 52, 14, + 0, 0, 0, 88, 49, 0, 0, 12, 0, 0, 0, 248, 107, 1, 132, 119, 53, 148, 0, 132, 9, 61, 92, + 128, 148, 163, 222, 235, 37, 106, 70, 13, 34, 201, 224, 71, 134, 58, 94, 231, 159, 237, + 188, 62, 73, 128, 132, 52, 103, 185, 80, 130, 1, 2, 160, 244, 180, 133, 103, 74, 93, + 21, 159, 64, 57, 219, 13, 44, 152, 135, 226, 169, 32, 159, 38, 122, 70, 119, 143, 47, + 187, 8, 70, 187, 84, 246, 50, 160, 37, 44, 189, 121, 39, 163, 64, 35, 212, 96, 114, + 159, 112, 19, 137, 242, 122, 153, 40, 66, 91, 58, 177, 212, 56, 211, 173, 170, 83, 13, + 176, 85, + ]; + eprintln!("{}", hex::encode(bytes)); + // assert_eq!(true, false); + } + + #[test] + fn test_hex_encode_v0_tx() { + let bytes = [ + 1, 195, 51, 167, 150, 247, 55, 53, 248, 87, 145, 226, 107, 103, 143, 215, 85, 62, 100, + 128, 254, 136, 249, 2, 68, 10, 226, 181, 117, 197, 116, 123, 10, 25, 188, 7, 130, 56, + 16, 164, 148, 238, 144, 40, 1, 29, 213, 36, 243, 153, 42, 247, 46, 74, 245, 246, 187, + 202, 223, 137, 176, 212, 204, 198, 6, 128, 1, 0, 3, 4, 129, 250, 211, 63, 136, 192, + 175, 63, 138, 71, 161, 34, 135, 75, 55, 3, 149, 61, 84, 23, 252, 239, 203, 80, 170, + 175, 222, 166, 136, 217, 173, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 6, 70, 111, 229, 33, 23, 50, 255, 236, + 173, 186, 114, 195, 155, 231, 188, 140, 229, 187, 197, 247, 18, 107, 44, 67, 155, 58, + 64, 0, 0, 0, 60, 0, 57, 43, 120, 125, 56, 168, 83, 209, 36, 5, 118, 52, 196, 60, 113, + 51, 198, 18, 70, 29, 116, 254, 177, 127, 66, 72, 21, 82, 134, 192, 120, 25, 149, 73, + 158, 141, 39, 109, 12, 97, 90, 180, 212, 130, 149, 30, 62, 56, 197, 80, 116, 62, 58, 5, + 27, 10, 213, 206, 39, 141, 199, 83, 4, 2, 0, 9, 3, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 5, 1, + 0, 0, 4, 0, 2, 0, 5, 2, 192, 92, 21, 0, 3, 32, 24, 0, 29, 17, 1, 6, 28, 26, 33, 16, 18, + 31, 8, 12, 11, 25, 13, 32, 30, 15, 14, 4, 10, 22, 9, 27, 23, 21, 5, 19, 20, 7, 5, 51, + 29, 0, 0, 0, 1, 35, 227, 136, 54, 194, 46, 23, 104, 208, 155, 167, 222, 101, 18, 44, + 98, 220, 121, 194, 180, 176, 19, 46, 226, 47, 225, 188, 124, 123, 18, 197, 81, 26, 0, + 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 20, 21, 22, 24, 25, 26, 27, + 28, 29, 4, 2, 3, 18, 23, + ]; + eprintln!("{}", hex::encode(bytes)); + // assert_eq!(true, false); } } diff --git a/evm_loader/lib/src/solana_simulator/utils.rs b/evm_loader/lib/src/solana_simulator/utils.rs index 162a29ea2..d30dbefe2 100644 --- a/evm_loader/lib/src/solana_simulator/utils.rs +++ b/evm_loader/lib/src/solana_simulator/utils.rs @@ -1,8 +1,6 @@ use super::error::Error; -use solana_runtime::{ - bank::Bank, - genesis_utils::{create_genesis_config_with_leader_ex, GenesisConfigInfo}, -}; +use log::debug; +use solana_program_runtime::sysvar_cache::SysvarCache; use solana_sdk::{ account::Account, account_utils::StateMut, @@ -11,11 +9,7 @@ use solana_sdk::{ state::{AddressLookupTable, LookupTableMeta}, }, bpf_loader_upgradeable::{self, UpgradeableLoaderState}, - fee_calculator::DEFAULT_TARGET_LAMPORTS_PER_SIGNATURE, - native_token::sol_to_lamports, pubkey::Pubkey, - signature::Keypair, - signer::Signer, sysvar, }; @@ -27,54 +21,10 @@ pub enum SyncState { Yes, } -pub async fn genesis_config_info( +pub async fn sync_sysvar_accounts( rpc: &impl Rpc, - sync: SyncState, - mint_sol: f64, -) -> Result { - let rent = sysvar::rent::Rent::default(); - let fee_rate_governor = solana_sdk::fee_calculator::FeeRateGovernor { - // Initialize with a non-zero fee - lamports_per_signature: DEFAULT_TARGET_LAMPORTS_PER_SIGNATURE / 2, - ..solana_sdk::fee_calculator::FeeRateGovernor::default() - }; - let validator_pubkey = Pubkey::new_unique(); - let validator_stake_lamports = rent - .minimum_balance(solana_sdk::vote::state::VoteState::size_of()) - + sol_to_lamports(1_000_000.0); - - let mint_keypair = Keypair::new(); - let voting_keypair = Keypair::new(); - - let mut genesis_config = create_genesis_config_with_leader_ex( - sol_to_lamports(mint_sol), - &mint_keypair.pubkey(), - &validator_pubkey, - &voting_keypair.pubkey(), - &Pubkey::new_unique(), - validator_stake_lamports, - 42, - fee_rate_governor, - rent, - solana_sdk::genesis_config::ClusterType::Development, - vec![], - ); - - if sync == SyncState::Yes { - for feature in rpc.get_deactivated_solana_features().await? { - genesis_config.accounts.remove(&feature); - } - } - - Ok(GenesisConfigInfo { - genesis_config, - mint_keypair, - voting_keypair, - validator_pubkey, - }) -} - -pub async fn sync_sysvar_accounts(rpc: &impl Rpc, bank: &Bank) -> Result<(), Error> { + sysvar_cache: &mut SysvarCache, +) -> Result<(), Error> { let keys = sysvar::ALL_IDS.clone(); let accounts = rpc.get_multiple_accounts(&keys).await?; for (key, account) in keys.into_iter().zip(accounts) { @@ -87,57 +37,57 @@ pub async fn sync_sysvar_accounts(rpc: &impl Rpc, bank: &Bank) -> Result<(), Err use sysvar::clock::Clock; let clock: Clock = bincode::deserialize(&account.data)?; - bank.set_sysvar_for_tests(&clock); + sysvar_cache.set_clock(clock); + } + sysvar::epoch_rewards::ID => { + use sysvar::epoch_rewards::EpochRewards; + + let epoch_rewards: EpochRewards = bincode::deserialize(&account.data)?; + sysvar_cache.set_epoch_rewards(epoch_rewards); } sysvar::epoch_schedule::ID => { use sysvar::epoch_schedule::EpochSchedule; let epoch_schedule: EpochSchedule = bincode::deserialize(&account.data)?; - bank.set_sysvar_for_tests(&epoch_schedule); + sysvar_cache.set_epoch_schedule(epoch_schedule); } sysvar::rent::ID => { use sysvar::rent::Rent; let rent: Rent = bincode::deserialize(&account.data)?; - bank.set_sysvar_for_tests(&rent); - } - sysvar::rewards::ID => { - use sysvar::rewards::Rewards; - - let rewards: Rewards = bincode::deserialize(&account.data)?; - bank.set_sysvar_for_tests(&rewards); + sysvar_cache.set_rent(rent); } sysvar::slot_hashes::ID => { use sysvar::slot_hashes::SlotHashes; let slot_hashes: SlotHashes = bincode::deserialize(&account.data)?; - bank.set_sysvar_for_tests(&slot_hashes); - } - sysvar::slot_history::ID => { - use sysvar::slot_history::SlotHistory; - - let slot_history: SlotHistory = bincode::deserialize(&account.data)?; - bank.set_sysvar_for_tests(&slot_history); + sysvar_cache.set_slot_hashes(slot_hashes); } sysvar::stake_history::ID => { use sysvar::stake_history::StakeHistory; let stake_history: StakeHistory = bincode::deserialize(&account.data)?; - bank.set_sysvar_for_tests(&stake_history); + sysvar_cache.set_stake_history(stake_history); } #[allow(deprecated)] id if sysvar::fees::check_id(&id) => { use sysvar::fees::Fees; let fees: Fees = bincode::deserialize(&account.data)?; - bank.set_sysvar_for_tests(&fees); + sysvar_cache.set_fees(fees); + } + sysvar::last_restart_slot::ID => { + use sysvar::last_restart_slot::LastRestartSlot; + + let last_restart_slot: LastRestartSlot = bincode::deserialize(&account.data)?; + sysvar_cache.set_last_restart_slot(last_restart_slot); } #[allow(deprecated)] id if sysvar::recent_blockhashes::check_id(&id) => { use sysvar::recent_blockhashes::RecentBlockhashes; let recent_blockhashes: RecentBlockhashes = bincode::deserialize(&account.data)?; - bank.set_sysvar_for_tests(&recent_blockhashes); + sysvar_cache.set_recent_blockhashes(recent_blockhashes); } _ => {} } @@ -148,7 +98,7 @@ pub async fn sync_sysvar_accounts(rpc: &impl Rpc, bank: &Bank) -> Result<(), Err pub fn program_data_address(account: &Account) -> Result { assert!(account.executable); - assert!(account.owner == bpf_loader_upgradeable::id()); + assert_eq!(account.owner, bpf_loader_upgradeable::id()); let UpgradeableLoaderState::Program { programdata_address, @@ -162,27 +112,35 @@ pub fn program_data_address(account: &Account) -> Result { } pub fn reset_program_data_slot(account: &mut Account) -> Result<(), Error> { - assert!(account.owner == bpf_loader_upgradeable::id()); + assert_eq!(account.owner, bpf_loader_upgradeable::id()); let UpgradeableLoaderState::ProgramData { + slot, upgrade_authority_address, - .. } = account.state()? else { return Err(Error::ProgramAccountError); }; + debug!( + "slot_before_update: slot={slot} upgrade_authority_address={upgrade_authority_address:?}" + ); + let new_state = UpgradeableLoaderState::ProgramData { slot: 0, upgrade_authority_address, }; account.set_state(&new_state)?; + debug!( + "slot_after_update: slot={slot} upgrade_authority_address={upgrade_authority_address:?}" + ); + Ok(()) } pub fn reset_alt_slot(account: &mut Account) -> Result<(), Error> { - assert!(account.owner == address_lookup_table::program::id()); + assert_eq!(account.owner, address_lookup_table::program::id()); let lookup_table = AddressLookupTable::deserialize(&account.data)?; let metadata = LookupTableMeta { diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index 0a89c9dc8..105866610 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -1,10 +1,17 @@ pub mod tracer_ch_common; -mod tracer_ch_db; - +pub(crate) mod tracer_ch_db; pub mod tracer_rocks_db; + +use crate::commands::get_config::ChainInfo; use crate::tracing::TraceCallConfig; +use crate::types::tracer_ch_common::{EthSyncStatus, RevisionMap}; +pub use crate::types::tracer_ch_db::ClickHouseDb; +pub use crate::types::tracer_rocks_db::RocksDb; +use async_trait::async_trait; +use enum_dispatch::enum_dispatch; use ethnum::U256; +use evm_loader::solana_program::clock::{Slot, UnixTimestamp}; pub use evm_loader::types::Address; use evm_loader::types::{StorageKey, Transaction}; use evm_loader::{ @@ -14,12 +21,16 @@ use evm_loader::{ use serde::{Deserialize, Serialize}; use serde_with::skip_serializing_none; use serde_with::{hex::Hex, serde_as, DisplayFromStr, OneOrMany}; +use solana_sdk::signature::Signature; use solana_sdk::{account::Account, pubkey::Pubkey}; use std::collections::HashMap; -pub use tracer_rocks_db::RocksDb as TracerDb; - -use crate::commands::get_config::ChainInfo; +pub type DbResult = Result; +#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Default)] +pub struct DbConfig { + pub rocksdb_config: Option, + pub chdb_config: Option, +} #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Default)] pub struct ChDbConfig { pub clickhouse_url: Vec, @@ -33,6 +44,58 @@ pub struct RocksDbConfig { pub rocksdb_port: u16, } +#[enum_dispatch] +pub enum TracerDbType { + ClickHouseDb, + RocksDb, +} + +impl TracerDbType { + pub async fn from_config(db_config: &DbConfig) -> Self { + if let Some(rocksdb_config) = &db_config.rocksdb_config { + RocksDb::new(rocksdb_config).await.into() + } else { + ClickHouseDb::new(&db_config.clone().chdb_config.unwrap()).into() + } + } +} + +impl Clone for TracerDbType { + fn clone(&self) -> Self { + match self { + Self::RocksDb(r) => r.clone().into(), + Self::ClickHouseDb(c) => c.clone().into(), + } + } +} + +#[async_trait] +#[enum_dispatch(TracerDbType)] +pub trait TracerDb { + async fn get_block_time(&self, slot: Slot) -> DbResult; + + async fn get_earliest_rooted_slot(&self) -> DbResult; + + async fn get_latest_block(&self) -> DbResult; + + async fn get_account_at( + &self, + pubkey: &Pubkey, + slot: u64, + tx_index_in_block: Option, + ) -> DbResult>; + + async fn get_transaction_index(&self, signature: Signature) -> DbResult; + + async fn get_neon_revisions(&self, _pubkey: &Pubkey) -> DbResult; + + async fn get_neon_revision(&self, _slot: Slot, _pubkey: &Pubkey) -> DbResult; + + async fn get_slot_by_blockhash(&self, blockhash: String) -> DbResult; + + async fn get_sync_status(&self) -> DbResult; +} + #[serde_as] #[derive(Clone, Serialize, Deserialize, Debug)] pub struct AccessListItem { @@ -181,6 +244,7 @@ pub struct EmulateApiRequest { pub body: EmulateRequest, pub slot: Option, pub tx_index_in_block: Option, + pub id: Option, } #[derive(Deserialize, Serialize, Debug, Default, Copy, Clone, Eq, PartialEq)] @@ -209,6 +273,7 @@ pub struct GetBalanceRequest { #[serde_as(as = "OneOrMany<_>")] pub account: Vec, pub slot: Option, + pub id: Option, } #[serde_as] @@ -217,6 +282,7 @@ pub struct GetContractRequest { #[serde_as(as = "OneOrMany<_>")] pub contract: Vec
, pub slot: Option, + pub id: Option, } #[derive(Serialize, Deserialize, Debug, Default)] @@ -224,6 +290,7 @@ pub struct GetStorageAtRequest { pub contract: Address, pub index: U256, pub slot: Option, + pub id: Option, } #[derive(Deserialize, Serialize, Debug, Default)] @@ -256,6 +323,7 @@ pub struct GetHolderRequest { #[serde_as(as = "DisplayFromStr")] pub pubkey: Pubkey, pub slot: Option, + pub id: Option, } #[serde_as] @@ -269,6 +337,7 @@ pub struct SimulateSolanaRequest { pub blockhash: [u8; 32], #[serde_as(as = "Vec")] pub transactions: Vec>, + pub id: Option, } #[cfg(test)] diff --git a/evm_loader/lib/src/types/tracer_ch_common.rs b/evm_loader/lib/src/types/tracer_ch_common.rs index 16ab260e7..8e50def58 100644 --- a/evm_loader/lib/src/types/tracer_ch_common.rs +++ b/evm_loader/lib/src/types/tracer_ch_common.rs @@ -75,7 +75,7 @@ pub struct AccountRow { impl fmt::Debug for AccountRow { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut debug_struct = f.debug_struct("Account"); + let mut debug_struct = f.debug_struct("AccountRow"); debug_struct .field("owner", &bs58::encode(&self.owner).into_string()) diff --git a/evm_loader/lib/src/types/tracer_ch_db.rs b/evm_loader/lib/src/types/tracer_ch_db.rs index 4ef60f751..b8d823be9 100644 --- a/evm_loader/lib/src/types/tracer_ch_db.rs +++ b/evm_loader/lib/src/types/tracer_ch_db.rs @@ -2,14 +2,18 @@ use crate::{ commands::get_neon_elf::get_elf_parameter, types::tracer_ch_common::{AccountRow, ChError, RevisionRow, SlotParent, ROOT_BLOCK_DELAY}, + types::{DbResult, TracerDb}, }; use super::tracer_ch_common::{ChResult, EthSyncStatus, EthSyncing, RevisionMap, SlotParentRooted}; use crate::types::ChDbConfig; +use anyhow::anyhow; +use async_trait::async_trait; use clickhouse::Client; use log::{debug, error, info}; use rand::Rng; +use solana_sdk::signature::Signature; use solana_sdk::{ account::Account, clock::{Slot, UnixTimestamp}, @@ -29,25 +33,10 @@ pub struct ClickHouseDb { } #[allow(dead_code)] -impl ClickHouseDb { - pub fn new(config: &ChDbConfig) -> Self { - let url_id = rand::thread_rng().gen_range(0..config.clickhouse_url.len()); - let url = config.clickhouse_url.get(url_id).unwrap(); - - let client = match (&config.clickhouse_user, &config.clickhouse_password) { - (None, None | Some(_)) => Client::default().with_url(url), - (Some(user), None) => Client::default().with_url(url).with_user(user), - (Some(user), Some(password)) => Client::default() - .with_url(url) - .with_user(user) - .with_password(password), - }; - - Self { client } - } - +#[async_trait] +impl TracerDb for ClickHouseDb { // Returned value is not used for tracer methods. - pub async fn get_block_time(&self, slot: Slot) -> ChResult { + async fn get_block_time(&self, slot: Slot) -> DbResult { let time_start = Instant::now(); let query = "SELECT JSONExtractInt(notify_block_json, 'block_time') FROM events.notify_block_distributed WHERE slot = ? LIMIT 1"; @@ -66,7 +55,7 @@ impl ClickHouseDb { result } - pub async fn get_earliest_rooted_slot(&self) -> ChResult { + async fn get_earliest_rooted_slot(&self) -> DbResult { let time_start = Instant::now(); let query = "SELECT min(slot) FROM events.rooted_slots"; let result = self @@ -83,7 +72,7 @@ impl ClickHouseDb { result } - pub async fn get_latest_block(&self) -> ChResult { + async fn get_latest_block(&self) -> DbResult { let time_start = Instant::now(); let query = "SELECT max(slot) FROM events.update_slot"; let result = self @@ -100,6 +89,202 @@ impl ClickHouseDb { result } + async fn get_account_at( + &self, + pubkey: &Pubkey, + slot: u64, + tx_index_in_block: Option, + ) -> DbResult> { + if let Some(tx_index_in_block) = tx_index_in_block { + return if let Some(account) = self + .get_account_at_index_in_block(pubkey, slot, tx_index_in_block) + .await? + { + Ok(Some(account)) + } else { + self.get_account_at_slot(pubkey, slot - 1) + .await + .map_err(|e| anyhow!("Failed to get NEON_REVISION, error: {e}")) + }; + } + + self.get_account_at_slot(pubkey, slot) + .await + .map_err(|e| anyhow!("Failed to get NEON_REVISION, error: {e}")) + } + + async fn get_transaction_index(&self, signature: Signature) -> DbResult { + let query = r" + SELECT idx + FROM events.notify_transaction_distributed + WHERE signature = ? + LIMIT 1 + "; + self.client + .query(query) + .bind(format!("{:?}", signature.as_ref())) + .fetch_one::() + .await + .map_err(Into::into) + } + + async fn get_neon_revisions(&self, pubkey: &Pubkey) -> DbResult { + let query = r"SELECT slot, data + FROM events.update_account_distributed + WHERE + pubkey = ? + ORDER BY + slot ASC, + write_version ASC"; + + let pubkey_str = format!("{:?}", pubkey.to_bytes()); + let rows: Vec = self + .client + .query(query) + .bind(pubkey_str) + .fetch_all() + .await?; + + let mut results: Vec<(u64, String)> = Vec::new(); + + for row in rows { + let neon_revision = get_elf_parameter(&row.data, "NEON_REVISION").map_err(|e| { + anyhow!(ChError::Db(clickhouse::error::Error::Custom(format!( + "Failed to get NEON_REVISION, error: {e}", + )))) + })?; + results.push((row.slot, neon_revision)); + } + let ranges = RevisionMap::build_ranges(&results); + + Ok(RevisionMap::new(ranges)) + } + + async fn get_neon_revision(&self, slot: Slot, pubkey: &Pubkey) -> DbResult { + let query = r"SELECT data + FROM events.update_account_distributed + WHERE + pubkey = ? AND slot <= ? + ORDER BY + pubkey ASC, + slot ASC, + write_version ASC + LIMIT 1 + "; + + let pubkey_str = format!("{:?}", pubkey.to_bytes()); + + let data = Self::row_opt( + self.client + .query(query) + .bind(pubkey_str) + .bind(slot) + .fetch_one::>() + .await, + )?; + if let Some(data) = data { + let neon_revision = + get_elf_parameter(data.as_slice(), "NEON_REVISION").map_err(|e| { + ChError::Db(clickhouse::error::Error::Custom(format!( + "Failed to get NEON_REVISION, error: {e:?}", + ))) + })?; + Ok(neon_revision) + } else { + let err = clickhouse::error::Error::Custom(format!( + "get_neon_revision: for slot {slot} and pubkey {pubkey} not found", + )); + Err(anyhow!(ChError::Db(err))) + } + } + + async fn get_slot_by_blockhash(&self, blockhash: String) -> DbResult { + let query = r"SELECT slot + FROM events.notify_block_distributed + WHERE hash = ? + LIMIT 1 + "; + + let slot = Self::row_opt( + self.client + .query(query) + .bind(blockhash) + .fetch_one::() + .await, + )?; + slot.map_or_else( + || { + Err(anyhow!(ChError::Db(clickhouse::error::Error::Custom( + "get_slot_by_blockhash: no data available".to_string(), + )))) + }, + Ok, + ) + } + + async fn get_sync_status(&self) -> DbResult { + let query_is_startup = r"SELECT is_startup + FROM events.update_account_distributed + WHERE slot = ( + SELECT MAX(slot) + FROM events.update_account_distributed + ) + LIMIT 1 + "; + + let is_startup = Self::row_opt( + self.client + .query(query_is_startup) + .fetch_one::() + .await, + )?; + + if is_startup == Some(true) { + let query = r"SELECT slot + FROM ( + (SELECT MIN(slot) as slot FROM events.notify_block_distributed) + UNION ALL + (SELECT MAX(slot) as slot FROM events.notify_block_distributed) + UNION ALL + (SELECT MAX(slot) as slot FROM events.notify_block_distributed) + ) + ORDER BY slot ASC + "; + + let data = Self::row_opt(self.client.query(query).fetch_one::().await)?; + + return data.map_or_else( + || { + Err(anyhow!(ChError::Db(clickhouse::error::Error::Custom( + "get_sync_status: no data available".to_string(), + )))) + }, + |data| Ok(EthSyncStatus::new(Some(data))), + ); + } + + Ok(EthSyncStatus::new(None)) + } +} + +impl ClickHouseDb { + #[must_use] + pub fn new(config: &ChDbConfig) -> Self { + let url_id = rand::thread_rng().gen_range(0..config.clickhouse_url.len()); + let url = config.clickhouse_url.get(url_id).unwrap(); + + let client = match (&config.clickhouse_user, &config.clickhouse_password) { + (None, None | Some(_)) => Client::default().with_url(url), + (Some(user), None) => Client::default().with_url(url).with_user(user), + (Some(user), Some(password)) => Client::default() + .with_url(url) + .with_user(user) + .with_password(password), + }; + + Self { client } + } + async fn get_branch_slots(&self, slot: Option) -> ChResult<(u64, Vec)> { fn branch_from( rows: Vec, @@ -123,7 +308,7 @@ impl ClickHouseDb { info!("get_branch_slots {{ slot: {slot:?} }}"); - let query = r#" + let query = r" SELECT DISTINCT ON (slot, parent) slot, parent, status FROM events.update_slot WHERE slot >= ( @@ -134,7 +319,7 @@ impl ClickHouseDb { ) AND isNotNull(parent) ORDER BY slot DESC, status DESC - "#; + "; let time_start = Instant::now(); let mut rows = self .client @@ -184,7 +369,7 @@ impl ClickHouseDb { async fn get_account_rooted_slot(&self, key: &str, slot: u64) -> ChResult> { info!("get_account_rooted_slot {{ key: {key}, slot: {slot} }}"); - let query = r#" + let query = r" SELECT DISTINCT uad.slot FROM events.update_account_distributed AS uad WHERE uad.pubkey = ? @@ -196,7 +381,7 @@ impl ClickHouseDb { ) >= 1 ORDER BY uad.slot DESC LIMIT 1 - "#; + "; let time_start = Instant::now(); let slot_opt = Self::row_opt( @@ -218,26 +403,6 @@ impl ClickHouseDb { Ok(slot_opt) } - pub async fn get_account_at( - &self, - pubkey: &Pubkey, - slot: u64, - tx_index_in_block: Option, - ) -> ChResult> { - if let Some(tx_index_in_block) = tx_index_in_block { - return if let Some(account) = self - .get_account_at_index_in_block(pubkey, slot, tx_index_in_block) - .await? - { - Ok(Some(account)) - } else { - self.get_account_at_slot(pubkey, slot - 1).await - }; - } - - self.get_account_at_slot(pubkey, slot).await - } - async fn get_account_at_slot( &self, pubkey: &Pubkey, @@ -265,14 +430,14 @@ impl ClickHouseDb { let mut row = if branch.is_empty() { None } else { - let query = r#" + let query = r" SELECT owner, lamports, executable, rent_epoch, data, txn_signature FROM events.update_account_distributed WHERE pubkey = ? AND slot IN ? ORDER BY pubkey, slot DESC, write_version DESC LIMIT 1 - "#; + "; let time_start = Instant::now(); let row = Self::row_opt( @@ -326,7 +491,7 @@ impl ClickHouseDb { "get_account_at_index_in_block {{ pubkey: {pubkey}, slot: {slot}, tx_index_in_block: {tx_index_in_block} }}" ); - let query = r#" + let query = r" SELECT owner, lamports, executable, rent_epoch, data, txn_signature FROM events.update_account_distributed WHERE pubkey = ? @@ -334,7 +499,7 @@ impl ClickHouseDb { AND write_version <= ? ORDER BY write_version DESC LIMIT 1 - "#; + "; let time_start = Instant::now(); @@ -369,13 +534,13 @@ impl ClickHouseDb { pubkey: &str, slot: u64, ) -> ChResult> { - let query = r#" + let query = r" SELECT owner, lamports, executable, rent_epoch, data, txn_signature FROM events.older_account_distributed FINAL WHERE pubkey = ? AND slot <= ? ORDER BY slot DESC LIMIT 1 - "#; + "; Self::row_opt( self.client .query(query) @@ -391,7 +556,7 @@ impl ClickHouseDb { } async fn get_sol_sig_rooted_slot(&self, sol_sig: &[u8; 64]) -> ChResult> { - let query = r#" + let query = r" SELECT slot, parent FROM events.rooted_slots WHERE slot IN ( @@ -401,7 +566,7 @@ impl ClickHouseDb { ) ORDER BY slot DESC LIMIT 1 - "#; + "; Self::row_opt( self.client @@ -419,7 +584,7 @@ impl ClickHouseDb { async fn get_sol_sig_confirmed_slot(&self, sol_sig: &[u8; 64]) -> ChResult> { let (_, slot_vec) = self.get_branch_slots(None).await?; - let query = r#" + let query = r" SELECT slot, parent, status FROM events.update_slot WHERE slot IN ? @@ -430,7 +595,7 @@ impl ClickHouseDb { ) ORDER BY slot DESC LIMIT 1 - "#; + "; Self::row_opt( self.client @@ -451,7 +616,7 @@ impl ClickHouseDb { &self, pubkey: &Pubkey, sol_sig: &[u8; 64], - ) -> ChResult> { + ) -> DbResult> { let sol_sig_str = bs58::encode(sol_sig).into_string(); info!("get_account_by_sol_sig {{ pubkey: {pubkey}, sol_sig: {sol_sig_str} }}"); let time_start = Instant::now(); @@ -477,13 +642,13 @@ impl ClickHouseDb { }; // Try to find account changes within the given slot. - let query = r#" + let query = r" SELECT DISTINCT ON (pubkey, txn_signature, write_version) owner, lamports, executable, rent_epoch, data, txn_signature FROM events.update_account_distributed WHERE slot = ? AND pubkey = ? ORDER BY write_version DESC - "#; + "; let pubkey_str = format!("{:?}", pubkey.to_bytes()); let time_start = Instant::now(); @@ -525,7 +690,7 @@ impl ClickHouseDb { return row_found .map(|row| { row.try_into() - .map_err(|err| ChError::Db(clickhouse::error::Error::Custom(err))) + .map_err(|err| anyhow!(ChError::Db(clickhouse::error::Error::Custom(err)))) }) .transpose(); } @@ -538,144 +703,6 @@ impl ClickHouseDb { } } - pub async fn get_neon_revision(&self, slot: Slot, pubkey: &Pubkey) -> ChResult { - let query = r#"SELECT data - FROM events.update_account_distributed - WHERE - pubkey = ? AND slot <= ? - ORDER BY - pubkey ASC, - slot ASC, - write_version ASC - LIMIT 1 - "#; - - let pubkey_str = format!("{:?}", pubkey.to_bytes()); - - let data = Self::row_opt( - self.client - .query(query) - .bind(pubkey_str) - .bind(slot) - .fetch_one::>() - .await, - )?; - if let Some(data) = data { - let neon_revision = - get_elf_parameter(data.as_slice(), "NEON_REVISION").map_err(|e| { - ChError::Db(clickhouse::error::Error::Custom(format!( - "Failed to get NEON_REVISION, error: {e:?}", - ))) - })?; - Ok(neon_revision) - } else { - let err = clickhouse::error::Error::Custom(format!( - "get_neon_revision: for slot {slot} and pubkey {pubkey} not found", - )); - Err(ChError::Db(err)) - } - } - - pub async fn get_neon_revisions(&self, pubkey: &Pubkey) -> ChResult { - let query = r#"SELECT slot, data - FROM events.update_account_distributed - WHERE - pubkey = ? - ORDER BY - slot ASC, - write_version ASC"#; - - let pubkey_str = format!("{:?}", pubkey.to_bytes()); - let rows: Vec = self - .client - .query(query) - .bind(pubkey_str) - .fetch_all() - .await?; - - let mut results: Vec<(u64, String)> = Vec::new(); - - for row in rows { - let neon_revision = get_elf_parameter(&row.data, "NEON_REVISION").map_err(|e| { - ChError::Db(clickhouse::error::Error::Custom(format!( - "Failed to get NEON_REVISION, error: {e}", - ))) - })?; - results.push((row.slot, neon_revision)); - } - let ranges = RevisionMap::build_ranges(&results); - - Ok(RevisionMap::new(ranges)) - } - - pub async fn get_slot_by_blockhash(&self, blockhash: &str) -> ChResult { - let query = r#"SELECT slot - FROM events.notify_block_distributed - WHERE hash = ? - LIMIT 1 - "#; - - let slot = Self::row_opt( - self.client - .query(query) - .bind(blockhash) - .fetch_one::() - .await, - )?; - slot.map_or_else( - || { - Err(ChError::Db(clickhouse::error::Error::Custom( - "get_slot_by_blockhash: no data available".to_string(), - ))) - }, - Ok, - ) - } - - pub async fn get_sync_status(&self) -> ChResult { - let query_is_startup = r#"SELECT is_startup - FROM events.update_account_distributed - WHERE slot = ( - SELECT MAX(slot) - FROM events.update_account_distributed - ) - LIMIT 1 - "#; - - let is_startup = Self::row_opt( - self.client - .query(query_is_startup) - .fetch_one::() - .await, - )?; - - if is_startup == Some(true) { - let query = r#"SELECT slot - FROM ( - (SELECT MIN(slot) as slot FROM events.notify_block_distributed) - UNION ALL - (SELECT MAX(slot) as slot FROM events.notify_block_distributed) - UNION ALL - (SELECT MAX(slot) as slot FROM events.notify_block_distributed) - ) - ORDER BY slot ASC - "#; - - let data = Self::row_opt(self.client.query(query).fetch_one::().await)?; - - return data.map_or_else( - || { - Err(ChError::Db(clickhouse::error::Error::Custom( - "get_sync_status: no data available".to_string(), - ))) - }, - |data| Ok(EthSyncStatus::new(Some(data))), - ); - } - - Ok(EthSyncStatus::new(None)) - } - fn row_opt(result: clickhouse::error::Result) -> clickhouse::error::Result> { match result { Ok(row) => Ok(Some(row)), diff --git a/evm_loader/lib/src/types/tracer_rocks_db.rs b/evm_loader/lib/src/types/tracer_rocks_db.rs index 01177cca6..f8ab52cf5 100644 --- a/evm_loader/lib/src/types/tracer_rocks_db.rs +++ b/evm_loader/lib/src/types/tracer_rocks_db.rs @@ -1,19 +1,19 @@ use abi_stable::traits::IntoOwned; +use async_trait::async_trait; use jsonrpsee::core::client::ClientT; use jsonrpsee::core::Serialize; use jsonrpsee::rpc_params; use jsonrpsee::ws_client::{WsClient, WsClientBuilder}; -use serde_json::{from_slice, from_str}; -use std::str::FromStr; -use std::sync::Arc; - -pub type RocksDbResult = std::result::Result; +use serde_json::from_str; use solana_sdk::signature::Signature; use solana_sdk::{ account::Account, clock::{Slot, UnixTimestamp}, pubkey::Pubkey, }; +use std::env; +use std::str::FromStr; +use std::sync::Arc; use tracing::info; #[derive(Clone, Serialize)] @@ -24,14 +24,13 @@ pub struct AccountParams { } use crate::types::tracer_ch_common::{EthSyncStatus, RevisionMap}; -use crate::types::RocksDbConfig; - +use crate::types::{DbResult, RocksDbConfig, TracerDb}; // use reconnecting_jsonrpsee_ws_client::{Client, CallRetryPolicy, rpc_params, ExponentialBackoff}; - -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct RocksDb { - pub url: String, - pub client: Arc, + #[allow(dead_code)] + url: String, + client: Arc, } impl RocksDb { @@ -55,44 +54,46 @@ impl RocksDb { Err(e) => panic!("Couln't start rocksDb client at {url}: {e}"), } } +} - pub async fn get_block_time(&self, slot: Slot) -> RocksDbResult { +#[async_trait] +impl TracerDb for RocksDb { + async fn get_block_time(&self, slot: Slot) -> DbResult { let response: String = self .client .request("get_block_time", rpc_params![slot]) .await?; - tracing::info!( + info!( "get_block_time for slot {:?} response: {:?}", - slot, - response + slot, response ); Ok(i64::from_str(response.as_str())?) } - pub async fn get_earliest_rooted_slot(&self) -> RocksDbResult { + async fn get_earliest_rooted_slot(&self) -> DbResult { let response: String = self .client .request("get_earliest_rooted_slot", rpc_params![]) .await?; - tracing::info!("get_earliest_rooted_slot response: {:?}", response); + info!("get_earliest_rooted_slot response: {:?}", response); Ok(u64::from_str(response.as_str())?) } - pub async fn get_latest_block(&self) -> RocksDbResult { + async fn get_latest_block(&self) -> DbResult { let response: String = self .client .request("get_last_rooted_slot", rpc_params![]) .await?; - tracing::info!("get_latest_block response: {:?}", response); + info!("get_latest_block response: {:?}", response); Ok(u64::from_str(response.as_str())?) } - pub async fn get_account_at( + async fn get_account_at( &self, pubkey: &Pubkey, slot: u64, tx_index_in_block: Option, - ) -> RocksDbResult> { + ) -> DbResult> { info!("get_account_at {pubkey:?}, slot: {slot:?}, tx_index: {tx_index_in_block:?}"); let response: String = self @@ -104,56 +105,47 @@ impl RocksDb { .await?; let account = from_str::>(response.as_str())?; - if let Some(account) = &account { - info!("Got Account by {pubkey:?} owner: {:?} lamports: {:?} executable: {:?} rent_epoch: {:?}", account.owner, account.lamports, account.executable, account.rent_epoch); - } else { + account.as_ref().map_or_else(|| { info!("Got None for Account by {pubkey:?}"); - } + }, |account| { + info!("Got Account by {pubkey:?} owner: {:?} lamports: {:?} executable: {:?} rent_epoch: {:?}", account.owner, account.lamports, account.executable, account.rent_epoch); + }); + Ok(account) } - pub async fn get_transaction_index(&self, signature: Signature) -> RocksDbResult { + async fn get_transaction_index(&self, signature: Signature) -> DbResult { let response: String = self .client .request("get_transaction_index", rpc_params![signature]) .await?; - println!("get_transaction_index response: {:?}", response); + info!("get_transaction_index response: {:?}", response); Ok(u64::from_str(response.as_str())?) } - pub async fn get_accounts(&self, start: u64, end: u64) -> RocksDbResult>> { - let response: String = self - .client - .request("get_accounts", rpc_params![start, end]) - .await?; - tracing::info!("get_accounts response: {:?}", response); - let accounts: Vec> = from_slice((response).as_ref()).unwrap(); - Ok(accounts) - } - - // TODO: Implement - // These are used by Tracer directly and eventually need to be implemented + async fn get_neon_revisions(&self, _pubkey: &Pubkey) -> DbResult { + let revision = env::var("NEON_REVISION").expect("NEON_REVISION should be set"); - pub async fn get_neon_revisions(&self, _pubkey: &Pubkey) -> RocksDbResult { - let revision = env!("NEON_REVISION").to_string(); + info!("get_neon_revisions for {revision:?}"); let ranges = vec![(1, 100_000, revision)]; Ok(RevisionMap::new(ranges)) } - pub async fn get_neon_revision(&self, _slot: Slot, _pubkey: &Pubkey) -> RocksDbResult { + async fn get_neon_revision(&self, slot: Slot, pubkey: &Pubkey) -> DbResult { + info!("get_neon_revision for {slot:?}, pubkey: {pubkey:?}"); Ok(env!("NEON_REVISION").to_string()) } - pub async fn get_slot_by_blockhash(&self, blockhash: String) -> RocksDbResult> { + async fn get_slot_by_blockhash(&self, blockhash: String) -> DbResult { let response: String = self .client .request("get_slot_by_blockhash", rpc_params![blockhash]) .await?; - tracing::info!("response: {:?}", response); + info!("response: {:?}", response); Ok(from_str(response.as_str())?) } - pub async fn get_sync_status(&self) -> RocksDbResult { + async fn get_sync_status(&self) -> DbResult { Ok(EthSyncStatus::new(None)) } } diff --git a/evm_loader/program-macro/src/config_parser.rs b/evm_loader/program-macro/src/config_parser.rs index 51848ae8f..62a05f15e 100644 --- a/evm_loader/program-macro/src/config_parser.rs +++ b/evm_loader/program-macro/src/config_parser.rs @@ -17,6 +17,7 @@ pub struct NetSpecificConfig { pub neon_chain_id: u64, pub neon_token_mint: String, pub chains: Vec, + pub no_update_tracking_owners: Vec, } impl Parse for NetSpecificConfig { @@ -38,6 +39,13 @@ impl Parse for NetSpecificConfig { .map(|v| v.as_str().unwrap().to_string()) .collect::>(); + let no_update_tracking_owners = root["no_update_tracking_owners"] + .as_array() + .unwrap() + .iter() + .map(|v| v.as_str().unwrap().to_string()) + .collect::>(); + let chains = root["chain"] .as_table() .unwrap() @@ -69,6 +77,7 @@ impl Parse for NetSpecificConfig { neon_chain_id, neon_token_mint, chains, + no_update_tracking_owners, }) } } @@ -138,7 +147,7 @@ impl Parse for CommonConfig { r#type: Type::Verbatim(quote!(bool)), value: Lit::Bool(LitBool::new(v, input.span())), }), - toml::Value::Array(ref array) => match (array.get(0), array.get(1)) { + toml::Value::Array(ref array) => match (array.first(), array.get(1)) { (Some(toml::Value::Integer(v)), Some(toml::Value::String(t))) => { let s = v.to_string(); let v: LitInt = parse_str(&s)?; diff --git a/evm_loader/program-macro/src/lib.rs b/evm_loader/program-macro/src/lib.rs index ec3b5c5c0..0eb1337fc 100644 --- a/evm_loader/program-macro/src/lib.rs +++ b/evm_loader/program-macro/src/lib.rs @@ -66,6 +66,7 @@ pub fn net_specific_config_parser(tokens: TokenStream) -> TokenStream { neon_chain_id, neon_token_mint, operators_whitelist, + no_update_tracking_owners, mut chains, } = parse_macro_input!(tokens as NetSpecificConfig); @@ -77,6 +78,14 @@ pub fn net_specific_config_parser(tokens: TokenStream) -> TokenStream { operators.sort_unstable(); let operators_len = operators.len(); + let mut no_update_tracking_owners: Vec> = no_update_tracking_owners + .iter() + .map(|key| bs58::decode(key).into_vec().unwrap()) + .collect(); + + no_update_tracking_owners.sort_unstable(); + let no_update_tracking_owners_len = no_update_tracking_owners.len(); + chains.sort_unstable_by_key(|c| c.id); let chains_len = chains.len(); @@ -100,6 +109,10 @@ pub fn net_specific_config_parser(tokens: TokenStream) -> TokenStream { #(::solana_program::pubkey::Pubkey::new_from_array([#((#operators),)*]),)* ]; + pub const NO_UPDATE_TRACKING_OWNERS: [::solana_program::pubkey::Pubkey; #no_update_tracking_owners_len] = [ + #(::solana_program::pubkey::Pubkey::new_from_array([#((#no_update_tracking_owners),)*]),)* + ]; + pub const CHAIN_ID_LIST: [(u64, &str, ::solana_program::pubkey::Pubkey); #chains_len] = [ #( (#chain_ids, #chain_names, ::solana_program::pubkey::Pubkey::new_from_array([#(#chain_tokens),*])) ),* ]; diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index be5e52a87..072e93d3a 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -1,4 +1,4 @@ -# Note: This crate must be built using cargo build-bpf +# Note: This crate must be built using cargo build-sbf [package] name = "evm-loader" @@ -44,8 +44,8 @@ spl-token = { version = "~4.0", default-features = false, features = ["no-entryp spl-associated-token-account = { version = "~2.3", default-features = false, features = ["no-entrypoint"] } mpl-token-metadata = { version = "~4.1", default-features = false } thiserror = "1.0" -arrayref = "0.3.6" -hex = "0.4.2" +arrayref = "0.3.8" +hex = "0.4.3" ripemd = "0.1" rlp = "0.5" static_assertions = "1" @@ -57,14 +57,14 @@ ethnum = { version = "1.5", default-features = false, features = ["serde"] } cfg-if = { version = "1.0" } log = { version = "0.4", default-features = false, optional = true } maybe-async = "0.2.10" -async-trait = { version = "0.1.80", optional = true } +async-trait = { version = "0.1.81", optional = true } [target.'cfg(target_os = "solana")'.dependencies.maybe-async] -version = "0.2.7" +version = "0.2.10" features = ["is_sync"] [dev-dependencies] -tokio = { version = "1.0", features = ["full"] } +tokio = { version = "1.38", features = ["full"] } serde_json = { version = "1.0.120", features = ["preserve_order"] } solana-sdk.workspace = true diff --git a/evm_loader/program/config/default.toml b/evm_loader/program/config/default.toml index 986667357..5939e4b37 100644 --- a/evm_loader/program/config/default.toml +++ b/evm_loader/program/config/default.toml @@ -1,4 +1,7 @@ program_id = "53DfF883gyixYNXnM7s5xhdeyV8mVk9T4i2hGV9vG9io" + +no_update_tracking_owners = [] + operators_whitelist = [ "9kPRbbwKL5SYELF4cZqWWFmP88QkKys51DoaUBx8eK73", "BMp6gEnveANdvSvspESJUrNczuHz1GF5UQKjVLCkAZih", diff --git a/evm_loader/program/config/devnet.toml b/evm_loader/program/config/devnet.toml index 00f47003c..06761ba8b 100644 --- a/evm_loader/program/config/devnet.toml +++ b/evm_loader/program/config/devnet.toml @@ -1,4 +1,11 @@ program_id = "eeLSJgWzzxrqKv1UxtRVVH8FX3qCQWUs9QuAjJpETGU" + +no_update_tracking_owners = [ + "HEvSKofvBgfaexv23kMabbYqxasxU3mQ4ibBMEmJWHny", # Chainlink oracle + "rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ", # Pyth oracle + "gSbePebfvPy7tRqimPoVecS2UsBvYv46ynrzWocc92s", # Pyth legacy oracle +] + operators_whitelist = [ "NeoQM3utcHGxhKT41Nq81g8t4xGcPNFpkAgYj1N2N8v", "Gw3Xiwve6HdvpJeQguhwT23cpK9nRjSy1NpNYCFY4XU9", diff --git a/evm_loader/program/config/govertest.toml b/evm_loader/program/config/govertest.toml index c9fe2df8b..cce68f0b8 100644 --- a/evm_loader/program/config/govertest.toml +++ b/evm_loader/program/config/govertest.toml @@ -1,4 +1,7 @@ program_id = "53DfF883gyixYNXnM7s5xhdeyV8mVk9T4i2hGV9vG9io" + +no_update_tracking_owners = [] + operators_whitelist = [ "9kPRbbwKL5SYELF4cZqWWFmP88QkKys51DoaUBx8eK73", "BMp6gEnveANdvSvspESJUrNczuHz1GF5UQKjVLCkAZih", diff --git a/evm_loader/program/config/mainnet.toml b/evm_loader/program/config/mainnet.toml index e3660baf9..b037c0165 100644 --- a/evm_loader/program/config/mainnet.toml +++ b/evm_loader/program/config/mainnet.toml @@ -1,4 +1,11 @@ program_id = "NeonVMyRX5GbCrsAHnUwx1nYYoJAtskU1bWUo6JGNyG" + +no_update_tracking_owners = [ + "HEvSKofvBgfaexv23kMabbYqxasxU3mQ4ibBMEmJWHny", # Chainlink oracle + "rec5EKMGg6MxZYaMdyBfgwp4d5rB9T1VQH5pJv5LtFJ", # Pyth oracle + "FsJ3A3u2vn5cTVofAjvy6y5kwABJAqYWpe4975bi2epH", # Pyth legacy oracle +] + operators_whitelist = [ "NeonPQFrw5stVvs1rFLDxALWUBDCnSPsWBP83RfNUKK", "GYt9w8MaXztDLhhsxmQr7Ar9FJ6MmaFwav7qBrxZKwhd", diff --git a/evm_loader/program/config/rollup.toml b/evm_loader/program/config/rollup.toml index 93bf2290d..b19446e01 100644 --- a/evm_loader/program/config/rollup.toml +++ b/evm_loader/program/config/rollup.toml @@ -1,4 +1,7 @@ program_id = "EgbRZxFRQTiZpQGinE5jT6KQq5jtVnjtLdSTkW5UTcAv" + +no_update_tracking_owners = [] + operators_whitelist = [ "2Gsipy7yniskehFAccTp4ShhmdTiP8UsLWVFdxsG6ZGt", "2fx77qnumM3sw5duzMYod8c8xSLavE4RwJAdNdeYZpFq", diff --git a/evm_loader/program/config/testnet.toml b/evm_loader/program/config/testnet.toml index 8e22e1371..ef01514c7 100644 --- a/evm_loader/program/config/testnet.toml +++ b/evm_loader/program/config/testnet.toml @@ -1,4 +1,7 @@ program_id = "eeLSJgWzzxrqKv1UxtRVVH8FX3qCQWUs9QuAjJpETGU" + +no_update_tracking_owners = [] + operators_whitelist = [ "NeoQM3utcHGxhKT41Nq81g8t4xGcPNFpkAgYj1N2N8v", "Gw3Xiwve6HdvpJeQguhwT23cpK9nRjSy1NpNYCFY4XU9", diff --git a/evm_loader/program/src/account/mod.rs b/evm_loader/program/src/account/mod.rs index 134262179..bd55d2019 100644 --- a/evm_loader/program/src/account/mod.rs +++ b/evm_loader/program/src/account/mod.rs @@ -285,6 +285,7 @@ impl<'a> AccountsDB<'a> { } } +#[allow(clippy::into_iter_without_iter)] impl<'a, 'r> IntoIterator for &'r AccountsDB<'a> { type Item = &'r AccountInfo<'a>; type IntoIter = std::slice::Iter<'r, AccountInfo<'a>>; diff --git a/evm_loader/program/src/account/state.rs b/evm_loader/program/src/account/state.rs index f02ba689b..8ff3a1f90 100644 --- a/evm_loader/program/src/account/state.rs +++ b/evm_loader/program/src/account/state.rs @@ -11,6 +11,7 @@ use crate::types::serde::bytes_32; use crate::types::{Address, Transaction}; use ethnum::U256; use serde::{Deserialize, Serialize}; +use solana_program::hash::Hash; use solana_program::system_program; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; @@ -35,6 +36,13 @@ enum AccountRevision { impl AccountRevision { pub fn new(program_id: &Pubkey, info: &AccountInfo) -> Self { if (info.owner != program_id) && !system_program::check_id(info.owner) { + if crate::config::NO_UPDATE_TRACKING_OWNERS + .binary_search(info.owner) + .is_ok() + { + return AccountRevision::Hash(Hash::default().to_bytes()); + } + let hash = solana_program::hash::hashv(&[ info.owner.as_ref(), &info.lamports().to_le_bytes(), @@ -80,6 +88,7 @@ struct Data { pub steps_executed: u64, } +#[allow(clippy::struct_field_names)] #[repr(C, packed)] struct Header { pub evm_state_len: usize, diff --git a/evm_loader/rpc-client/Cargo.toml b/evm_loader/rpc-client/Cargo.toml index 5b659978a..d1d693393 100644 --- a/evm_loader/rpc-client/Cargo.toml +++ b/evm_loader/rpc-client/Cargo.toml @@ -9,11 +9,11 @@ edition = "2021" serde = "1.0.204" serde_json = "1.0.120" neon-lib = { path = "../lib" } -thiserror = "1.0.62" -async-trait = "0.1.80" -jsonrpsee-core = "0.22.3" -jsonrpsee-http-client = "0.22.3" -jsonrpsee-types = "0.22.3" +thiserror = "1.0.63" +async-trait = "0.1.81" +jsonrpsee-core = "0.22.5" +jsonrpsee-http-client = "0.22.5" +jsonrpsee-types = "0.22.5" tokio = { version = "1", features = ["full"] } build-info = "0.0.37" diff --git a/evm_loader/rpc/Cargo.toml b/evm_loader/rpc/Cargo.toml index 7a4d13cd8..1cf1fb602 100644 --- a/evm_loader/rpc/Cargo.toml +++ b/evm_loader/rpc/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] actix-web = "4.8.0" -clap = "2.33.3" +clap = "2.34.0" jsonrpc-v2 = "0.13.0" neon-lib-interface = { path = "../lib-interface" } neon-lib = { path = "../lib" } diff --git a/rust-toolchain.toml b/rust-toolchain.toml index c6e4d7d50..7897a24d1 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.79" +channel = "1.75.0" From c343bc4659e945afb3954603eb66fb691800a578 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Jul 2024 10:35:47 +0200 Subject: [PATCH 283/318] Bump serde_json from 1.0.120 to 1.0.121 in /evm_loader (#515) Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.120 to 1.0.121. - [Release notes](https://github.com/serde-rs/json/releases) - [Commits](https://github.com/serde-rs/json/compare/v1.0.120...v1.0.121) --- updated-dependencies: - dependency-name: serde_json dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- evm_loader/Cargo.lock | 5 +++-- evm_loader/api/Cargo.toml | 2 +- evm_loader/cli/Cargo.toml | 2 +- evm_loader/lib-interface/Cargo.toml | 2 +- evm_loader/program/Cargo.toml | 2 +- evm_loader/rpc-client/Cargo.toml | 2 +- evm_loader/rpc/Cargo.toml | 2 +- 7 files changed, 9 insertions(+), 8 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 82708f890..3a7288956 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -4913,12 +4913,13 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.120" +version = "1.0.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +checksum = "4ab380d7d9f22ef3f21ad3e6c1ebe8e4fc7a2000ccba2e4d71fc96f15b2cb609" dependencies = [ "indexmap 2.2.6", "itoa", + "memchr", "ryu", "serde", ] diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 256822c3c..6ac1b88e5 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -11,7 +11,7 @@ evm-loader = { path = "../program", default-features = false, features = ["log"] solana-sdk.workspace = true solana-client.workspace = true serde = "1.0.204" -serde_json = { version = "1.0.120", features = ["preserve_order"] } +serde_json = { version = "1.0.121", features = ["preserve_order"] } ethnum = { version = "1.5", default-features = false, features = ["serde"] } tokio = { version = "1", features = ["full"] } tracing = "0.1" diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index 8cf6ca5a2..367008d49 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -14,7 +14,7 @@ solana-clap-utils.workspace = true solana-cli-config.workspace = true hex = "0.4.3" serde = "1.0.204" -serde_json = { version = "1.0.120", features = ["preserve_order"] } +serde_json = { version = "1.0.121", features = ["preserve_order"] } log = "0.4.22" fern = "0.6" ethnum = { version = "1.5", default-features = false, features = ["serde"] } diff --git a/evm_loader/lib-interface/Cargo.toml b/evm_loader/lib-interface/Cargo.toml index d3a5607d8..a3357cdf5 100644 --- a/evm_loader/lib-interface/Cargo.toml +++ b/evm_loader/lib-interface/Cargo.toml @@ -10,4 +10,4 @@ abi_stable = "0.11.3" thiserror = "1" async-ffi = { version = "0.5.0", features = ["abi_stable"] } serde = "1.0.204" -serde_json = "1.0.120" +serde_json = "1.0.121" diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index f573e6ea9..5c505dab2 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -65,7 +65,7 @@ features = ["is_sync"] [dev-dependencies] tokio = { version = "1.39", features = ["full"] } -serde_json = { version = "1.0.120", features = ["preserve_order"] } +serde_json = { version = "1.0.121", features = ["preserve_order"] } solana-sdk.workspace = true diff --git a/evm_loader/rpc-client/Cargo.toml b/evm_loader/rpc-client/Cargo.toml index d1d693393..d010a2216 100644 --- a/evm_loader/rpc-client/Cargo.toml +++ b/evm_loader/rpc-client/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] serde = "1.0.204" -serde_json = "1.0.120" +serde_json = "1.0.121" neon-lib = { path = "../lib" } thiserror = "1.0.63" async-trait = "0.1.81" diff --git a/evm_loader/rpc/Cargo.toml b/evm_loader/rpc/Cargo.toml index 1cf1fb602..766a77796 100644 --- a/evm_loader/rpc/Cargo.toml +++ b/evm_loader/rpc/Cargo.toml @@ -13,7 +13,7 @@ neon-lib-interface = { path = "../lib-interface" } neon-lib = { path = "../lib" } semver = "1.0.23" serde = "1.0.204" -serde_json = "1.0.120" +serde_json = "1.0.121" tokio = { version = "1", features = ["full"] } build-info = "0.0.37" thiserror = "1.0" From 4f1e9b8b744987d55f0fb398a64fecff6c205a31 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Wed, 31 Jul 2024 11:42:43 +0200 Subject: [PATCH 284/318] SLA-119: Fix DELEGATECALL "to" address in callTracer (#517) --- evm_loader/lib/src/tracing/tracers/call_tracer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evm_loader/lib/src/tracing/tracers/call_tracer.rs b/evm_loader/lib/src/tracing/tracers/call_tracer.rs index a455b82ec..eac19027b 100644 --- a/evm_loader/lib/src/tracing/tracers/call_tracer.rs +++ b/evm_loader/lib/src/tracing/tracers/call_tracer.rs @@ -246,7 +246,7 @@ impl CallTracer { if self.depth == 1 { let call_frame = &mut self.call_stack[0]; call_frame.from = context.caller; - call_frame.to = Some(context.contract); + call_frame.to = context.code_address.or(Some(context.contract)); call_frame.input = input.into(); call_frame.value = Some(to_web3_u256(context.value)); call_frame.type_string = opcode; @@ -259,7 +259,7 @@ impl CallTracer { self.call_stack.push(CallFrame { from: context.caller, - to: Some(context.contract), + to: context.code_address.or(Some(context.contract)), input: input.into(), value: Some(to_web3_u256(context.value)), type_string: opcode, From af7c8c01741872cbc0dfcf4d3e4d98413674b38c Mon Sep 17 00:00:00 2001 From: Evgeny Zdanovich Date: Wed, 14 Aug 2024 14:21:37 +0200 Subject: [PATCH 285/318] Heap inside Holder account. (#495) * Heap inside Holder account impl. * Adjust get_holder Core API implementation to read raw bits from the State Account. * Introduce macro to reconstruct transaction payload from the pointer. This shall be used from Core API in the get_holder to properly read transaction in there. --- evm_loader/Cargo.lock | 9 +- evm_loader/lib/src/account_storage.rs | 10 +- evm_loader/lib/src/account_storage_tests.rs | 27 +- evm_loader/lib/src/commands/emulate.rs | 37 +- evm_loader/lib/src/commands/get_holder.rs | 15 +- evm_loader/lib/src/types/mod.rs | 12 +- evm_loader/program-macro/Cargo.toml | 2 +- evm_loader/program-macro/src/lib.rs | 95 ++++- evm_loader/program/Cargo.toml | 3 +- evm_loader/program/src/account/holder.rs | 90 ++++- evm_loader/program/src/account/mod.rs | 4 +- evm_loader/program/src/account/state.rs | 326 +++++++++++++----- .../program/src/account_storage/apply.rs | 39 ++- .../program/src/account_storage/backend.rs | 2 +- evm_loader/program/src/account_storage/mod.rs | 6 +- .../program/src/account_storage/synced.rs | 6 +- evm_loader/program/src/allocator.rs | 103 ------ evm_loader/program/src/allocator/mod.rs | 57 +++ .../program/src/allocator/solana/mod.rs | 72 ++++ .../src/allocator/solana/solana_allocator.rs | 43 +++ .../solana/state_account_allocator.rs | 46 +++ evm_loader/program/src/error.rs | 7 +- evm_loader/program/src/evm/buffer.rs | 238 ++----------- evm_loader/program/src/evm/database.rs | 7 +- evm_loader/program/src/evm/memory.rs | 68 +--- evm_loader/program/src/evm/mod.rs | 92 ++--- evm_loader/program/src/evm/opcode.rs | 44 ++- .../program/src/evm/precompile/big_mod_exp.rs | 18 +- .../program/src/evm/precompile/blake2_f.rs | 12 +- .../program/src/evm/precompile/bn256.rs | 19 +- .../program/src/evm/precompile/datacopy.rs | 7 +- .../program/src/evm/precompile/ecrecover.rs | 11 +- evm_loader/program/src/evm/precompile/mod.rs | 4 +- .../program/src/evm/precompile/ripemd160.rs | 7 +- .../program/src/evm/precompile/sha256.rs | 7 +- evm_loader/program/src/evm/stack.rs | 58 +--- evm_loader/program/src/executor/action.rs | 24 +- evm_loader/program/src/executor/cache.rs | 18 +- evm_loader/program/src/executor/mod.rs | 1 + .../precompile_extension/call_solana.rs | 108 +++--- .../executor/precompile_extension/metaplex.rs | 51 +-- .../src/executor/precompile_extension/mod.rs | 12 +- .../precompile_extension/neon_token.rs | 14 +- .../precompile_extension/query_account.rs | 43 ++- .../precompile_extension/spl_token.rs | 198 +++++------ evm_loader/program/src/executor/state.rs | 157 +++++---- .../program/src/executor/synced_state.rs | 19 +- .../program/src/external_programs/metaplex.rs | 5 +- evm_loader/program/src/instruction/mod.rs | 10 +- .../src/instruction/transaction_cancel.rs | 2 +- .../src/instruction/transaction_execute.rs | 21 +- .../transaction_execute_from_account.rs | 18 +- ...action_execute_from_account_solana_call.rs | 23 +- .../transaction_execute_from_instruction.rs | 21 +- ...on_execute_from_instruction_solana_call.rs | 21 +- .../src/instruction/transaction_step.rs | 111 +++--- .../transaction_step_from_account.rs | 18 +- .../transaction_step_from_instruction.rs | 9 +- evm_loader/program/src/lib.rs | 1 + evm_loader/program/src/types/boxx.rs | 7 + evm_loader/program/src/types/mod.rs | 8 +- .../program/src/types/read_raw_utils.rs | 37 ++ evm_loader/program/src/types/serde.rs | 130 ------- evm_loader/program/src/types/transaction.rs | 65 ++-- evm_loader/program/src/types/tree_map.rs | 187 ++++++++++ evm_loader/program/src/types/vector.rs | 94 +++++ 66 files changed, 1737 insertions(+), 1299 deletions(-) delete mode 100644 evm_loader/program/src/allocator.rs create mode 100644 evm_loader/program/src/allocator/mod.rs create mode 100644 evm_loader/program/src/allocator/solana/mod.rs create mode 100644 evm_loader/program/src/allocator/solana/solana_allocator.rs create mode 100644 evm_loader/program/src/allocator/solana/state_account_allocator.rs create mode 100644 evm_loader/program/src/types/boxx.rs create mode 100644 evm_loader/program/src/types/read_raw_utils.rs delete mode 100644 evm_loader/program/src/types/serde.rs create mode 100644 evm_loader/program/src/types/tree_map.rs create mode 100644 evm_loader/program/src/types/vector.rs diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 3a7288956..5c6448eeb 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -358,6 +358,12 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + [[package]] name = "android-tzdata" version = "0.1.1" @@ -1999,6 +2005,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" name = "evm-loader" version = "1.14.0-dev" dependencies = [ + "allocator-api2", "arrayref", "async-trait", "bincode", @@ -2010,12 +2017,12 @@ dependencies = [ "linked_list_allocator", "log", "maybe-async", + "memoffset 0.9.1", "mpl-token-metadata", "ripemd", "rlp", "serde", "serde_bytes", - "serde_json", "solana-program", "solana-sdk", "spl-associated-token-account", diff --git a/evm_loader/lib/src/account_storage.rs b/evm_loader/lib/src/account_storage.rs index 92d247dfa..5486ff2ee 100644 --- a/evm_loader/lib/src/account_storage.rs +++ b/evm_loader/lib/src/account_storage.rs @@ -16,7 +16,7 @@ use evm_loader::{ config::STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT, error::Error as EvmLoaderError, executor::OwnedAccountInfo, - types::Address, + types::{vector::VectorVecExt, Address, Vector}, }; use log::{debug, info, trace}; use solana_sdk::{ @@ -1113,7 +1113,7 @@ impl AccountStorage for EmulatorAccountStorage<'_, T> { .await .unwrap(); - Buffer::from_vec(code) + Buffer::from_vector(code.into_vector()) } async fn storage(&self, address: Address, index: U256) -> [u8; 32] { @@ -1189,7 +1189,7 @@ impl SyncedAccountStorage for EmulatorAccountStorage<'_, T> { &mut self, address: Address, chain_id: u64, - code: Vec, + code: Vector, ) -> evm_loader::error::Result<()> { info!("set_code {address} -> {} bytes", code.len()); { @@ -1337,7 +1337,7 @@ impl SyncedAccountStorage for EmulatorAccountStorage<'_, T> { async fn execute_external_instruction( &mut self, instruction: Instruction, - seeds: Vec>>, + seeds: Vector>>, _fee: u64, emulated_internally: bool, ) -> evm_loader::error::Result<()> { @@ -1362,7 +1362,7 @@ impl SyncedAccountStorage for EmulatorAccountStorage<'_, T> { let signers = seeds .iter() .map(|s| { - let seed = s.iter().map(Vec::as_slice).collect::>(); + let seed = s.iter().map(Vector::as_slice).collect::>(); let signer = Pubkey::create_program_address(&seed, &self.program_id)?; Ok(signer) }) diff --git a/evm_loader/lib/src/account_storage_tests.rs b/evm_loader/lib/src/account_storage_tests.rs index 32ea5f277..d5f68dc50 100644 --- a/evm_loader/lib/src/account_storage_tests.rs +++ b/evm_loader/lib/src/account_storage_tests.rs @@ -1,6 +1,7 @@ use super::*; use crate::rpc; use crate::tracing::AccountOverride; +use evm_loader::types::vector::VectorVecExt; use hex_literal::hex; use std::collections::HashMap; use std::str::FromStr; @@ -1115,7 +1116,7 @@ async fn test_deploy_at_missing_contract() { let code = hex!("14643165").to_vec(); assert!(storage - .set_code(MISSING_ADDRESS, LEGACY_CHAIN_ID, code.clone()) + .set_code(MISSING_ADDRESS, LEGACY_CHAIN_ID, code.clone().into_vector()) .await .is_ok()); storage.verify_used_accounts(&[(fixture.contract_pubkey(MISSING_ADDRESS), true, false)]); @@ -1131,7 +1132,7 @@ async fn test_deploy_at_actual_balance() { let code = hex!("14643165").to_vec(); let acc = &ACTUAL_BALANCE; assert!(storage - .set_code(acc.address, LEGACY_CHAIN_ID, code.clone()) + .set_code(acc.address, LEGACY_CHAIN_ID, code.clone().into_vector()) .await .is_ok()); storage.verify_used_accounts(&[(fixture.contract_pubkey(acc.address), true, false)]); @@ -1148,7 +1149,7 @@ async fn test_deploy_at_actual_contract() { let contract = &ACTUAL_CONTRACT; assert_eq!( storage - .set_code(contract.address, LEGACY_CHAIN_ID, code) + .set_code(contract.address, LEGACY_CHAIN_ID, code.into_vector()) .await .unwrap_err() .to_string(), @@ -1168,7 +1169,11 @@ async fn test_deploy_at_legacy_account() { let code = hex!("37455846").to_vec(); let contract = &LEGACY_ACCOUNT; assert!(storage - .set_code(contract.address, LEGACY_CHAIN_ID, code.clone()) + .set_code( + contract.address, + LEGACY_CHAIN_ID, + code.clone().into_vector() + ) .await .is_ok()); storage.verify_used_accounts(&[ @@ -1192,7 +1197,7 @@ async fn test_deploy_at_legacy_contract() { let contract = &LEGACY_CONTRACT; assert_eq!( storage - .set_code(contract.address, LEGACY_CHAIN_ID, code) + .set_code(contract.address, LEGACY_CHAIN_ID, code.into_vector()) .await .unwrap_err() .to_string(), @@ -1223,7 +1228,11 @@ async fn test_deploy_at_actual_suicide() { let contract = &ACTUAL_SUICIDE; // TODO: Should we deploy new contract by the previous address? assert!(storage - .set_code(contract.address, LEGACY_CHAIN_ID, code.clone()) + .set_code( + contract.address, + LEGACY_CHAIN_ID, + code.clone().into_vector() + ) .await .is_ok(),); storage.verify_used_accounts(&[(fixture.contract_pubkey(contract.address), true, false)]); @@ -1243,7 +1252,11 @@ async fn test_deploy_at_legacy_suicide() { let contract = &LEGACY_SUICIDE; // TODO: Should we deploy new contract by the previous address? assert!(storage - .set_code(contract.address, LEGACY_CHAIN_ID, code.clone()) + .set_code( + contract.address, + LEGACY_CHAIN_ID, + code.clone().into_vector() + ) .await .is_ok(),); storage.verify_used_accounts(&[ diff --git a/evm_loader/lib/src/commands/emulate.rs b/evm_loader/lib/src/commands/emulate.rs index a7f2b48df..d1f16a334 100644 --- a/evm_loader/lib/src/commands/emulate.rs +++ b/evm_loader/lib/src/commands/emulate.rs @@ -173,25 +173,28 @@ async fn emulate_trx( let chain_id = tx.chain_id().unwrap_or_else(|| storage.default_chain_id()); storage.increment_nonce(origin, chain_id).await?; - let mut backend = SyncedExecutorState::new(storage); - let mut evm = match Machine::new(&tx, origin, &mut backend, tracer).await { - Ok(evm) => evm, - Err(e) => { - error!("EVM creation failed {e:?}"); - return Ok((EmulateResponse::revert(&e, &backend), None)); + let (exit_status, steps_executed, tracer, logs) = { + let mut backend = SyncedExecutorState::new(storage); + let mut evm = match Machine::new(&tx, origin, &mut backend, tracer).await { + Ok(evm) => evm, + Err(e) => { + error!("EVM creation failed {e:?}"); + return Ok((EmulateResponse::revert(&e, &backend), None)); + } + }; + + let (exit_status, steps_executed, tracer) = evm.execute(step_limit, &mut backend).await?; + if exit_status == ExitStatus::StepLimit { + error!("Step_limit={step_limit} exceeded"); + return Ok(( + EmulateResponse::revert(&NeonError::TooManySteps, &backend), + None, + )); } - }; - - let (exit_status, steps_executed, tracer) = evm.execute(step_limit, &mut backend).await?; - if exit_status == ExitStatus::StepLimit { - error!("Step_limit={step_limit} exceeded"); - return Ok(( - EmulateResponse::revert(&NeonError::TooManySteps, &backend), - None, - )); - } - let logs = backend.backend().logs(); + let logs = backend.backend().logs(); + (exit_status, steps_executed, tracer, logs) + }; debug!("Execute done, result={exit_status:?}"); debug!("{steps_executed} steps executed"); diff --git a/evm_loader/lib/src/commands/get_holder.rs b/evm_loader/lib/src/commands/get_holder.rs index bc2c4d092..0c0e8d108 100644 --- a/evm_loader/lib/src/commands/get_holder.rs +++ b/evm_loader/lib/src/commands/get_holder.rs @@ -117,23 +117,24 @@ pub fn read_holder(program_id: &Pubkey, info: AccountInfo) -> NeonResult { - let state = StateAccount::from_account(program_id, info)?; - let accounts = state.accounts().copied().collect(); + // StateAccount::from_account doesn't work here because state contains heap + // and transaction inside state account has been allocated via this heap. + // Data should be read by pointers with offsets. + let (transaction, owner, origin, accounts, steps) = + StateAccount::get_state_account_view(program_id, &info)?; - let origin = state.trx_origin(); - let transaction = state.trx(); - let tx_params = TxParams::from_transaction(origin, transaction); + let tx_params = TxParams::from_transaction(origin, &transaction); Ok(GetHolderResponse { status: Status::Active, len: Some(data_len), - owner: Some(state.owner()), + owner: Some(owner), tx: Some(transaction.hash()), tx_data: Some(tx_params), chain_id: transaction.chain_id(), origin: Some(origin), accounts: Some(accounts), - steps_executed: state.steps_executed(), + steps_executed: steps, }) } _ => Err(ProgramError::InvalidAccountData.into()), diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index 718ed4583..00103d72d 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -5,7 +5,9 @@ pub use evm_loader::types::Address; use evm_loader::types::{StorageKey, Transaction}; use evm_loader::{ account_storage::AccountStorage, - types::{AccessListTx, LegacyTx, TransactionPayload}, + types::{ + vector::VectorVecExt, vector::VectorVecSlowExt, AccessListTx, LegacyTx, TransactionPayload, + }, }; use serde_with::skip_serializing_none; use solana_sdk::{account::Account, pubkey::Pubkey}; @@ -63,7 +65,7 @@ impl TxParams { let payload = if let Some(access_list) = self.access_list { let access_list: Vec<_> = access_list .into_iter() - .map(|a| (a.address, a.storage_keys)) + .map(|a| (a.address, a.storage_keys.into_vector())) .collect(); let access_list_tx = AccessListTx { @@ -72,9 +74,9 @@ impl TxParams { gas_limit: self.gas_limit.unwrap_or(U256::MAX), target: self.to, value: self.value.unwrap_or_default(), - call_data: self.data.unwrap_or_default(), + call_data: self.data.unwrap_or_default().into_vector(), chain_id: U256::from(chain_id), - access_list, + access_list: access_list.elementwise_copy_into_vector(), r: U256::ZERO, s: U256::ZERO, recovery_id: 0, @@ -87,7 +89,7 @@ impl TxParams { gas_limit: self.gas_limit.unwrap_or(U256::MAX), target: self.to, value: self.value.unwrap_or_default(), - call_data: self.data.unwrap_or_default(), + call_data: self.data.unwrap_or_default().into_vector(), chain_id: self.chain_id.map(U256::from), v: U256::ZERO, r: U256::ZERO, diff --git a/evm_loader/program-macro/Cargo.toml b/evm_loader/program-macro/Cargo.toml index 2734fa151..07bfee2be 100644 --- a/evm_loader/program-macro/Cargo.toml +++ b/evm_loader/program-macro/Cargo.toml @@ -9,7 +9,7 @@ authors = ["NeonLabs Maintainers "] proc-macro = true [dependencies] -syn = "2" +syn = {version = "2", features = ["full"] } proc-macro2 = "1" quote = "1" itertools = "0.13" diff --git a/evm_loader/program-macro/src/lib.rs b/evm_loader/program-macro/src/lib.rs index 0eb1337fc..2b3f2000d 100644 --- a/evm_loader/program-macro/src/lib.rs +++ b/evm_loader/program-macro/src/lib.rs @@ -8,7 +8,10 @@ use std::collections::BTreeMap; use config_parser::{CommonConfig, NetSpecificConfig}; use proc_macro::TokenStream; use syn::parse::{Parse, ParseStream}; -use syn::{parse_macro_input, Expr, Ident, LitStr, Result, Token}; +use syn::{ + parse_macro_input, Data::Struct, DataStruct, DeriveInput, Expr, Fields::Named, FieldsNamed, + GenericArgument, Ident, LitStr, PathArguments, Result, Token, Type, TypePath, TypeTuple, +}; use quote::quote; @@ -163,3 +166,93 @@ pub fn common_config_parser(tokens: TokenStream) -> TokenStream { } .into() } + +#[proc_macro_derive(ReconstructRaw)] +pub fn reconstruct_raw(input: TokenStream) -> TokenStream { + // Parse the string representation + let ast = parse_macro_input!(input as DeriveInput); + + let Struct(DataStruct { + fields: Named(FieldsNamed { ref named, .. }), + .. + }) = ast.data + else { + unimplemented!("ReconstructRaw only works for structs"); + }; + let builder_fields = named.iter().map(|f| { + let name = &f.ident; + let ty = &f.ty; + + // If the type of the field is Vector, use a special function to reconstruct it. + // Only Vectors of primitive types are supported. + // Other Vectors (including Vector>) are constructed empty. + // N.B. Currently, it's only used in the Transaction in the context of the Core API. + // The only composite vector is access_list which is not relevant for the Core API. + if !is_vector_type(ty) { + quote! { #name: std::ptr::read_unaligned(std::ptr::addr_of!((*struct_ptr).#name)) } + } else if is_composite_vector_type(ty) { + quote! { #name: vector![] } + } else { + quote! { #name: read_vec(std::ptr::addr_of!((*struct_ptr).#name).cast::(), offset).into_vector() } + } + }); + + let name = &ast.ident; + quote! { + impl ReconstructRaw for #name { + /// # Safety + /// Generated code, if something goes wrong here, it likely won't compile at all. + unsafe fn build(struct_ptr: *const Self, offset: isize) -> Self { + unsafe { + Self { + #(#builder_fields,)* + } + } + } + } + } + .into() +} + +fn is_vector_type(ty: &Type) -> bool { + match ty { + Type::Path(TypePath { + path: path_type, .. + }) => path_type + .segments + .iter() + .any(|f| f.ident.to_string().eq("Vector")), + Type::Tuple(TypeTuple { + elems: elems_type, .. + }) => elems_type.iter().any(is_vector_type), + _ => false, + } +} + +fn is_argument_vector_type(arg: &PathArguments) -> bool { + match arg { + PathArguments::AngleBracketed(inner_arg) => inner_arg.args.iter().any(|f| match f { + GenericArgument::Type(inner_type) => is_vector_type(inner_type), + _ => false, + }), + _ => false, + } +} + +fn is_composite_vector_type(ty: &Type) -> bool { + if let Type::Path(TypePath { + qself: _, + path: path_type, + }) = ty + { + let vec_path_segment = path_type + .segments + .iter() + .find(|&f| f.ident.to_string().eq("Vector")); + if let Some(path_segment) = vec_path_segment { + return is_argument_vector_type(&path_segment.arguments); + } + return false; + } + false +} diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 5c505dab2..c78059090 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -58,6 +58,8 @@ cfg-if = { version = "1.0" } log = { version = "0.4", default-features = false, optional = true } maybe-async = "0.2.10" async-trait = { version = "0.1.81", optional = true } +allocator-api2 = "0.2.16" +memoffset = "0.9.1" [target.'cfg(target_os = "solana")'.dependencies.maybe-async] version = "0.2.10" @@ -65,7 +67,6 @@ features = ["is_sync"] [dev-dependencies] tokio = { version = "1.39", features = ["full"] } -serde_json = { version = "1.0.121", features = ["preserve_order"] } solana-sdk.workspace = true diff --git a/evm_loader/program/src/account/holder.rs b/evm_loader/program/src/account/holder.rs index 6c9d3eace..c81cdd3f9 100644 --- a/evm_loader/program/src/account/holder.rs +++ b/evm_loader/program/src/account/holder.rs @@ -1,9 +1,12 @@ +use linked_list_allocator::Heap; use solana_program::account_info::AccountInfo; use solana_program::pubkey::Pubkey; +use static_assertions::const_assert; use std::cell::{Ref, RefMut}; -use std::mem::size_of; +use std::mem::{align_of, size_of}; use crate::account::TAG_STATE_FINALIZED; +use crate::allocator::STATE_ACCOUNT_DATA_ADDRESS; use crate::error::{Error, Result}; use crate::types::Transaction; @@ -15,6 +18,7 @@ pub struct Header { pub owner: Pubkey, pub transaction_hash: [u8; 32], pub transaction_len: usize, + pub heap_offset: usize, } impl AccountHeader for Header { @@ -26,7 +30,18 @@ pub struct Holder<'a> { } const HEADER_OFFSET: usize = ACCOUNT_PREFIX_LEN; -const BUFFER_OFFSET: usize = HEADER_OFFSET + size_of::
(); +pub const BUFFER_OFFSET: usize = HEADER_OFFSET + size_of::
(); + +// Offset of the Header.heap_offset from the start of account data. +// TODO: get rid of memoffset in favor of core::mem::offset_of! when rust version >= 1.77. +pub const HEAP_OFFSET_OFFSET: usize = HEADER_OFFSET + memoffset::offset_of!(Header, heap_offset); +// State Account Header and Holder Account Header should have a shared and fixed memory cell that denotes +// the offset of the persistent heap (heap_offset field). +// The following asert checks that State Account Header does not overlap with `heap_offset` memory cell, +// so writes to State Account Header do not override it. +const_assert!( + memoffset::offset_of!(Header, heap_offset) >= size_of::() +); impl<'a> Holder<'a> { pub fn from_account(program_id: &Pubkey, account: AccountInfo<'a>) -> Result { @@ -100,6 +115,7 @@ impl<'a> Holder<'a> { let mut header = self.header_mut(); header.transaction_hash.fill(0); header.transaction_len = 0; + header.heap_offset = 0; } { let mut buffer = self.buffer_mut(); @@ -180,6 +196,76 @@ impl<'a> Holder<'a> { Ok(()) } + /// Initializes the heap using the whole account data space. + /// Also, writes the offset of the heap object into the separate field in the header. + /// After this, the persistent objects can be allocated into the account data. + pub fn init_heap(&mut self, transaction_offset: usize) -> Result<()> { + // For this case, the account.owner is already validated to be equal to program id. + Self::init_holder_heap(self.account.owner, &mut self.account, transaction_offset) + } + + /// Associated function, see `fn init_heap`. + pub fn init_holder_heap( + program_id: &Pubkey, + account: &mut AccountInfo, + transaction_offset: usize, + ) -> Result<()> { + // Validation: check that the passed account is a variant of Holder: Holder, State or StateFinalized. + // An additional owner check is happening inside the tag. + let tag = crate::account::tag(program_id, account)?; + assert!( + tag == TAG_HOLDER || tag == crate::account::TAG_STATE || tag == TAG_STATE_FINALIZED + ); + + let data_ptr = account.data.borrow().as_ptr(); + // Validation: the Holder Account used as a persistent heap, must be first in the account list. + assert_eq!(data_ptr as usize, STATE_ACCOUNT_DATA_ADDRESS); + + // Calculate the actual aligned heap object ptr and its offset. + let (heap_ptr, heap_object_offset) = { + // Locate heap object into the buffer with offset no less than min_heap_object_offset. + let mut heap_object_offset = BUFFER_OFFSET + transaction_offset; + let mut heap_ptr = data_ptr.wrapping_add(heap_object_offset); + + // Calculate alignment and offset the heap pointer. + let alignment = heap_ptr.align_offset(align_of::()); + heap_ptr = heap_ptr.wrapping_add(alignment); + heap_object_offset += alignment; + // Validation: double check the alignment. + assert_eq!(heap_ptr.align_offset(align_of::()), 0); + + (heap_ptr, heap_object_offset) + }; + + // Initialize the heap. + let heap_ptr = heap_ptr.cast_mut(); + unsafe { + // First, zero out underlying bytes of the future heap representation. + heap_ptr.write_bytes(0, size_of::()); + // Calculate the bottom of the heap, right after the Heap object. + let heap_bottom = heap_ptr.add(size_of::()); + + // Size of heap is equal to account data length minus the length of prefix. + let heap_size = account + .data_len() + .saturating_sub(heap_object_offset + size_of::()); + // Validation: check that heap object is within the account data. + assert!(heap_size > 0); + + // Cast to reference and init. + // Zeroed memory is a valid representation of the Heap and hence we can safely do it. + // That's a safety reason we zeroed the memory above. + #[allow(clippy::cast_ptr_alignment)] + let heap = &mut *(heap_ptr.cast::()); + heap.init(heap_bottom, heap_size); + }; + + // Write the actual heap offset into the header. This memory cell is used by the allocator. + super::section_mut::
(account, HEADER_OFFSET).heap_offset = heap_object_offset; + + Ok(()) + } + /// # Safety /// Permanently deletes Holder account and all data in it pub unsafe fn suicide(self, operator: &Operator) { diff --git a/evm_loader/program/src/account/mod.rs b/evm_loader/program/src/account/mod.rs index bd55d2019..92a429df8 100644 --- a/evm_loader/program/src/account/mod.rs +++ b/evm_loader/program/src/account/mod.rs @@ -33,8 +33,10 @@ mod state_finalized; pub mod token; mod treasury; +pub const HEAP_OFFSET_PTR: usize = holder::HEAP_OFFSET_OFFSET; + pub const TAG_EMPTY: u8 = 0; -pub const TAG_STATE: u8 = 24; +pub const TAG_STATE: u8 = 25; pub const TAG_STATE_FINALIZED: u8 = 32; pub const TAG_HOLDER: u8 = 52; diff --git a/evm_loader/program/src/account/state.rs b/evm_loader/program/src/account/state.rs index 8ff3a1f90..71d0ebd5b 100644 --- a/evm_loader/program/src/account/state.rs +++ b/evm_loader/program/src/account/state.rs @@ -1,16 +1,23 @@ use std::cell::{Ref, RefMut}; -use std::collections::btree_map::Entry; -use std::collections::BTreeMap; -use std::mem::size_of; +use std::mem::{align_of, size_of, ManuallyDrop}; +use std::ptr::{addr_of, read_unaligned}; use crate::account_storage::AccountStorage; +use crate::allocator::acc_allocator; use crate::config::DEFAULT_CHAIN_ID; use crate::debug::log_data; use crate::error::{Error, Result}; -use crate::types::serde::bytes_32; -use crate::types::{Address, Transaction}; +use crate::evm::database::Database; +use crate::evm::tracing::EventListener; +use crate::evm::Machine; +use crate::executor::ExecutorStateData; +use crate::types::boxx::{boxx, Boxx}; +use crate::types::{ + read_raw_utils::{read_vec, ReconstructRaw}, + AccessListTx, Address, LegacyTx, Transaction, TransactionPayload, TreeMap, +}; + use ethnum::U256; -use serde::{Deserialize, Serialize}; use solana_program::hash::Hash; use solana_program::system_program; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; @@ -27,10 +34,17 @@ pub enum AccountsStatus { NeedRestart, } -#[derive(Serialize, Deserialize, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq, Copy)] +#[repr(C)] enum AccountRevision { Revision(u32), - Hash(#[serde(with = "bytes_32")] [u8; 32]), + Hash([u8; 32]), +} + +impl Default for AccountRevision { + fn default() -> Self { + AccountRevision::Revision(0) + } } impl AccountRevision { @@ -71,39 +85,43 @@ impl AccountRevision { } /// Storage data account to store execution metainfo between steps for iterative execution -#[derive(Serialize, Deserialize)] +#[repr(C)] struct Data { pub owner: Pubkey, pub transaction: Transaction, /// Ethereum transaction caller address pub origin: Address, /// Stored revision - pub revisions: BTreeMap, + pub revisions: TreeMap, /// Accounts that been read during the transaction - pub touched_accounts: BTreeMap, + pub touched_accounts: TreeMap, /// Ethereum transaction gas used and paid - #[serde(with = "ethnum::serde::bytes::le")] pub gas_used: U256, /// Steps executed in the transaction pub steps_executed: u64, } +// Stores relative offsets for the corresponding objects as allocated by the AccountAllocator. #[allow(clippy::struct_field_names)] #[repr(C, packed)] -struct Header { - pub evm_state_len: usize, - pub evm_machine_len: usize, - pub data_len: usize, +pub struct Header { + pub executor_state_offset: usize, + pub evm_machine_offset: usize, + pub data_offset: usize, } impl AccountHeader for Header { - const VERSION: u8 = 0; + const VERSION: u8 = 1; } pub struct StateAccount<'a> { account: AccountInfo<'a>, - data: Data, + // ManuallyDrop to ensure Data is not dropped when StateAccount + // is being dropped (between iterations). + data: ManuallyDrop>, } +type StateAccountCoreApiView = (Transaction, Pubkey, Address, Vec, u64); + const BUFFER_OFFSET: usize = ACCOUNT_PREFIX_LEN + size_of::
(); impl<'a> StateAccount<'a> { @@ -112,22 +130,26 @@ impl<'a> StateAccount<'a> { self.account } - pub fn from_account(program_id: &Pubkey, account: AccountInfo<'a>) -> Result { - super::validate_tag(program_id, &account, TAG_STATE)?; - - let (offset, len) = { - let header = super::header::
(&account); - let offset = BUFFER_OFFSET + header.evm_state_len + header.evm_machine_len; - (offset, header.data_len) - }; + pub fn from_account(program_id: &Pubkey, account: &AccountInfo<'a>) -> Result { + super::validate_tag(program_id, account, TAG_STATE)?; - let data = { - let account_data = account.try_borrow_data()?; - let buffer = &account_data[offset..(offset + len)]; - bincode::deserialize(buffer)? + let header = super::header::
(account); + let data_ptr = unsafe { + // Data is more-strictly aligned, but it's safe because we previously initiated it at the exact address. + #[allow(clippy::cast_ptr_alignment)] + account + .data + .borrow() + .as_ptr() + .add(header.data_offset) + .cast::() + .cast_mut() }; - Ok(Self { account, data }) + Ok(Self { + account: account.clone(), + data: ManuallyDrop::new(unsafe { Boxx::from_raw_in(data_ptr, acc_allocator()) }), + }) } pub fn new( @@ -152,42 +174,52 @@ impl<'a> StateAccount<'a> { tag => return Err(Error::AccountInvalidTag(*info.key, tag)), }; + // accounts.into_iter returns sorted accounts, so it's safe. let revisions = accounts .into_iter() .map(|account| { let revision = AccountRevision::new(program_id, account); (*account.key, revision) }) - .collect(); + .collect::>(); - let data = Data { + let data = boxx(Data { owner, transaction, origin, revisions, - touched_accounts: BTreeMap::new(), + touched_accounts: TreeMap::new(), gas_used: U256::ZERO, steps_executed: 0_u64, + }); + + let data_offset = { + let account_data_ptr = info.data.borrow().as_ptr(); + let data_obj_addr = addr_of!(*data).cast::(); + let data_offset = unsafe { data_obj_addr.offset_from(account_data_ptr) }; + #[allow(clippy::cast_sign_loss)] + let data_offset = data_offset as usize; + data_offset }; super::set_tag(program_id, &info, TAG_STATE, Header::VERSION)?; { // Set header let mut header = super::header_mut::
(&info); - header.evm_state_len = 0; - header.evm_machine_len = 0; - header.data_len = 0; + header.executor_state_offset = 0; + header.evm_machine_offset = 0; + header.data_offset = data_offset; } Ok(Self { account: info, - data, + data: ManuallyDrop::new(data), }) } pub fn restore( program_id: &Pubkey, - info: AccountInfo<'a>, + info: &AccountInfo<'a>, accounts: &AccountsDB, ) -> Result<(Self, AccountsStatus)> { let mut status = AccountsStatus::Ok; @@ -205,7 +237,7 @@ impl<'a> StateAccount<'a> { let touched_accounts = accounts.into_iter().filter(|a| is_touched_account(a.key)); for account in touched_accounts { let account_revision = AccountRevision::new(program_id, account); - let revision_entry = &state.data.revisions[account.key]; + let revision_entry = &state.data.revisions[*account.key]; if revision_entry != &account_revision { log_data(&[b"INVALID_REVISION", account.key.as_ref()]); @@ -234,17 +266,13 @@ impl<'a> StateAccount<'a> { Ok(()) } - pub fn update_touched_accounts(&mut self, touched: BTreeMap) -> Result<()> { - for (key, counter) in touched { - match self.data.touched_accounts.entry(key) { - Entry::Vacant(e) => { - e.insert(counter); - } - Entry::Occupied(e) => { - let value = e.into_mut(); - *value = value.checked_add(counter).ok_or(Error::IntegerOverflow)?; - } - } + pub fn update_touched_accounts(&mut self, touched: &TreeMap) -> Result<()> { + for (key, counter) in touched.iter() { + self.data + .touched_accounts + .update_or_insert(*key, counter, |v| { + v.checked_add(*counter).ok_or(Error::IntegerOverflow) + })?; } Ok(()) @@ -254,21 +282,9 @@ impl<'a> StateAccount<'a> { self.data.revisions.keys() } - #[inline] - #[must_use] - fn header(&self) -> Ref
{ - super::header(&self.account) - } - - #[inline] - #[must_use] - fn header_mut(&mut self) -> RefMut
{ - super::header_mut(&self.account) - } - #[must_use] pub fn buffer(&self) -> Ref<[u8]> { - let data = self.account.data.borrow(); + let data = self.account.try_borrow_data().unwrap(); Ref::map(data, |d| &d[BUFFER_OFFSET..]) } @@ -278,37 +294,6 @@ impl<'a> StateAccount<'a> { RefMut::map(data, |d| &mut d[BUFFER_OFFSET..]) } - #[must_use] - pub fn buffer_variables(&self) -> (usize, usize) { - let header = self.header(); - (header.evm_state_len, header.evm_machine_len) - } - - pub fn set_buffer_variables(&mut self, evm_state_len: usize, evm_machine_len: usize) { - let mut header = self.header_mut(); - header.evm_state_len = evm_state_len; - header.evm_machine_len = evm_machine_len; - } - - pub fn save_data(&mut self) -> Result<()> { - let (evm_state_len, evm_machine_len) = self.buffer_variables(); - let offset = BUFFER_OFFSET + evm_state_len + evm_machine_len; - - let data_len: usize = { - let mut data = self.account.data.borrow_mut(); - let buffer = &mut data[offset..]; - - let mut cursor = std::io::Cursor::new(buffer); - bincode::serialize_into(&mut cursor, &self.data)?; - - cursor.position().try_into()? - }; - - self.header_mut().data_len = data_len; - - Ok(()) - } - #[must_use] pub fn owner(&self) -> Pubkey { self.data.owner @@ -411,3 +396,154 @@ impl<'a> StateAccount<'a> { Ok(()) } } + +// Implementation of functional to save/restore persistent state of iterative transactions. +impl<'a> StateAccount<'a> { + pub fn alloc_executor_state(&self, data: Boxx) -> Result<()> { + let offset = self.leak_and_offset(data); + let mut header = super::header_mut::
(&self.account); + header.executor_state_offset = offset; + Ok(()) + } + + pub fn alloc_evm(&self, evm: Boxx>) -> Result<()> { + let offset = self.leak_and_offset(evm); + let mut header = super::header_mut::
(&self.account); + header.evm_machine_offset = offset; + Ok(()) + } + + /// Leak the Box's underlying data and returns offset from the account data start. + fn leak_and_offset(&self, object: Boxx) -> usize { + let data_ptr = self.account.data.borrow().as_ptr(); + unsafe { + // allocator_api2 does not expose Box::leak (private associated fn). + // We avoid drop of persistent object by leaking via Box::into_raw. + let obj_addr = Boxx::into_raw(object).cast_const().cast::(); + + let offset = obj_addr.offset_from(data_ptr); + assert!(offset > 0); + #[allow(clippy::cast_sign_loss)] + let offset = offset as usize; + offset + } + } + + #[must_use] + pub fn read_evm(&self) -> ManuallyDrop>> { + let header = super::header::
(&self.account); + self.map_obj(header.evm_machine_offset) + } + + #[must_use] + pub fn read_executor_state(&self) -> ManuallyDrop> { + let header = super::header::
(&self.account); + self.map_obj(header.executor_state_offset) + } + + fn map_obj(&self, offset: usize) -> ManuallyDrop> { + let data = self.account.data.borrow().as_ptr(); + unsafe { + let ptr = data.add(offset).cast_mut(); + assert_eq!(ptr.align_offset(align_of::()), 0); + let data_ptr = ptr.cast::(); + + ManuallyDrop::new(Boxx::from_raw_in(data_ptr, acc_allocator())) + } + } +} + +impl<'a> StateAccount<'a> { + /// Implementation to squeeze bits of information from the state account. + /// N.B. + /// 1. `StateAccount` contains objects and pointers allocated by the state account allocator, so reading + /// objects inside requires jumping on the offset (between the real account address as allocated by the + /// current allocator) and "intended" address of the first account as provided by the Solana runtime. + /// 2. `addr_of!` and `read_unaligned` is heavily used to facilitate the reading of fields by raw pointers. + /// 3. There are upcasts from *const u8 to *const T, but since T was allocated by the allocator previously, + /// it has the correct alignment and the upcast is sound. + #[allow(clippy::cast_ptr_alignment)] + pub fn get_state_account_view( + program_id: &Pubkey, + account: &AccountInfo<'a>, + ) -> Result { + super::validate_tag(program_id, account, TAG_STATE)?; + + let header = super::header::
(account); + let memory_space_delta = { + account.data.borrow().as_ptr() as isize + - isize::try_from(crate::allocator::STATE_ACCOUNT_DATA_ADDRESS)? + }; + // Pointer to the Data is needed to get pointers to the fields in a safe way (using addr_of!). + let data_ptr = unsafe { + account + .data + .borrow() + .as_ptr() + .add(header.data_offset) + .cast::() + .cast_mut() + }; + + unsafe { + // Reading full `Transaction`. + let transaction_ptr = addr_of!((*data_ptr).transaction); + // Memory layout for transaction payload is: tag of enum's variant (u8) followed by the variant value. + // Payload that follows enum tag can have offset due to alignment. + let tx_payload_enum_tag = addr_of!((*transaction_ptr).transaction).cast::(); + let payload_ptr = tx_payload_enum_tag.add(1); + + let tx_payload = match read_unaligned(tx_payload_enum_tag) { + 0 => { + let legacy_payload_ptr = + payload_ptr.wrapping_add(payload_ptr.align_offset(align_of::())); + + TransactionPayload::Legacy(LegacyTx::build( + legacy_payload_ptr.cast::(), + memory_space_delta, + )) + } + 1 => { + let access_list_payload_ptr = payload_ptr + .wrapping_add(payload_ptr.align_offset(align_of::())); + + TransactionPayload::AccessList(AccessListTx::build( + access_list_payload_ptr.cast::(), + memory_space_delta, + )) + } + _ => { + return Err(Error::Custom( + "Incorrect transaction payload type.".to_owned(), + )); + } + }; + + let byte_len = read_unaligned(addr_of!((*transaction_ptr).byte_len)); + let hash = read_unaligned(addr_of!((*transaction_ptr).hash)); + let signed_hash = read_unaligned(addr_of!((*transaction_ptr).signed_hash)); + let tx = Transaction { + transaction: tx_payload, + byte_len, + hash, + signed_hash, + }; + + // Reading parts of `StateAccount`. + let owner = read_unaligned(addr_of!((*data_ptr).owner)); + let origin = read_unaligned(addr_of!((*data_ptr).origin)); + let keys_ptr = addr_of!((*data_ptr).revisions).cast::(); + + // Hereby we read the TreeMap and rely on the fact that under the hood it's a Vector<(Pubkey, AccountRevision)>. + // In case the structure changes, it also requires adjustments. + let accounts = read_vec::<(Pubkey, AccountRevision)>(keys_ptr, memory_space_delta) + .iter() + .map(|(key, _)| *key) + .collect(); + + let steps = read_unaligned(addr_of!((*data_ptr).steps_executed)); + + Ok((tx, owner, origin, accounts, steps)) + } + } +} diff --git a/evm_loader/program/src/account_storage/apply.rs b/evm_loader/program/src/account_storage/apply.rs index 630bef837..baae5ff7f 100644 --- a/evm_loader/program/src/account_storage/apply.rs +++ b/evm_loader/program/src/account_storage/apply.rs @@ -12,7 +12,7 @@ use crate::config::{ }; use crate::error::Result; use crate::executor::Action; -use crate::types::Address; +use crate::types::{Address, Vector}; impl<'a> ProgramAccountStorage<'a> { pub fn transfer_treasury_payment(&mut self) -> Result<()> { @@ -68,7 +68,8 @@ impl<'a> ProgramAccountStorage<'a> { Ok(total_result) } - pub fn apply_state_change(&mut self, actions: Vec) -> Result<()> { + /// Takes an *immutable borrow* of Actions from the accumulated state changes and applies it. + pub fn apply_state_change(&mut self, actions: &Vector) -> Result<()> { debug_print!("Applies begin"); let mut storage = HashMap::with_capacity(16); @@ -81,22 +82,22 @@ impl<'a> ProgramAccountStorage<'a> { chain_id, value, } => { - let mut source = self.balance_account(source, chain_id)?; - let mut target = self.create_balance_account(target, chain_id)?; + let mut source = self.balance_account(*source, *chain_id)?; + let mut target = self.create_balance_account(*target, *chain_id)?; source.increment_revision(&self.rent, &self.accounts)?; target.increment_revision(&self.rent, &self.accounts)?; - source.transfer(&mut target, value)?; + source.transfer(&mut target, *value)?; } Action::Burn { source, chain_id, value, } => { - let mut account = self.create_balance_account(source, chain_id)?; + let mut account = self.create_balance_account(*source, *chain_id)?; account.increment_revision(&self.rent, &self.accounts)?; - account.burn(value)?; + account.burn(*value)?; } Action::EvmSetStorage { address, @@ -104,15 +105,15 @@ impl<'a> ProgramAccountStorage<'a> { value, } => { storage - .entry(address) + .entry(*address) .or_insert_with(|| HashMap::with_capacity(64)) - .insert(index, value); + .insert(*index, *value); } Action::EvmSetTransientStorage { .. } => { // do nothing, transient storage is discarded at the end of the transaction } Action::EvmIncrementNonce { address, chain_id } => { - let mut account = self.create_balance_account(address, chain_id)?; + let mut account = self.create_balance_account(*address, *chain_id)?; account.increment_nonce()?; } Action::EvmSetCode { @@ -121,17 +122,17 @@ impl<'a> ProgramAccountStorage<'a> { code, } => { ContractAccount::create( - address, - chain_id, + *address, + *chain_id, 0, - &code, + code, &self.accounts, Some(&self.keys), )?; } Action::ExternalInstruction { program_id, - mut accounts, + accounts, data, seeds, .. @@ -147,7 +148,9 @@ impl<'a> ProgramAccountStorage<'a> { let program = self.accounts.get(&program_id).clone(); accounts_info.push(program); - for meta in &mut accounts { + // Convert from persistent Vector to std::Vec, as required by the solana Instruction. + let mut ixn_accounts = accounts.to_vec(); + for meta in &mut ixn_accounts { if meta.pubkey == FAKE_OPERATOR { meta.pubkey = self.accounts.operator_key(); } @@ -156,9 +159,9 @@ impl<'a> ProgramAccountStorage<'a> { } let instruction = Instruction { - program_id, - accounts, - data, + program_id: *program_id, + accounts: ixn_accounts, + data: data.to_vec(), }; if !seeds.is_empty() { diff --git a/evm_loader/program/src/account_storage/backend.rs b/evm_loader/program/src/account_storage/backend.rs index 9ecc959c8..9b33c2c36 100644 --- a/evm_loader/program/src/account_storage/backend.rs +++ b/evm_loader/program/src/account_storage/backend.rs @@ -70,7 +70,7 @@ impl<'a> AccountStorage for ProgramAccountStorage<'a> { } fn return_data(&self) -> Option<(Pubkey, Vec)> { - solana_program::program::get_return_data() + solana_program::program::get_return_data().map(|res| (res.0, res.1)) } fn set_return_data(&mut self, data: &[u8]) { diff --git a/evm_loader/program/src/account_storage/mod.rs b/evm_loader/program/src/account_storage/mod.rs index 6b722a19f..5efd41264 100644 --- a/evm_loader/program/src/account_storage/mod.rs +++ b/evm_loader/program/src/account_storage/mod.rs @@ -1,6 +1,6 @@ -use crate::error::Result; use crate::executor::OwnedAccountInfo; use crate::types::Address; +use crate::{error::Result, types::Vector}; use ethnum::U256; use maybe_async::maybe_async; use solana_program::{ @@ -98,7 +98,7 @@ pub trait AccountStorage: LogCollector { #[maybe_async(?Send)] pub trait SyncedAccountStorage: AccountStorage { - async fn set_code(&mut self, address: Address, chain_id: u64, code: Vec) -> Result<()>; + async fn set_code(&mut self, address: Address, chain_id: u64, code: Vector) -> Result<()>; async fn set_storage(&mut self, address: Address, index: U256, value: [u8; 32]) -> Result<()>; async fn increment_nonce(&mut self, address: Address, chain_id: u64) -> Result<()>; async fn transfer( @@ -112,7 +112,7 @@ pub trait SyncedAccountStorage: AccountStorage { async fn execute_external_instruction( &mut self, instruction: Instruction, - seeds: Vec>>, + seeds: Vector>>, fee: u64, emulated_internally: bool, ) -> Result<()>; diff --git a/evm_loader/program/src/account_storage/synced.rs b/evm_loader/program/src/account_storage/synced.rs index 77ab8c8ed..d80d9b08a 100644 --- a/evm_loader/program/src/account_storage/synced.rs +++ b/evm_loader/program/src/account_storage/synced.rs @@ -7,12 +7,12 @@ use crate::account::{AllocateResult, ContractAccount, StorageCell}; use crate::account_storage::{SyncedAccountStorage, FAKE_OPERATOR}; use crate::config::{ACCOUNT_SEED_VERSION, STORAGE_ENTRIES_IN_CONTRACT_ACCOUNT}; use crate::error::Result; -use crate::types::Address; +use crate::types::{vector::Vector, Address}; use super::{AccountStorage, ProgramAccountStorage}; impl<'a> SyncedAccountStorage for crate::account_storage::ProgramAccountStorage<'a> { - fn set_code(&mut self, address: Address, chain_id: u64, code: Vec) -> Result<()> { + fn set_code(&mut self, address: Address, chain_id: u64, code: Vector) -> Result<()> { let result = ContractAccount::allocate( address, &code, @@ -102,7 +102,7 @@ impl<'a> SyncedAccountStorage for crate::account_storage::ProgramAccountStorage< fn execute_external_instruction( &mut self, mut instruction: Instruction, - seeds: Vec>>, + seeds: Vector>>, _fee: u64, _emulated_internally: bool, ) -> Result<()> { diff --git a/evm_loader/program/src/allocator.rs b/evm_loader/program/src/allocator.rs deleted file mode 100644 index bcf0f8170..000000000 --- a/evm_loader/program/src/allocator.rs +++ /dev/null @@ -1,103 +0,0 @@ -use std::{ - alloc::Layout, - mem::{align_of, size_of}, - ptr::NonNull, -}; - -use linked_list_allocator::Heap; -use solana_program::entrypoint::HEAP_START_ADDRESS; -use static_assertions::{const_assert, const_assert_eq}; - -cfg_if::cfg_if! { - if #[cfg(feature = "rollup")] { - // NeonEVM under rollup is intended to be deployed with a forked version of Solana that supports such bigger heap. - const HEAP_SIZE: usize = 1024 * 1024; - } else { - const HEAP_SIZE: usize = 256 * 1024; - } -} - -#[allow(clippy::cast_possible_truncation)] // HEAP_START_ADDRESS < usize::max -const EVM_HEAP_START_ADDRESS: usize = HEAP_START_ADDRESS as usize; -const EVM_HEAP_SIZE: usize = HEAP_SIZE; - -const_assert!(HEAP_START_ADDRESS < (usize::MAX as u64)); -const_assert_eq!(EVM_HEAP_START_ADDRESS % align_of::(), 0); - -#[inline] -unsafe fn heap() -> &'static mut Heap { - // This is legal since all-zero is a valid `Heap`-struct representation - const HEAP_PTR: *mut Heap = EVM_HEAP_START_ADDRESS as *mut Heap; - let heap = &mut *HEAP_PTR; - - if heap.bottom().is_null() { - let start = (EVM_HEAP_START_ADDRESS + size_of::()) as *mut u8; - let size = EVM_HEAP_SIZE - size_of::(); - heap.init(start, size); - } - - heap -} - -pub struct SolanaAllocator; - -unsafe impl std::alloc::GlobalAlloc for SolanaAllocator { - unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - #[allow(clippy::option_if_let_else)] - if let Ok(non_null) = heap().allocate_first_fit(layout) { - non_null.as_ptr() - } else { - solana_program::log::sol_log("EVM Allocator out of memory"); - std::ptr::null_mut() - } - } - - unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { - heap().deallocate(NonNull::new_unchecked(ptr), layout); - } - - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { - let ptr = self.alloc(layout); - - if !ptr.is_null() { - #[cfg(target_os = "solana")] - solana_program::syscalls::sol_memset_(ptr, 0, layout.size() as u64); - #[cfg(not(target_os = "solana"))] - std::ptr::write_bytes(ptr, 0, layout.size()); - } - - ptr - } - - unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { - let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); - let new_ptr = self.alloc(new_layout); - - if !new_ptr.is_null() { - let copy_bytes = std::cmp::min(layout.size(), new_size); - - #[cfg(target_os = "solana")] - solana_program::syscalls::sol_memcpy_(new_ptr, ptr, copy_bytes as u64); - #[cfg(not(target_os = "solana"))] - std::ptr::copy_nonoverlapping(ptr, new_ptr, copy_bytes); - - self.dealloc(ptr, layout); - } - - new_ptr - } -} - -cfg_if::cfg_if! { - if #[cfg(target_os = "solana")] { - #[global_allocator] - static mut DEFAULT: SolanaAllocator = SolanaAllocator; - pub static mut EVM: SolanaAllocator = SolanaAllocator; - } else { - use std::alloc::System; - - #[global_allocator] - static mut DEFAULT: System = System; - pub static mut EVM: System = System; - } -} diff --git a/evm_loader/program/src/allocator/mod.rs b/evm_loader/program/src/allocator/mod.rs new file mode 100644 index 000000000..146628c3f --- /dev/null +++ b/evm_loader/program/src/allocator/mod.rs @@ -0,0 +1,57 @@ +#[cfg(not(target_os = "solana"))] +use std::alloc::System; +use std::mem::size_of; + +use solana_program::pubkey::Pubkey; + +#[cfg(target_os = "solana")] +use solana::solana_allocator::SolanaAllocator; +#[cfg(target_os = "solana")] +use solana::state_account_allocator::AccountAllocator; + +#[cfg(target_os = "solana")] +mod solana; + +// Holder account heap constants. + +/// See [`solana_program::entrypoint::deserialize`] for more details. +const FIRST_ACCOUNT_DATA_OFFSET: usize = + /* number of accounts */ + size_of::() + + /* duplication marker */ size_of::() + + /* is signer? */ size_of::() + + /* is writable? */ size_of::() + + /* is executable? */ size_of::() + + /* original_data_len */ size_of::() + + /* key */ size_of::() + + /* owner */ size_of::() + + /* lamports */ size_of::() + + /* factual_data_len */ size_of::(); + +/// See for more details. +const PROGRAM_DATA_INPUT_PARAMETERS_OFFSET: usize = 0x0004_0000_0000_usize; + +pub const STATE_ACCOUNT_DATA_ADDRESS: usize = + PROGRAM_DATA_INPUT_PARAMETERS_OFFSET + FIRST_ACCOUNT_DATA_OFFSET; + +#[cfg(target_os = "solana")] +pub type StateAccountAllocator = AccountAllocator; + +#[cfg(target_os = "solana")] +#[inline] +pub fn acc_allocator() -> StateAccountAllocator { + AccountAllocator +} + +#[cfg(not(target_os = "solana"))] +pub type StateAccountAllocator = System; + +#[cfg(not(target_os = "solana"))] +#[inline] +pub fn acc_allocator() -> StateAccountAllocator { + System +} + +#[cfg(target_os = "solana")] +#[global_allocator] +static mut DEFAULT: SolanaAllocator = SolanaAllocator; diff --git a/evm_loader/program/src/allocator/solana/mod.rs b/evm_loader/program/src/allocator/solana/mod.rs new file mode 100644 index 000000000..199678af9 --- /dev/null +++ b/evm_loader/program/src/allocator/solana/mod.rs @@ -0,0 +1,72 @@ +use linked_list_allocator::Heap; +use std::alloc::Layout; +use std::ptr::NonNull; + +use solana_allocator::SolanaAllocator; +use state_account_allocator::AccountAllocator; + +pub mod solana_allocator; +pub mod state_account_allocator; + +trait Alloc { + fn heap() -> &'static mut Heap; + + fn alloc_impl(layout: Layout) -> Result, ()> { + Self::heap().allocate_first_fit(layout) + } + + fn dealloc_impl(ptr: *mut u8, layout: Layout) { + unsafe { + Self::heap().deallocate(NonNull::new_unchecked(ptr), layout); + } + } +} + +macro_rules! impl_global_alloc { + ($t:ty, $err:expr) => { + unsafe impl std::alloc::GlobalAlloc for $t { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + #[allow(clippy::option_if_let_else)] + if let Ok(non_null) = Self::alloc_impl(layout) { + non_null.as_ptr() + } else { + solana_program::log::sol_log($err); + std::ptr::null_mut() + } + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + Self::dealloc_impl(ptr, layout); + } + + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { + let ptr = self.alloc(layout); + + if !ptr.is_null() { + solana_program::syscalls::sol_memset_(ptr, 0, layout.size() as u64); + } + + ptr + } + + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); + let new_ptr = self.alloc(new_layout); + + if !new_ptr.is_null() { + let copy_bytes = std::cmp::min(layout.size(), new_size); + + solana_program::syscalls::sol_memcpy_(new_ptr, ptr, copy_bytes as u64); + + self.dealloc(ptr, layout); + } + + new_ptr + } + } + }; +} + +impl_global_alloc!(SolanaAllocator, "Solana Allocator out of memory"); + +impl_global_alloc!(AccountAllocator, "EVM Account Allocator out of memory"); diff --git a/evm_loader/program/src/allocator/solana/solana_allocator.rs b/evm_loader/program/src/allocator/solana/solana_allocator.rs new file mode 100644 index 000000000..b2fcbf0bc --- /dev/null +++ b/evm_loader/program/src/allocator/solana/solana_allocator.rs @@ -0,0 +1,43 @@ +use std::mem::{align_of, size_of}; + +use linked_list_allocator::Heap; +use solana_program::entrypoint::HEAP_START_ADDRESS; +use static_assertions::{const_assert, const_assert_eq}; + +use crate::allocator::solana::Alloc; + +// Solana heap constants. +#[allow(clippy::cast_possible_truncation)] // HEAP_START_ADDRESS < usize::max +const SOLANA_HEAP_START_ADDRESS: usize = HEAP_START_ADDRESS as usize; + +cfg_if::cfg_if! { + if #[cfg(feature = "rollup")] { + // NeonEVM under rollup is intended to be deployed with a forked version of Solana that supports such bigger heap. + const SOLANA_HEAP_SIZE: usize = 1024 * 1024; + } else { + const SOLANA_HEAP_SIZE: usize = 256 * 1024; + } +} + +const_assert!(HEAP_START_ADDRESS < (usize::MAX as u64)); + +const_assert_eq!(SOLANA_HEAP_START_ADDRESS % align_of::(), 0); + +#[derive(Clone, Copy)] +pub struct SolanaAllocator; + +impl Alloc for SolanaAllocator { + fn heap() -> &'static mut Heap { + // This is legal since all-zero is a valid `Heap`-struct representation + const HEAP_PTR: *mut Heap = SOLANA_HEAP_START_ADDRESS as *mut Heap; + let heap = unsafe { &mut *HEAP_PTR }; + + if heap.bottom().is_null() { + let start = (SOLANA_HEAP_START_ADDRESS + size_of::()) as *mut u8; + let size = SOLANA_HEAP_SIZE - size_of::(); + unsafe { heap.init(start, size) }; + } + + heap + } +} diff --git a/evm_loader/program/src/allocator/solana/state_account_allocator.rs b/evm_loader/program/src/allocator/solana/state_account_allocator.rs new file mode 100644 index 000000000..cc356aa58 --- /dev/null +++ b/evm_loader/program/src/allocator/solana/state_account_allocator.rs @@ -0,0 +1,46 @@ +use std::alloc::Layout; +use std::ptr::NonNull; +use std::slice; + +use linked_list_allocator::Heap; + +use crate::allocator::solana::Alloc; +use crate::allocator::STATE_ACCOUNT_DATA_ADDRESS; + +#[derive(Clone, Copy)] +pub struct AccountAllocator; + +// Configure State/Holder Account heap: the offset of the heap object is at HEAP_OBJECT_OFFSET_PTR address. +#[allow(clippy::cast_possible_truncation)] +const HEAP_OBJECT_OFFSET_PTR: usize = STATE_ACCOUNT_DATA_ADDRESS + crate::account::HEAP_OFFSET_PTR; + +impl Alloc for AccountAllocator { + fn heap() -> &'static mut Heap { + let heap_object_offset_ptr = HEAP_OBJECT_OFFSET_PTR as *const usize; + let heap_object_offset = unsafe { std::ptr::read_unaligned(heap_object_offset_ptr) }; + let heap_ptr: *mut Heap = (STATE_ACCOUNT_DATA_ADDRESS + heap_object_offset) as *mut Heap; + let heap = unsafe { &mut *heap_ptr }; + // Unlike SolanaAllocator, AccountAllocator do not init account heap here. + // It's account's responsibility to initialize it itself (likely during + // Holder/StateAccount creation), because account knows its size and thus can + // correctly specify heap size. + + heap + } +} + +unsafe impl allocator_api2::alloc::Allocator for AccountAllocator { + fn allocate(&self, layout: Layout) -> Result, allocator_api2::alloc::AllocError> { + unsafe { + Self::alloc_impl(layout) + .map(|ptr| { + NonNull::new_unchecked(slice::from_raw_parts_mut(ptr.as_ptr(), layout.size())) + }) + .map_err(|()| allocator_api2::alloc::AllocError) + } + } + + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + Self::dealloc_impl(ptr.as_ptr(), layout); + } +} diff --git a/evm_loader/program/src/error.rs b/evm_loader/program/src/error.rs index bf88f7e92..fcbcc3380 100644 --- a/evm_loader/program/src/error.rs +++ b/evm_loader/program/src/error.rs @@ -3,6 +3,7 @@ use std::{array::TryFromSliceError, num::TryFromIntError, str::Utf8Error}; +use crate::allocator::acc_allocator; use ethnum::U256; use solana_program::{ program_error::ProgramError, @@ -11,7 +12,7 @@ use solana_program::{ }; use thiserror::Error; -use crate::types::Address; +use crate::types::{Address, Vector}; /// Errors that may be returned by the EVM Loader program. #[derive(Error, Debug)] @@ -311,7 +312,7 @@ pub fn print_revert_message(msg: &[u8]) { } #[must_use] -pub fn build_revert_message(msg: &str) -> Vec { +pub fn build_revert_message(msg: &str) -> Vector { let data_len = if msg.len() % 32 == 0 { std::cmp::max(msg.len(), 32) } else { @@ -319,7 +320,7 @@ pub fn build_revert_message(msg: &str) -> Vec { }; let capacity = 4 + 32 + 32 + data_len; - let mut result = Vec::with_capacity(capacity); + let mut result = Vector::with_capacity_in(capacity, acc_allocator()); result.extend_from_slice(&[0x08, 0xc3, 0x79, 0xa0]); // Error(string) function selector let offset = U256::new(0x20); diff --git a/evm_loader/program/src/evm/buffer.rs b/evm_loader/program/src/evm/buffer.rs index 2eb4169c9..da6ff8843 100644 --- a/evm_loader/program/src/evm/buffer.rs +++ b/evm_loader/program/src/evm/buffer.rs @@ -2,21 +2,23 @@ use std::ops::{Deref, Range}; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; +use crate::types::vector::VectorSliceExt; +use crate::types::Vector; +use crate::vector; + #[cfg_attr(test, derive(Debug, PartialEq))] +#[repr(C)] enum Inner { - Owned(Vec), + Owned(Vector), Account { key: Pubkey, range: Range, data: *const u8, }, - AccountUninit { - key: Pubkey, - range: Range, - }, } #[cfg_attr(test, derive(Debug))] +#[repr(C)] pub struct Buffer { // We maintain a ptr and len to be able to construct a slice without having to discriminate // inner. This means we should not allow mutation of inner after the construction of a buffer. @@ -40,7 +42,6 @@ impl Buffer { let ptr = unsafe { data.add(range.start) }; (ptr, range.len()) } - Inner::AccountUninit { .. } => (std::ptr::null(), 0), }; Buffer { ptr, len, inner } @@ -68,28 +69,23 @@ impl Buffer { } #[must_use] - pub fn from_vec(v: Vec) -> Self { - Self::new(Inner::Owned(v)) + pub fn from_vector(data: Vector) -> Self { + Self::new(Inner::Owned(data)) } #[must_use] pub fn from_slice(v: &[u8]) -> Self { - Self::from_vec(v.to_vec()) + Self::from_vector(v.to_vector()) } #[must_use] pub fn empty() -> Self { - Buffer::new(Inner::Owned(Vec::default())) - } - - #[must_use] - pub fn is_initialized(&self) -> bool { - !matches!(self.inner, Inner::AccountUninit { .. }) + Self::from_vector(vector![]) } #[must_use] pub fn uninit_data(&self) -> Option<(Pubkey, Range)> { - if let Inner::AccountUninit { key, range } = &self.inner { + if let Inner::Account { key, range, .. } = &self.inner { Some((*key, range.clone())) } else { None @@ -130,10 +126,6 @@ impl Clone for Buffer { range: range.clone(), data: *data, }), - Inner::AccountUninit { key, range } => Self::new(Inner::AccountUninit { - key: *key, - range: range.clone(), - }), } } } @@ -144,99 +136,10 @@ impl Default for Buffer { } } -impl serde::Serialize for Buffer { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - use serde::ser::SerializeStructVariant; - - match &self.inner { - Inner::Owned(data) => { - let bytes = serde_bytes::Bytes::new(data); - serializer.serialize_newtype_variant("evm_buffer", 1, "owned", bytes) - } - Inner::Account { key, range, .. } => { - let mut sv = serializer.serialize_struct_variant("evm_buffer", 2, "account", 2)?; - sv.serialize_field("key", key)?; - sv.serialize_field("range", range)?; - sv.end() - } - Inner::AccountUninit { .. } => { - unreachable!() - } - } - } -} - -impl<'de> serde::Deserialize<'de> for Buffer { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - struct BufferVisitor; - - impl<'de> serde::de::Visitor<'de> for BufferVisitor { - type Value = Buffer; - - fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.write_str("EVM Buffer") - } - - fn visit_unit(self) -> Result - where - E: serde::de::Error, - { - Ok(Buffer::empty()) - } - - fn visit_bytes(self, v: &[u8]) -> Result - where - E: serde::de::Error, - { - Ok(Buffer::from_slice(v)) - } - - fn visit_seq(self, mut seq: A) -> Result - where - A: serde::de::SeqAccess<'de>, - { - let key = seq - .next_element()? - .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?; - let range = seq - .next_element()? - .ok_or_else(|| serde::de::Error::invalid_length(1, &self))?; - Ok(Buffer::new(Inner::AccountUninit { key, range })) - } - - fn visit_enum(self, data: A) -> Result - where - A: serde::de::EnumAccess<'de>, - { - use serde::de::VariantAccess; - - let (index, variant) = data.variant::()?; - match index { - 0 => variant.unit_variant().map(|()| Buffer::empty()), - 1 => variant.newtype_variant().map(Buffer::from_slice), - 2 => variant.struct_variant(&["key", "range"], self), - _ => Err(serde::de::Error::unknown_variant( - "_", - &["owned", "account"], - )), - } - } - } - - deserializer.deserialize_enum("evm_buffer", &["owned", "account"], BufferVisitor) - } -} - #[cfg(test)] mod tests { use super::*; - use crate::executor::OwnedAccountInfo; + use crate::{executor::OwnedAccountInfo, vector}; use solana_program::account_info::IntoAccountInfo; macro_rules! assert_slice_ptr_eq { @@ -250,20 +153,20 @@ mod tests { #[test] fn test_deref_owned_empty() { - let data = Vec::default(); + let data = vector![]; let expected = (data.as_ptr(), data.len()); - assert_slice_ptr_eq!(&*Buffer::default(), expected); + assert_slice_ptr_eq!(&*Buffer::from_vector(data), expected); } #[test] fn test_deref_owned_non_empty() { - let data = vec![1]; + let data = vector![1]; let expected = (data.as_ptr(), data.len()); - assert_slice_ptr_eq!(&*Buffer::from_vec(data), expected); + assert_slice_ptr_eq!(&*Buffer::from_vector(data), expected); } impl OwnedAccountInfo { - fn with_data(data: Vec) -> Self { + fn with_data(data: Vector) -> Self { OwnedAccountInfo { key: Pubkey::default(), lamports: 0, @@ -279,7 +182,7 @@ mod tests { #[test] fn test_deref_account_empty() { - let data = Vec::default(); + let data = vector![]; let expected = (data.as_ptr(), data.len()); let mut account_info = OwnedAccountInfo::with_data(data); assert_slice_ptr_eq!( @@ -290,7 +193,7 @@ mod tests { #[test] fn test_deref_account_non_empty() { - let data = vec![1]; + let data = vector![1]; let expected = (data.as_ptr(), data.len()); let mut account_info = OwnedAccountInfo::with_data(data); assert_slice_ptr_eq!( @@ -298,105 +201,4 @@ mod tests { expected ); } - - #[test] - #[cfg(debug_assertions)] - #[should_panic(expected = "assertion failed: !self.ptr.is_null()")] - fn test_deref_account_uninit() { - let _: &[u8] = &Buffer::new(Inner::AccountUninit { - key: Pubkey::default(), - range: 0..0, - }); - } - - #[test] - fn historic_empty_deserialization_works() { - let serialized = [ - 0, 0, 0, 0, // Variant - ]; - let deserialized = Buffer::empty(); - assert_eq!( - bincode::deserialize::(&serialized).unwrap(), - deserialized - ); - } - - #[test] - fn non_empty_owned_serialization_works() { - let deserialized = Buffer::from_vec(vec![0xcc; 3]); - let serialized = [ - 1, 0, 0, 0, // Variant - 3, 0, 0, 0, 0, 0, 0, 0, // Byte count - 0xcc, 0xcc, 0xcc, // Bytes - ]; - assert_eq!(bincode::serialize(&deserialized).unwrap(), serialized); - } - - #[test] - fn non_empty_owned_deserialization_works() { - let serialized = [ - 1, 0, 0, 0, // Variant - 3, 0, 0, 0, 0, 0, 0, 0, // Byte count - 0xcc, 0xcc, 0xcc, // Bytes - ]; - let deserialized = Buffer::from_vec(vec![0xcc; 3]); - assert_eq!( - bincode::deserialize::(&serialized).unwrap(), - deserialized - ); - } - - #[test] - fn non_empty_account_serialization_works() { - let mut account = OwnedAccountInfo { - key: Pubkey::from([0xaa; 32]), - is_signer: false, - is_writable: false, - lamports: 0, - data: vec![0xcc; 10], - owner: Pubkey::from([0xbb; 32]), - executable: false, - rent_epoch: 0, - }; - let deserialized = unsafe { Buffer::from_account(&account.into_account_info(), 6..8) }; - let serialized = [ - 2, 0, 0, 0, // Variant - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, // Pubkey - 6, 0, 0, 0, 0, 0, 0, 0, // Range start - 8, 0, 0, 0, 0, 0, 0, 0, // Range end - ]; - assert_eq!(bincode::serialize(&deserialized).unwrap(), serialized); - } - - #[test] - fn non_empty_account_deserialization_works() { - let serialized = [ - 2, 0, 0, 0, // Variant - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, // Pubkey - 6, 0, 0, 0, 0, 0, 0, 0, // Range start - 8, 0, 0, 0, 0, 0, 0, 0, // Range end - ]; - let deserialized = Buffer::new(Inner::AccountUninit { - key: Pubkey::from([0xaa; 32]), - range: 6..8, - }); - assert_eq!( - bincode::deserialize::(&serialized).unwrap(), - deserialized - ); - } - - #[test] - #[should_panic(expected = "unreachable")] - fn account_uninit_serialization_fails() { - let _: Vec = bincode::serialize(&Buffer::new(Inner::AccountUninit { - key: Pubkey::default(), - range: 0..0, - })) - .unwrap(); - } } diff --git a/evm_loader/program/src/evm/database.rs b/evm_loader/program/src/evm/database.rs index bad42fff2..8c260a397 100644 --- a/evm_loader/program/src/evm/database.rs +++ b/evm_loader/program/src/evm/database.rs @@ -1,5 +1,6 @@ use super::{Buffer, Context}; use crate::account_storage::LogCollector; +use crate::types::Vector; use crate::{error::Result, executor::OwnedAccountInfo, types::Address}; use ethnum::U256; use maybe_async::maybe_async; @@ -33,7 +34,7 @@ pub trait Database: LogCollector { async fn code_size(&self, address: Address) -> Result; async fn code(&self, address: Address) -> Result; - async fn set_code(&mut self, address: Address, chain_id: u64, code: Vec) -> Result<()>; + async fn set_code(&mut self, address: Address, chain_id: u64, code: Vector) -> Result<()>; async fn storage(&self, address: Address, index: U256) -> Result<[u8; 32]>; async fn set_storage(&mut self, address: Address, index: U256, value: [u8; 32]) -> Result<()>; @@ -65,7 +66,7 @@ pub trait Database: LogCollector { async fn queue_external_instruction( &mut self, instruction: Instruction, - seeds: Vec>>, + seeds: Vector>>, fee: u64, emulated_internally: bool, ) -> Result<()>; @@ -76,7 +77,7 @@ pub trait Database: LogCollector { address: &Address, data: &[u8], is_static: bool, - ) -> Option>>; + ) -> Option>>; } /// Provides convenience methods that can be implemented in terms of `Database`. diff --git a/evm_loader/program/src/evm/memory.rs b/evm_loader/program/src/evm/memory.rs index 0e95034e1..514f0df3e 100644 --- a/evm_loader/program/src/evm/memory.rs +++ b/evm_loader/program/src/evm/memory.rs @@ -1,6 +1,7 @@ use std::alloc::{GlobalAlloc, Layout}; use std::ops::Range; +use crate::allocator::acc_allocator; use solana_program::program_memory::{sol_memcpy, sol_memmove, sol_memset}; use crate::error::Error; @@ -14,6 +15,7 @@ const MEMORY_ALIGN: usize = 1; static_assertions::const_assert!(MEMORY_ALIGN.is_power_of_two()); +#[repr(C)] pub struct Memory { data: *mut u8, capacity: usize, @@ -28,7 +30,7 @@ impl Memory { pub fn with_capacity(capacity: usize) -> Self { unsafe { let layout = Layout::from_size_align_unchecked(capacity, MEMORY_ALIGN); - let data = crate::allocator::EVM.alloc_zeroed(layout); + let data = acc_allocator().alloc_zeroed(layout); if data.is_null() { std::alloc::handle_alloc_error(layout); } @@ -41,26 +43,6 @@ impl Memory { } } - pub fn from_buffer(v: &[u8]) -> Self { - let capacity = v.len().next_power_of_two().max(MEMORY_CAPACITY); - - unsafe { - let layout = Layout::from_size_align_unchecked(capacity, MEMORY_ALIGN); - let data = crate::allocator::EVM.alloc_zeroed(layout); - if data.is_null() { - std::alloc::handle_alloc_error(layout); - } - - std::ptr::copy_nonoverlapping(v.as_ptr(), data, v.len()); - - Self { - data, - capacity, - size: v.len(), - } - } - } - #[cfg(not(target_os = "solana"))] pub fn to_vec(&self) -> Vec { let slice = unsafe { std::slice::from_raw_parts(self.data, self.size) }; @@ -93,7 +75,7 @@ impl Memory { unsafe { let old_layout = Layout::from_size_align_unchecked(self.capacity, MEMORY_ALIGN); - let new_data = crate::allocator::EVM.realloc(self.data, old_layout, new_capacity); + let new_data = acc_allocator().realloc(self.data, old_layout, new_capacity); if new_data.is_null() { let layout = Layout::from_size_align_unchecked(new_capacity, MEMORY_ALIGN); std::alloc::handle_alloc_error(layout); @@ -240,47 +222,7 @@ impl Drop for Memory { fn drop(&mut self) { unsafe { let layout = Layout::from_size_align_unchecked(self.capacity, MEMORY_ALIGN); - crate::allocator::EVM.dealloc(self.data, layout); + acc_allocator().dealloc(self.data, layout); } } } - -impl serde::Serialize for Memory { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let data = unsafe { std::slice::from_raw_parts(self.data, self.capacity) }; - serializer.serialize_bytes(&data[..self.size()]) - } -} - -impl<'de> serde::Deserialize<'de> for Memory { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - struct BytesVisitor; - - impl<'de> serde::de::Visitor<'de> for BytesVisitor { - type Value = Memory; - - fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.write_str("EVM Memory") - } - - fn visit_bytes(self, v: &[u8]) -> Result - where - E: serde::de::Error, - { - if v.len() % 32 != 0 { - return Err(E::invalid_length(v.len(), &self)); - } - - Ok(Memory::from_buffer(v)) - } - } - - deserializer.deserialize_bytes(BytesVisitor) - } -} diff --git a/evm_loader/program/src/evm/mod.rs b/evm_loader/program/src/evm/mod.rs index f409893b3..ad4f50fca 100644 --- a/evm_loader/program/src/evm/mod.rs +++ b/evm_loader/program/src/evm/mod.rs @@ -3,23 +3,22 @@ #![allow(clippy::unsafe_derive_deserialize)] #![allow(clippy::future_not_send)] -use std::{fmt::Display, marker::PhantomData, ops::Range}; +use std::{fmt::Display, marker::PhantomData, mem::ManuallyDrop, ops::Range}; use ethnum::U256; use maybe_async::maybe_async; -use serde::{Deserialize, Serialize}; pub use buffer::Buffer; -use crate::evm::tracing::EventListener; #[cfg(target_os = "solana")] use crate::evm::tracing::NoopEventListener; use crate::{ debug::log_data, error::{build_revert_message, Error, Result}, evm::{opcode::Action, precompile::is_precompile_address}, - types::{Address, Transaction}, + types::{Address, Transaction, Vector}, }; +use crate::{evm::tracing::EventListener, types::boxx::Boxx}; use self::{database::Database, memory::Memory, stack::Stack}; @@ -104,11 +103,12 @@ pub(crate) use begin_vm; pub(crate) use end_vm; pub(crate) use tracing_event; -#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, Eq, PartialEq)] +#[repr(C)] pub enum ExitStatus { Stop, - Return(#[serde(with = "serde_bytes")] Vec), - Revert(#[serde(with = "serde_bytes")] Vec), + Return(Vector), + Revert(Vector), Suicide, StepLimit, } @@ -141,39 +141,37 @@ impl ExitStatus { #[must_use] pub fn into_result(self) -> Option> { match self { - ExitStatus::Return(v) | ExitStatus::Revert(v) => Some(v), + ExitStatus::Return(v) | ExitStatus::Revert(v) => Some(v.to_vec()), ExitStatus::Stop | ExitStatus::Suicide | ExitStatus::StepLimit => None, } } } -#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Eq, PartialEq)] +#[repr(C)] pub enum Reason { Call, Create, } -#[derive(Debug, Copy, Clone, Serialize, Deserialize)] +#[derive(Debug, Copy, Clone)] +#[repr(C)] pub struct Context { pub caller: Address, pub contract: Address, pub contract_chain_id: u64, - #[serde(with = "ethnum::serde::bytes::le")] pub value: U256, pub code_address: Option
, } -#[derive(Serialize, Deserialize)] -#[serde(bound = "B: Database")] +#[repr(C)] pub struct Machine { origin: Address, chain_id: u64, context: Context, - #[serde(with = "ethnum::serde::bytes::le")] gas_price: U256, - #[serde(with = "ethnum::serde::bytes::le")] gas_limit: U256, execution_code: Buffer, @@ -188,53 +186,33 @@ pub struct Machine { is_static: bool, reason: Reason, - parent: Option>, + parent: Option>, - #[serde(skip)] phantom: PhantomData<*const B>, - #[serde(skip)] tracer: Option, } #[cfg(target_os = "solana")] impl Machine { - pub fn serialize_into(&self, buffer: &mut [u8]) -> Result { - let mut cursor = std::io::Cursor::new(buffer); - - bincode::serialize_into(&mut cursor, &self)?; - - cursor.position().try_into().map_err(Error::from) - } - - pub fn deserialize_from(buffer: &[u8], backend: &B) -> Result { - fn reinit_buffer(buffer: &mut Buffer, backend: &B) { - if let Some((key, range)) = buffer.uninit_data() { - *buffer = - backend.map_solana_account(&key, |i| unsafe { Buffer::from_account(i, range) }); - } + fn reinit_buffer(buffer: &mut Buffer, backend: &B) { + if let Some((key, range)) = buffer.uninit_data() { + *buffer = + backend.map_solana_account(&key, |i| unsafe { Buffer::from_account(i, range) }); } + } - fn reinit_machine( - mut machine: &mut Machine, - backend: &B, - ) { - loop { - reinit_buffer(&mut machine.call_data, backend); - reinit_buffer(&mut machine.execution_code, backend); - reinit_buffer(&mut machine.return_data, backend); - - match &mut machine.parent { - None => break, - Some(parent) => machine = parent, - } + pub fn reinit(&mut self, backend: &B) { + let mut machine = self; + loop { + Self::reinit_buffer(&mut machine.call_data, backend); + Self::reinit_buffer(&mut machine.execution_code, backend); + Self::reinit_buffer(&mut machine.return_data, backend); + match &mut machine.parent { + None => break, + Some(parent) => machine = parent, } } - - let mut evm: Self = bincode::deserialize(buffer)?; - reinit_machine(&mut evm, backend); - - Ok(evm) } } @@ -369,10 +347,6 @@ impl Machine { step_limit: u64, backend: &mut B, ) -> Result<(ExitStatus, u64, Option)> { - assert!(self.execution_code.is_initialized()); - assert!(self.call_data.is_initialized()); - assert!(self.return_data.is_initialized()); - let mut step = 0_u64; begin_vm!( @@ -461,17 +435,17 @@ impl Machine { }; core::mem::swap(self, &mut other); - self.parent = Some(Box::new(other)); + self.parent = Some(crate::types::boxx::boxx(other)); } - fn join(&mut self) -> Self { + fn join(&mut self) -> ManuallyDrop> { assert!(self.parent.is_some()); - let mut other = *self.parent.take().unwrap(); - core::mem::swap(self, &mut other); + let mut other = self.parent.take().unwrap(); + core::mem::swap(self, other.as_mut()); self.tracer = other.tracer.take(); - other + ManuallyDrop::new(other) } } diff --git a/evm_loader/program/src/evm/opcode.rs b/evm_loader/program/src/evm/opcode.rs index 630a9b102..0c88eb792 100644 --- a/evm_loader/program/src/evm/opcode.rs +++ b/evm_loader/program/src/evm/opcode.rs @@ -1,5 +1,7 @@ #![allow(clippy::needless_pass_by_ref_mut)] +use std::mem::ManuallyDrop; + /// use ethnum::{I256, U256}; use maybe_async::maybe_async; @@ -10,6 +12,8 @@ use super::{ end_vm, tracing_event, Context, Machine, Reason, }; use crate::evm::tracing::EventListener; +use crate::types::vector::VectorSliceExt; +use crate::types::Vector; use crate::{ debug::log_data, error::{Error, Result}, @@ -22,8 +26,8 @@ pub enum Action { Continue, Jump(usize), Stop, - Return(Vec), - Revert(Vec), + Return(Vector), + Revert(Vector), Suicide, Noop, } @@ -1350,7 +1354,7 @@ impl Machine { let offset = self.stack.pop_usize()?; let length = self.stack.pop_usize()?; - let return_data = self.memory.read(offset, length)?.to_vec(); + let return_data = self.memory.read(offset, length)?.to_vector(); self.opcode_return_impl(return_data, backend).await } @@ -1359,13 +1363,12 @@ impl Machine { #[maybe_async] pub async fn opcode_return_impl( &mut self, - mut return_data: Vec, + return_data: Vector, backend: &mut B, ) -> Result { if self.reason == Reason::Create { - let code = std::mem::take(&mut return_data); backend - .set_code(self.context.contract, self.chain_id, code) + .set_code(self.context.contract, self.chain_id, return_data.clone()) .await?; } @@ -1382,13 +1385,13 @@ impl Machine { return Ok(Action::Return(return_data)); } - let returned = self.join(); + let mut returned = self.join(); match returned.reason { Reason::Call => { self.memory.write_range(&self.return_range, &return_data)?; self.stack.push_bool(true)?; // success - self.return_data = Buffer::from_vec(return_data); + self.return_data = Buffer::from_vector(return_data); } Reason::Create => { let address = returned.context.contract; @@ -1396,6 +1399,7 @@ impl Machine { } } + unsafe { ManuallyDrop::drop(&mut returned) }; Ok(Action::Continue) } @@ -1405,7 +1409,7 @@ impl Machine { let offset = self.stack.pop_usize()?; let length = self.stack.pop_usize()?; - let return_data = self.memory.read(offset, length)?.to_vec(); + let return_data = self.memory.read(offset, length)?.to_vector(); self.opcode_revert_impl(return_data, backend).await } @@ -1413,7 +1417,7 @@ impl Machine { #[maybe_async] pub async fn opcode_revert_impl( &mut self, - return_data: Vec, + return_data: Vector, backend: &mut B, ) -> Result { log_data(&[b"EXIT", b"REVERT", &return_data]); @@ -1429,7 +1433,7 @@ impl Machine { return Ok(Action::Revert(return_data)); } - let returned = self.join(); + let mut returned = self.join(); match returned.reason { Reason::Call => { self.memory.write_range(&self.return_range, &return_data)?; @@ -1440,7 +1444,11 @@ impl Machine { } } - self.return_data = Buffer::from_vec(return_data); + self.return_data = Buffer::from_vector(return_data); + + unsafe { + ManuallyDrop::drop(&mut returned); + } Ok(Action::Continue) } @@ -1478,7 +1486,7 @@ impl Machine { return Ok(Action::Suicide); } - let returned = self.join(); + let mut returned = self.join(); match returned.reason { Reason::Call => { self.memory.write_range(&self.return_range, &[])?; @@ -1489,6 +1497,10 @@ impl Machine { } } + unsafe { + ManuallyDrop::drop(&mut returned); + } + Ok(Action::Continue) } @@ -1504,7 +1516,7 @@ impl Machine { return Ok(Action::Stop); } - let returned = self.join(); + let mut returned = self.join(); match returned.reason { Reason::Call => { self.memory.write_range(&self.return_range, &[])?; @@ -1515,6 +1527,10 @@ impl Machine { } } + unsafe { + ManuallyDrop::drop(&mut returned); + } + Ok(Action::Continue) } } diff --git a/evm_loader/program/src/evm/precompile/big_mod_exp.rs b/evm_loader/program/src/evm/precompile/big_mod_exp.rs index 3331f0917..1309088c9 100644 --- a/evm_loader/program/src/evm/precompile/big_mod_exp.rs +++ b/evm_loader/program/src/evm/precompile/big_mod_exp.rs @@ -1,9 +1,13 @@ use ethnum::U256; +use crate::types::vector::VectorVecExt; +use crate::types::Vector; +use crate::vector; + #[must_use] -pub fn big_mod_exp(input: &[u8]) -> Vec { +pub fn big_mod_exp(input: &[u8]) -> Vector { if input.len() < 96 { - return vec![]; + return vector![]; } let (base_len, rest) = input.split_at(32); @@ -11,22 +15,22 @@ pub fn big_mod_exp(input: &[u8]) -> Vec { let (mod_len, rest) = rest.split_at(32); let Ok(base_len) = U256::from_be_bytes(base_len.try_into().unwrap()).try_into() else { - return vec![]; + return vector![]; }; let Ok(exp_len) = U256::from_be_bytes(exp_len.try_into().unwrap()).try_into() else { - return vec![]; + return vector![]; }; let Ok(mod_len) = U256::from_be_bytes(mod_len.try_into().unwrap()).try_into() else { - return vec![]; + return vector![]; }; if base_len == 0 && mod_len == 0 { - return vec![0; 32]; + return vector![0; 32]; } let (base_val, rest) = rest.split_at(base_len); let (exp_val, rest) = rest.split_at(exp_len); let (mod_val, _) = rest.split_at(mod_len); - solana_program::big_mod_exp::big_mod_exp(base_val, exp_val, mod_val) + solana_program::big_mod_exp::big_mod_exp(base_val, exp_val, mod_val).into_vector() } diff --git a/evm_loader/program/src/evm/precompile/blake2_f.rs b/evm_loader/program/src/evm/precompile/blake2_f.rs index 4c984cdcb..b8258d1c5 100644 --- a/evm_loader/program/src/evm/precompile/blake2_f.rs +++ b/evm_loader/program/src/evm/precompile/blake2_f.rs @@ -1,6 +1,10 @@ +use crate::types::vector::VectorSliceExt; +use crate::types::Vector; +use crate::vector; + #[must_use] #[allow(clippy::too_many_lines)] -pub fn blake2_f(input: &[u8]) -> Vec { +pub fn blake2_f(input: &[u8]) -> Vector { const BLAKE2_F_ARG_LEN: usize = 213; debug_print!("blake2F"); @@ -67,7 +71,7 @@ pub fn blake2_f(input: &[u8]) -> Vec { if input.len() != BLAKE2_F_ARG_LEN { // return Err(ExitError::Other("input length for Blake2 F precompile should be exactly 213 bytes".into())); - return Vec::new(); + return vector![]; } let mut rounds_arr: [u8; 4] = Default::default(); @@ -113,7 +117,7 @@ pub fn blake2_f(input: &[u8]) -> Vec { false } else { // return Err(ExitError::Other("incorrect final block indicator flag".into())) - return Vec::new(); + return vector![]; }; compress(&mut h, m, [t_0, t_1], f, rounds as usize); @@ -123,5 +127,5 @@ pub fn blake2_f(input: &[u8]) -> Vec { output_buf[i * 8..(i + 1) * 8].copy_from_slice(&state_word.to_le_bytes()); } - output_buf.to_vec() + output_buf.to_vector() } diff --git a/evm_loader/program/src/evm/precompile/bn256.rs b/evm_loader/program/src/evm/precompile/bn256.rs index a9405cf1d..22ba2ffe5 100644 --- a/evm_loader/program/src/evm/precompile/bn256.rs +++ b/evm_loader/program/src/evm/precompile/bn256.rs @@ -1,22 +1,26 @@ +use crate::types::vector::{VectorSliceExt, VectorVecExt}; +use crate::types::Vector; +use crate::vector; use ethnum::U256; use solana_program::alt_bn128::prelude::*; /// Call inner `bn256Add` #[must_use] -pub fn bn256_add(input: &[u8]) -> Vec { +pub fn bn256_add(input: &[u8]) -> Vector { if input.len() >= ALT_BN128_ADDITION_INPUT_LEN { alt_bn128_addition(&input[..ALT_BN128_ADDITION_INPUT_LEN]) } else { - let mut buffer = vec![0_u8; ALT_BN128_ADDITION_INPUT_LEN]; + let mut buffer = vector![0_u8; ALT_BN128_ADDITION_INPUT_LEN]; buffer[..input.len()].copy_from_slice(input); alt_bn128_addition(&buffer) } .unwrap() + .into_vector() } /// Call inner `bn256ScalarMul` #[must_use] -pub fn bn256_scalar_mul(input: &[u8]) -> Vec { +pub fn bn256_scalar_mul(input: &[u8]) -> Vector { if input.len() >= ALT_BN128_MULTIPLICATION_INPUT_LEN { alt_bn128_multiplication(&input[..ALT_BN128_MULTIPLICATION_INPUT_LEN]) } else { @@ -25,18 +29,19 @@ pub fn bn256_scalar_mul(input: &[u8]) -> Vec { alt_bn128_multiplication(&buffer) } .unwrap() + .into_vector() } /// Call inner `bn256Pairing` #[must_use] -pub fn bn256_pairing(input: &[u8]) -> Vec { +pub fn bn256_pairing(input: &[u8]) -> Vector { if input.is_empty() { - return U256::ONE.to_be_bytes().to_vec(); + return U256::ONE.to_be_bytes().to_vector(); } if (input.len() % ALT_BN128_PAIRING_ELEMENT_LEN) != 0 { - return U256::ZERO.to_be_bytes().to_vec(); + return U256::ZERO.to_be_bytes().to_vector(); } - alt_bn128_pairing(input).unwrap() + alt_bn128_pairing(input).unwrap().into_vector() } diff --git a/evm_loader/program/src/evm/precompile/datacopy.rs b/evm_loader/program/src/evm/precompile/datacopy.rs index 37e3c8715..ca61ee455 100644 --- a/evm_loader/program/src/evm/precompile/datacopy.rs +++ b/evm_loader/program/src/evm/precompile/datacopy.rs @@ -1,6 +1,9 @@ +use crate::types::vector::VectorSliceExt; +use crate::types::Vector; + #[must_use] -pub fn datacopy(input: &[u8]) -> Vec { +pub fn datacopy(input: &[u8]) -> Vector { debug_print!("datacopy"); - input.to_vec() + input.to_vector() } diff --git a/evm_loader/program/src/evm/precompile/ecrecover.rs b/evm_loader/program/src/evm/precompile/ecrecover.rs index 2f8140325..6d5dda6a3 100644 --- a/evm_loader/program/src/evm/precompile/ecrecover.rs +++ b/evm_loader/program/src/evm/precompile/ecrecover.rs @@ -1,3 +1,6 @@ +use crate::types::vector::VectorSliceExt; +use crate::types::Vector; +use crate::vector; use arrayref::{array_ref, array_refs}; use ethnum::U256; use solana_program::keccak; @@ -5,7 +8,7 @@ use solana_program::secp256k1_recover::secp256k1_recover; #[allow(clippy::manual_let_else)] #[must_use] -pub fn ecrecover(input: &[u8]) -> Vec { +pub fn ecrecover(input: &[u8]) -> Vector { debug_print!("ecrecover"); let input = if input.len() >= 128 { @@ -21,18 +24,18 @@ pub fn ecrecover(input: &[u8]) -> Vec { let v = U256::from_be_bytes(*v); if !(27..=30).contains(&v) { - return vec![]; + return vector![]; } let recovery_id = v.as_u8() - 27; let Ok(public_key) = secp256k1_recover(&msg[..], recovery_id, &sig[..]) else { - return vec![]; + return vector![]; }; let mut address = keccak::hash(&public_key.to_bytes()).to_bytes(); address[0..12].fill(0); debug_print!("{}", hex::encode(address)); - address.to_vec() + address.to_vector() } diff --git a/evm_loader/program/src/evm/precompile/mod.rs b/evm_loader/program/src/evm/precompile/mod.rs index c22b65a8b..f75881b81 100644 --- a/evm_loader/program/src/evm/precompile/mod.rs +++ b/evm_loader/program/src/evm/precompile/mod.rs @@ -1,6 +1,6 @@ use crate::evm::tracing::EventListener; use crate::evm::{database::Database, Machine}; -use crate::types::Address; +use crate::types::{Address, Vector}; mod big_mod_exp; mod blake2_f; @@ -59,7 +59,7 @@ pub fn is_precompile_address(address: &Address) -> bool { impl Machine { #[must_use] - pub fn precompile(address: &Address, data: &[u8]) -> Option> { + pub fn precompile(address: &Address, data: &[u8]) -> Option> { match *address { SYSTEM_ACCOUNT_ECRECOVER => Some(ecrecover::ecrecover(data)), SYSTEM_ACCOUNT_SHA_256 => Some(sha256::sha256(data)), diff --git a/evm_loader/program/src/evm/precompile/ripemd160.rs b/evm_loader/program/src/evm/precompile/ripemd160.rs index 3c38728f0..7a718f441 100644 --- a/evm_loader/program/src/evm/precompile/ripemd160.rs +++ b/evm_loader/program/src/evm/precompile/ripemd160.rs @@ -1,5 +1,8 @@ +use crate::types::Vector; +use crate::vector; + #[must_use] -pub fn ripemd160(input: &[u8]) -> Vec { +pub fn ripemd160(input: &[u8]) -> Vector { use ripemd::{Digest, Ripemd160}; debug_print!("ripemd160"); @@ -11,7 +14,7 @@ pub fn ripemd160(input: &[u8]) -> Vec { let hash_val = hasher.finalize(); // transform to [u8; 32] - let mut result = vec![0_u8; 12]; + let mut result = vector![0_u8; 12]; result.extend(&hash_val[..]); result diff --git a/evm_loader/program/src/evm/precompile/sha256.rs b/evm_loader/program/src/evm/precompile/sha256.rs index eec4915dd..e67577343 100644 --- a/evm_loader/program/src/evm/precompile/sha256.rs +++ b/evm_loader/program/src/evm/precompile/sha256.rs @@ -1,10 +1,13 @@ +use crate::types::vector::VectorSliceExt; +use crate::types::Vector; + #[must_use] -pub fn sha256(input: &[u8]) -> Vec { +pub fn sha256(input: &[u8]) -> Vector { use solana_program::hash::hash as sha256_digest; debug_print!("sha256"); let hash = sha256_digest(input); - hash.to_bytes().to_vec() + hash.to_bytes().to_vector() } diff --git a/evm_loader/program/src/evm/stack.rs b/evm_loader/program/src/evm/stack.rs index 8d8b322ba..2dcb17fb6 100644 --- a/evm_loader/program/src/evm/stack.rs +++ b/evm_loader/program/src/evm/stack.rs @@ -7,11 +7,13 @@ use std::{ use ethnum::{I256, U256}; +use crate::allocator::acc_allocator; use crate::{error::Error, types::Address}; const ELEMENT_SIZE: usize = 32; const STACK_SIZE: usize = ELEMENT_SIZE * 128; +#[repr(C)] pub struct Stack { begin: *mut u8, end: *mut u8, @@ -22,7 +24,7 @@ impl Stack { pub fn new() -> Self { let (begin, end) = unsafe { let layout = Layout::from_size_align_unchecked(STACK_SIZE, ELEMENT_SIZE); - let begin = crate::allocator::EVM.alloc(layout); + let begin = acc_allocator().alloc(layout); if begin.is_null() { std::alloc::handle_alloc_error(layout); } @@ -259,59 +261,7 @@ impl Drop for Stack { fn drop(&mut self) { unsafe { let layout = Layout::from_size_align_unchecked(STACK_SIZE, ELEMENT_SIZE); - crate::allocator::EVM.dealloc(self.begin, layout); + acc_allocator().dealloc(self.begin, layout); } } } - -impl serde::Serialize for Stack { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - unsafe { - let data = std::slice::from_raw_parts(self.begin, STACK_SIZE); - let offset: usize = self.top.offset_from(self.begin).try_into().unwrap(); - - serializer.serialize_bytes(&data[..offset]) - } - } -} - -impl<'de> serde::Deserialize<'de> for Stack { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - struct BytesVisitor; - - impl<'de> serde::de::Visitor<'de> for BytesVisitor { - type Value = Stack; - - fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.write_str("EVM Stack") - } - - fn visit_bytes(self, v: &[u8]) -> Result - where - E: serde::de::Error, - { - if v.len() % 32 != 0 { - return Err(E::invalid_length(v.len(), &self)); - } - - let mut stack = Stack::new(); - unsafe { - stack.top = stack.begin.add(v.len()); - - let slice = std::slice::from_raw_parts_mut(stack.begin, v.len()); - slice.copy_from_slice(v); - } - - Ok(stack) - } - } - - deserializer.deserialize_bytes(BytesVisitor) - } -} diff --git a/evm_loader/program/src/executor/action.rs b/evm_loader/program/src/executor/action.rs index 0705b77f2..10d5c2e6a 100644 --- a/evm_loader/program/src/executor/action.rs +++ b/evm_loader/program/src/executor/action.rs @@ -1,17 +1,18 @@ +use std::fmt::Debug; + use ethnum::U256; -use serde::{Deserialize, Serialize}; use solana_program::{instruction::AccountMeta, pubkey::Pubkey}; -use crate::types::{serde::bytes_32, Address}; +use crate::types::{vector::Vector, Address}; -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone)] +#[repr(C)] pub enum Action { ExternalInstruction { program_id: Pubkey, - accounts: Vec, - #[serde(with = "serde_bytes")] - data: Vec, - seeds: Vec>>, + accounts: Vector, + data: Vector, + seeds: Vector>>, fee: u64, emulated_internally: bool, }, @@ -19,27 +20,21 @@ pub enum Action { source: Address, target: Address, chain_id: u64, - #[serde(with = "ethnum::serde::bytes::le")] value: U256, }, Burn { source: Address, chain_id: u64, - #[serde(with = "ethnum::serde::bytes::le")] value: U256, }, EvmSetStorage { address: Address, - #[serde(with = "ethnum::serde::bytes::le")] index: U256, - #[serde(with = "bytes_32")] value: [u8; 32], }, EvmSetTransientStorage { address: Address, - #[serde(with = "ethnum::serde::bytes::le")] index: U256, - #[serde(with = "bytes_32")] value: [u8; 32], }, EvmIncrementNonce { @@ -49,7 +44,6 @@ pub enum Action { EvmSetCode { address: Address, chain_id: u64, - #[serde(with = "serde_bytes")] - code: Vec, + code: Vector, }, } diff --git a/evm_loader/program/src/executor/cache.rs b/evm_loader/program/src/executor/cache.rs index ad4a5db90..487dbb0b3 100644 --- a/evm_loader/program/src/executor/cache.rs +++ b/evm_loader/program/src/executor/cache.rs @@ -1,17 +1,19 @@ use std::{cell::RefCell, rc::Rc}; use ethnum::U256; -use serde::{Deserialize, Serialize}; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; -#[derive(Clone, Serialize, Deserialize)] +use crate::types::vector::VectorSliceExt; +use crate::{types::Vector, vector}; + +#[derive(Clone)] +#[repr(C)] pub struct OwnedAccountInfo { pub key: Pubkey, pub is_signer: bool, pub is_writable: bool, pub lamports: u64, - #[serde(with = "serde_bytes")] - pub data: Vec, + pub data: Vector, pub owner: Pubkey, pub executable: bool, pub rent_epoch: solana_program::clock::Epoch, @@ -28,9 +30,9 @@ impl OwnedAccountInfo { data: if info.executable || (info.owner == program_id) { // This is only used to emulate external programs // They don't use data in our accounts - vec![] + vector![] } else { - info.data.borrow().to_vec() + info.data.borrow().to_vector() }, owner: *info.owner, executable: info.executable, @@ -54,10 +56,8 @@ impl<'a> solana_program::account_info::IntoAccountInfo<'a> for &'a mut OwnedAcco } } -#[derive(Serialize, Deserialize)] +#[repr(C)] pub struct Cache { - #[serde(with = "ethnum::serde::bytes::le")] pub block_number: U256, - #[serde(with = "ethnum::serde::bytes::le")] pub block_timestamp: U256, } diff --git a/evm_loader/program/src/executor/mod.rs b/evm_loader/program/src/executor/mod.rs index 5de732354..200a3d8ad 100644 --- a/evm_loader/program/src/executor/mod.rs +++ b/evm_loader/program/src/executor/mod.rs @@ -7,4 +7,5 @@ mod synced_state; pub use action::Action; pub use cache::OwnedAccountInfo; pub use state::ExecutorState; +pub use state::ExecutorStateData; pub use synced_state::SyncedExecutorState; diff --git a/evm_loader/program/src/executor/precompile_extension/call_solana.rs b/evm_loader/program/src/executor/precompile_extension/call_solana.rs index 1c618602d..6c6206d2c 100644 --- a/evm_loader/program/src/executor/precompile_extension/call_solana.rs +++ b/evm_loader/program/src/executor/precompile_extension/call_solana.rs @@ -1,10 +1,13 @@ use crate::{ account_storage::FAKE_OPERATOR, + allocator::acc_allocator, config::ACCOUNT_SEED_VERSION, error::{Error, Result}, evm::database::Database, - types::Address, + types::{vector::VectorSliceExt, Address, Vector}, + vector, }; + use arrayref::array_ref; use ethnum::U256; use maybe_async::maybe_async; @@ -34,7 +37,7 @@ pub async fn call_solana( input: &[u8], context: &crate::evm::Context, is_static: bool, -) -> Result> { +) -> Result> { if context.value != 0 { return Err(Error::Custom("CallSolana: value != 0".to_string())); } @@ -66,10 +69,10 @@ pub async fn call_solana( let signer = context.caller; let (_signer_pubkey, bump_seed) = state.contract_pubkey(signer); - let signer_seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], + let signer_seeds = vector![ + vector![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vector(), + vector![bump_seed], ]; execute_external_instruction( @@ -101,12 +104,12 @@ pub async fn call_solana( salt, ]; let (_, signer_seed) = Pubkey::find_program_address(seeds, state.program_id()); - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - b"AUTH".to_vec(), - context.caller.as_bytes().to_vec(), - salt.to_vec(), - vec![signer_seed], + let seeds = vector![ + vector![ACCOUNT_SEED_VERSION], + b"AUTH".to_vector(), + context.caller.as_bytes().to_vector(), + salt.to_vector(), + vector![signer_seed], ]; execute_external_instruction(state, context, instruction, seeds, required_lamports) @@ -126,10 +129,10 @@ pub async fn call_solana( let signer = context.caller; let (_signer_pubkey, bump_seed) = state.contract_pubkey(signer); - let signer_seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], + let signer_seeds = vector![ + vector![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vector(), + vector![bump_seed], ]; execute_external_instruction( @@ -160,12 +163,12 @@ pub async fn call_solana( salt, ]; let (_, signer_seed) = Pubkey::find_program_address(seeds, state.program_id()); - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - b"AUTH".to_vec(), - context.caller.as_bytes().to_vec(), - salt.to_vec(), - vec![signer_seed], + let seeds = vector![ + vector![ACCOUNT_SEED_VERSION], + b"AUTH".to_vector(), + context.caller.as_bytes().to_vector(), + salt.to_vector(), + vector![signer_seed], ]; execute_external_instruction(state, context, instruction, seeds, required_lamports) @@ -176,7 +179,7 @@ pub async fn call_solana( [0x15, 0x4d, 0x4a, 0xa5] => { let neon_addess = Address::from(*array_ref![input, 12, 20]); let sol_address = state.contract_pubkey(neon_addess).0; - Ok(sol_address.to_bytes().to_vec()) + Ok(sol_address.to_bytes().to_vector()) } // "59e4ad63": "getResourceAddress(bytes32)" @@ -189,7 +192,7 @@ pub async fn call_solana( salt, ]; let (sol_address, _) = Pubkey::find_program_address(seeds, state.program_id()); - Ok(sol_address.to_bytes().to_vec()) + Ok(sol_address.to_bytes().to_vector()) } // "cd2d1a3a": "getExtAuthority(bytes32)" @@ -202,7 +205,7 @@ pub async fn call_solana( salt, ]; let (sol_address, _) = Pubkey::find_program_address(seeds, state.program_id()); - Ok(sol_address.to_bytes().to_vec()) + Ok(sol_address.to_bytes().to_vector()) } // "4a890f31": "getSolanaPDA(bytes32,bytes)" @@ -210,7 +213,7 @@ pub async fn call_solana( let program_id = read_pubkey(&input[0..])?; let offset = read_usize(&input[32..])?; let length = read_usize(&input[offset..])?; - let mut seeds = Vec::with_capacity((length + 31) / 32); + let mut seeds = Vector::with_capacity_in((length + 31) / 32, acc_allocator()); for i in 0..length / 32 { seeds.push(&input[offset + 32 + i * 32..offset + 32 + (i + 1) * 32]); } @@ -218,7 +221,7 @@ pub async fn call_solana( seeds.push(&input[offset + 32 + length - length % 32..offset + 32 + length]); } let (sol_address, _) = Pubkey::find_program_address(&seeds, &program_id); - Ok(sol_address.to_bytes().to_vec()) + Ok(sol_address.to_bytes().to_vector()) } // "30aa81c6": "getPayer()" @@ -226,7 +229,7 @@ pub async fn call_solana( let seeds: &[&[u8]] = &[&[ACCOUNT_SEED_VERSION], b"PAYER", context.caller.as_bytes()]; let (sol_address, _bump_seed) = Pubkey::find_program_address(seeds, state.program_id()); - Ok(sol_address.to_bytes().to_vec()) + Ok(sol_address.to_bytes().to_vector()) } // "cfd51d32": "createResource(bytes32,uint64,uint64,bytes32)" @@ -250,16 +253,16 @@ pub async fn call_solana( state.program_id(), ); let account = state.external_account(sol_address).await?; - let seeds: Vec> = vec![ - vec![ACCOUNT_SEED_VERSION], - b"ContractData".to_vec(), - context.caller.as_bytes().to_vec(), - salt.to_vec(), - vec![bump_seed], + let seeds: Vector> = vector![ + vector![ACCOUNT_SEED_VERSION], + b"ContractData".to_vector(), + context.caller.as_bytes().to_vector(), + salt.to_vector(), + vector![bump_seed], ]; super::create_account(state, &account, space, &owner, seeds).await?; - Ok(sol_address.to_bytes().to_vec()) + Ok(sol_address.to_bytes().to_vector()) } // "cff5c1a5": "getReturnData()", @@ -267,7 +270,7 @@ pub async fn call_solana( let return_value = match state.return_data() { Some((program, data)) => { let data_len = (data.len() + 31) & (!31); - let mut result = vec![0_u8; 32 + 32 + 32 + data_len]; + let mut result = vector![0_u8; 32 + 32 + 32 + data_len]; result[0..32].copy_from_slice(&program.to_bytes()); result[63] = 0x40; // offset - 64 bytes @@ -279,7 +282,7 @@ pub async fn call_solana( result } None => { - vec![ + vector![ // program_id 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -308,9 +311,9 @@ async fn execute_external_instruction( state: &mut State, context: &crate::evm::Context, instruction: Instruction, - signer_seeds: Vec>, + signer_seeds: Vector>, required_lamports: u64, -) -> Result> { +) -> Result> { #[cfg(not(target_os = "solana"))] log::info!("instruction: {:?}", instruction); @@ -339,11 +342,11 @@ async fn execute_external_instruction( .any(|meta| meta.pubkey == payer_pubkey); if required_payer { - let payer_seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - b"PAYER".to_vec(), - context.caller.as_bytes().to_vec(), - vec![payer_bump_seed], + let payer_seeds = vector![ + vector![ACCOUNT_SEED_VERSION], + b"PAYER".to_vector(), + context.caller.as_bytes().to_vector(), + vector![payer_bump_seed], ]; let payer = state.external_account(payer_pubkey).await?; @@ -354,14 +357,14 @@ async fn execute_external_instruction( required_lamports - payer.lamports, ); state - .queue_external_instruction(transfer_instruction, vec![], 0, false) + .queue_external_instruction(transfer_instruction, vector![], 0, false) .await?; } state .queue_external_instruction( instruction, - vec![signer_seeds, payer_seeds.clone()], + vector![signer_seeds, payer_seeds.clone()], required_lamports, false, ) @@ -375,12 +378,17 @@ async fn execute_external_instruction( payer.lamports, ); state - .queue_external_instruction(transfer_instruction, vec![payer_seeds], 0, false) + .queue_external_instruction(transfer_instruction, vector![payer_seeds], 0, false) .await?; } } else { state - .queue_external_instruction(instruction, vec![signer_seeds], required_lamports, false) + .queue_external_instruction( + instruction, + vector![signer_seeds], + required_lamports, + false, + ) .await?; } @@ -463,14 +471,14 @@ fn read_salt(input: &[u8]) -> Result<&[u8; 32]> { Ok(arrayref::array_ref![input, 0, 32]) } -fn to_solidity_bytes(b: &[u8]) -> Vec { +fn to_solidity_bytes(b: &[u8]) -> Vector { // Bytes encoding // 32 bytes - offset // 32 bytes - length // length + padding bytes - data let data_len = (b.len() + 31) & (!31); - let mut result = vec![0_u8; 32 + 32 + data_len]; + let mut result = vector![0_u8; 32 + 32 + data_len]; result[31] = 0x20; // offset - 32 bytes diff --git a/evm_loader/program/src/executor/precompile_extension/metaplex.rs b/evm_loader/program/src/executor/precompile_extension/metaplex.rs index 5df716274..69c174d54 100644 --- a/evm_loader/program/src/executor/precompile_extension/metaplex.rs +++ b/evm_loader/program/src/executor/precompile_extension/metaplex.rs @@ -12,6 +12,9 @@ use mpl_token_metadata::{ }; use solana_program::pubkey::Pubkey; +use crate::types::vector::VectorSliceExt; +use crate::types::Vector; +use crate::vector; use crate::{ account::ACCOUNT_SEED_VERSION, account_storage::FAKE_OPERATOR, @@ -66,7 +69,7 @@ pub async fn metaplex( input: &[u8], context: &crate::evm::Context, is_static: bool, -) -> Result> { +) -> Result> { if context.value != 0 { return Err(Error::Custom("Metaplex: value != 0".to_string())); } @@ -185,14 +188,14 @@ async fn create_metadata( name: String, symbol: String, uri: String, -) -> Result> { +) -> Result> { let signer = context.caller; let (signer_pubkey, bump_seed) = state.contract_pubkey(signer); - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], + let seeds = vector![ + vector![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vector(), + vector![bump_seed], ]; let (metadata_pubkey, _) = Metadata::find_pda(&mint); @@ -228,10 +231,10 @@ async fn create_metadata( let fee = state.rent().minimum_balance(MAX_METADATA_LEN) + CREATE_FEE; state - .queue_external_instruction(instruction, vec![seeds], fee, true) + .queue_external_instruction(instruction, vector![seeds], fee, true) .await?; - Ok(metadata_pubkey.to_bytes().to_vec()) + Ok(metadata_pubkey.to_bytes().to_vector()) } #[maybe_async] @@ -240,14 +243,14 @@ async fn create_master_edition( state: &mut State, mint: Pubkey, max_supply: Option, -) -> Result> { +) -> Result> { let signer = context.caller; let (signer_pubkey, bump_seed) = state.contract_pubkey(signer); - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], + let seeds = vector![ + vector![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vector(), + vector![bump_seed], ]; let (metadata_pubkey, _) = Metadata::find_pda(&mint); @@ -270,10 +273,10 @@ async fn create_master_edition( let fee = state.rent().minimum_balance(MAX_MASTER_EDITION_LEN) + CREATE_FEE; state - .queue_external_instruction(instruction, vec![seeds], fee, true) + .queue_external_instruction(instruction, vector![seeds], fee, true) .await?; - Ok(edition_pubkey.to_bytes().to_vec()) + Ok(edition_pubkey.to_bytes().to_vector()) } #[maybe_async] @@ -281,7 +284,7 @@ async fn is_initialized( context: &crate::evm::Context, state: &State, mint: Pubkey, -) -> Result> { +) -> Result> { let is_initialized = metadata(context, state, mint) .await? .map_or_else(|| false, |_| true); @@ -294,7 +297,7 @@ async fn is_nft( context: &crate::evm::Context, state: &State, mint: Pubkey, -) -> Result> { +) -> Result> { let is_nft = metadata(context, state, mint).await?.map_or_else( || false, |m| m.token_standard == Some(TokenStandard::NonFungible), @@ -308,7 +311,7 @@ async fn uri( context: &crate::evm::Context, state: &State, mint: Pubkey, -) -> Result> { +) -> Result> { let uri = metadata(context, state, mint) .await? .map_or_else(String::new, |m| m.uri); @@ -321,7 +324,7 @@ async fn token_name( context: &crate::evm::Context, state: &State, mint: Pubkey, -) -> Result> { +) -> Result> { let token_name = metadata(context, state, mint) .await? .map_or_else(String::new, |m| m.name); @@ -334,7 +337,7 @@ async fn symbol( context: &crate::evm::Context, state: &State, mint: Pubkey, -) -> Result> { +) -> Result> { let symbol = metadata(context, state, mint) .await? .map_or_else(String::new, |m| m.symbol); @@ -362,13 +365,13 @@ async fn metadata( Ok(result) } -fn to_solidity_bool(v: bool) -> Vec { - let mut result = vec![0_u8; 32]; +fn to_solidity_bool(v: bool) -> Vector { + let mut result = vector![0_u8; 32]; result[31] = u8::from(v); result } -fn to_solidity_string(s: &str) -> Vec { +fn to_solidity_string(s: &str) -> Vector { // String encoding // 32 bytes - offset // 32 bytes - length @@ -380,7 +383,7 @@ fn to_solidity_string(s: &str) -> Vec { ((s.len() / 32) + 1) * 32 }; - let mut result = vec![0_u8; 32 + 32 + data_len]; + let mut result = vector![0_u8; 32 + 32 + data_len]; result[31] = 0x20; // offset - 32 bytes diff --git a/evm_loader/program/src/executor/precompile_extension/mod.rs b/evm_loader/program/src/executor/precompile_extension/mod.rs index 0d0812c99..5e20dbb6f 100644 --- a/evm_loader/program/src/executor/precompile_extension/mod.rs +++ b/evm_loader/program/src/executor/precompile_extension/mod.rs @@ -1,3 +1,5 @@ +use crate::types::Vector; +use crate::vector; use crate::{ account_storage::FAKE_OPERATOR, error::Result, @@ -54,7 +56,7 @@ impl PrecompiledContracts { address: &Address, input: &[u8], is_static: bool, - ) -> Option>> { + ) -> Option>> { match *address { Self::SYSTEM_ACCOUNT_QUERY => { Some(query_account::query_account(state, address, input, context, is_static).await) @@ -82,7 +84,7 @@ pub async fn create_account( account: &OwnedAccountInfo, space: usize, owner: &Pubkey, - seeds: Vec>, + seeds: Vector>, ) -> Result<()> { let minimum_balance = state.rent().minimum_balance(space); @@ -92,18 +94,18 @@ pub async fn create_account( let transfer = system_instruction::transfer(&FAKE_OPERATOR, &account.key, required_lamports); state - .queue_external_instruction(transfer, vec![], required_lamports, true) + .queue_external_instruction(transfer, vector![], required_lamports, true) .await?; } let allocate = system_instruction::allocate(&account.key, space.try_into().unwrap()); state - .queue_external_instruction(allocate, vec![seeds.clone()], 0, true) + .queue_external_instruction(allocate, vector![seeds.clone()], 0, true) .await?; let assign = system_instruction::assign(&account.key, owner); state - .queue_external_instruction(assign, vec![seeds], 0, true) + .queue_external_instruction(assign, vector![seeds], 0, true) .await?; Ok(()) diff --git a/evm_loader/program/src/executor/precompile_extension/neon_token.rs b/evm_loader/program/src/executor/precompile_extension/neon_token.rs index 8931725d6..93d431520 100644 --- a/evm_loader/program/src/executor/precompile_extension/neon_token.rs +++ b/evm_loader/program/src/executor/precompile_extension/neon_token.rs @@ -6,6 +6,10 @@ use maybe_async::maybe_async; use solana_program::{account_info::IntoAccountInfo, program_pack::Pack, pubkey::Pubkey}; use spl_associated_token_account::get_associated_token_address; +use crate::types::vector::VectorSliceExt; +use crate::vector; + +use crate::types::Vector; use crate::{ account::token, account_storage::FAKE_OPERATOR, @@ -27,7 +31,7 @@ pub async fn neon_token( input: &[u8], context: &crate::evm::Context, is_static: bool, -) -> Result> { +) -> Result> { debug_print!("neon_token({})", hex::encode(input)); if &context.contract != address { @@ -53,7 +57,7 @@ pub async fn neon_token( withdraw(state, source, chain_id, destination, value).await?; - let mut output = vec![0_u8; 32]; + let mut output = vector![0_u8; 32]; output[31] = 1; // return true return Ok(output); @@ -113,7 +117,7 @@ async fn withdraw( let fee = state.rent().minimum_balance(spl_token::state::Account::LEN); state - .queue_external_instruction(create_associated, vec![], fee, true) + .queue_external_instruction(create_associated, vector![], fee, true) .await?; } @@ -130,11 +134,11 @@ async fn withdraw( spl_amount.as_u64(), mint_data.decimals, )?; - let transfer_seeds = vec![b"Deposit".to_vec(), vec![bump_seed]]; + let transfer_seeds = vector![b"Deposit".to_vector(), vector![bump_seed]]; state.burn(source, chain_id, value).await?; state - .queue_external_instruction(transfer, vec![transfer_seeds], 0, true) + .queue_external_instruction(transfer, vector![transfer_seeds], 0, true) .await?; Ok(()) diff --git a/evm_loader/program/src/executor/precompile_extension/query_account.rs b/evm_loader/program/src/executor/precompile_extension/query_account.rs index 7c84ef27f..00f5f5ec6 100644 --- a/evm_loader/program/src/executor/precompile_extension/query_account.rs +++ b/evm_loader/program/src/executor/precompile_extension/query_account.rs @@ -8,7 +8,8 @@ use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; use crate::{ error::{Error, Result}, evm::database::Database, - types::Address, + types::{vector::VectorSliceExt, Address, Vector}, + vector, }; // QueryAccount method DEPRECATED ids: @@ -37,7 +38,7 @@ pub async fn query_account( input: &[u8], context: &crate::evm::Context, _is_static: bool, -) -> Result> { +) -> Result> { debug_print!("query_account({})", hex::encode(input)); if context.value != 0 { @@ -54,7 +55,7 @@ pub async fn query_account( [0x2b, 0x3c, 0x83, 0x22] => { // cache(uint256,uint64,uint64) // deprecated - Ok(Vec::new()) + Ok(vector![]) } [0xa1, 0x23, 0xc3, 0x3e] | [0x02, 0x57, 0x1b, 0xe3] => { debug_print!("query_account.owner({})", &account_address); @@ -102,36 +103,39 @@ pub async fn query_account( #[allow(clippy::unnecessary_wraps)] #[maybe_async] -async fn account_owner(state: &State, address: &Pubkey) -> Result> { +async fn account_owner(state: &State, address: &Pubkey) -> Result> { let owner = state .map_solana_account(address, |info| info.owner.to_bytes()) .await; - Ok(owner.to_vec()) + Ok(owner.to_vector()) } #[allow(clippy::unnecessary_wraps)] #[maybe_async] -async fn account_lamports(state: &State, address: &Pubkey) -> Result> { +async fn account_lamports(state: &State, address: &Pubkey) -> Result> { let lamports: U256 = state .map_solana_account(address, |info| **info.lamports.borrow()) .await .into(); - let bytes = lamports.to_be_bytes().to_vec(); + let bytes = lamports.to_be_bytes().to_vector(); Ok(bytes) } #[allow(clippy::unnecessary_wraps)] #[maybe_async] -async fn account_rent_epoch(state: &State, address: &Pubkey) -> Result> { +async fn account_rent_epoch( + state: &State, + address: &Pubkey, +) -> Result> { let epoch: U256 = state .map_solana_account(address, |info| info.rent_epoch) .await .into(); - let bytes = epoch.to_be_bytes().to_vec(); + let bytes = epoch.to_be_bytes().to_vector(); Ok(bytes) } @@ -141,26 +145,29 @@ async fn account_rent_epoch(state: &State, address: &Pubkey) -> async fn account_is_executable( state: &State, address: &Pubkey, -) -> Result> { +) -> Result> { let executable: U256 = state .map_solana_account(address, |info| info.executable) .await .into(); - let bytes = executable.to_be_bytes().to_vec(); + let bytes = executable.to_be_bytes().to_vector(); Ok(bytes) } #[allow(clippy::unnecessary_wraps)] #[maybe_async] -async fn account_data_length(state: &State, address: &Pubkey) -> Result> { +async fn account_data_length( + state: &State, + address: &Pubkey, +) -> Result> { let length: U256 = state .map_solana_account(address, |info| info.data.borrow().len()) .await .try_into()?; - let bytes = length.to_be_bytes().to_vec(); + let bytes = length.to_be_bytes().to_vector(); Ok(bytes) } @@ -172,7 +179,7 @@ async fn account_data( address: &Pubkey, offset: usize, length: usize, -) -> Result> { +) -> Result> { if length == 0 { return Err(Error::Custom( "Query Account: data() - length == 0".to_string(), @@ -184,7 +191,7 @@ async fn account_data( info.data .borrow() .get(offset..offset + length) - .map(<[u8]>::to_vec) + .map(<[u8]>::to_vector) }) .await .ok_or_else(|| Error::Custom("Query Account: data() - out of bounds".to_string())) @@ -192,8 +199,8 @@ async fn account_data( #[allow(clippy::unnecessary_wraps)] #[maybe_async] -async fn account_info(state: &State, address: &Pubkey) -> Result> { - fn to_solidity_account_value(info: &AccountInfo) -> Vec { +async fn account_info(state: &State, address: &Pubkey) -> Result> { + fn to_solidity_account_value(info: &AccountInfo) -> Vector { let mut buffer = [0_u8; 5 * 32]; let (key, _, lamports, owner, _, executable, _, rent_epoch) = arrayref::mut_array_refs![&mut buffer, 32, 24, 8, 32, 31, 1, 24, 8]; @@ -204,7 +211,7 @@ async fn account_info(state: &State, address: &Pubkey) -> Resul executable[0] = info.executable.into(); *rent_epoch = info.rent_epoch.to_be_bytes(); - buffer.to_vec() + buffer.to_vector() } let info = state diff --git a/evm_loader/program/src/executor/precompile_extension/spl_token.rs b/evm_loader/program/src/executor/precompile_extension/spl_token.rs index 589852fd5..499553852 100644 --- a/evm_loader/program/src/executor/precompile_extension/spl_token.rs +++ b/evm_loader/program/src/executor/precompile_extension/spl_token.rs @@ -15,6 +15,10 @@ use crate::{ types::Address, }; +use crate::vector; + +use crate::types::vector::{Vector, VectorSliceExt}; + // [0xa9, 0xc1, 0x58, 0x06] : "approve(bytes32,bytes32,uint64)", // [0xc0, 0x67, 0xee, 0xbb] : "burn(bytes32,bytes32,uint64)", // [0x57, 0x82, 0xa0, 0x43] : "closeAccount(bytes32)", @@ -41,7 +45,7 @@ pub async fn spl_token( input: &[u8], context: &crate::evm::Context, is_static: bool, -) -> Result> { +) -> Result> { if context.value != 0 { return Err(Error::Custom("SplToken: value != 0".to_string())); } @@ -266,7 +270,7 @@ async fn initialize_mint( decimals: u8, mint_authority: Option, freeze_authority: Option, -) -> Result> { +) -> Result> { let signer = context.caller; let (signer_pubkey, _) = state.contract_pubkey(signer); @@ -285,12 +289,12 @@ async fn initialize_mint( return Err(Error::AccountInvalidOwner(mint_key, system_program::ID)); } - let seeds: Vec> = vec![ - vec![ACCOUNT_SEED_VERSION], - b"ContractData".to_vec(), - signer.as_bytes().to_vec(), - seed.to_vec(), - vec![bump_seed], + let seeds: Vector> = vector![ + vector![ACCOUNT_SEED_VERSION], + b"ContractData".to_vector(), + signer.as_bytes().to_vector(), + seed.to_vector(), + vector![bump_seed], ]; create_account( @@ -310,10 +314,10 @@ async fn initialize_mint( decimals, )?; state - .queue_external_instruction(initialize_mint, vec![], 0, true) + .queue_external_instruction(initialize_mint, vector![], 0, true) .await?; - Ok(mint_key.to_bytes().to_vec()) + Ok(mint_key.to_bytes().to_vector()) } #[maybe_async] @@ -323,7 +327,7 @@ async fn initialize_account( seed: &[u8], mint: Pubkey, owner: Option, -) -> Result> { +) -> Result> { let signer = context.caller; let (signer_pubkey, _) = state.contract_pubkey(signer); @@ -342,12 +346,12 @@ async fn initialize_account( return Err(Error::AccountInvalidOwner(account_key, system_program::ID)); } - let seeds: Vec> = vec![ - vec![ACCOUNT_SEED_VERSION], - b"ContractData".to_vec(), - signer.as_bytes().to_vec(), - seed.to_vec(), - vec![bump_seed], + let seeds: Vector> = vector![ + vector![ACCOUNT_SEED_VERSION], + b"ContractData".to_vector(), + signer.as_bytes().to_vector(), + seed.to_vector(), + vector![bump_seed], ]; create_account( @@ -366,10 +370,10 @@ async fn initialize_account( &owner.unwrap_or(signer_pubkey), )?; state - .queue_external_instruction(initialize_mint, vec![], 0, true) + .queue_external_instruction(initialize_mint, vector![], 0, true) .await?; - Ok(account_key.to_bytes().to_vec()) + Ok(account_key.to_bytes().to_vector()) } #[maybe_async] @@ -377,14 +381,14 @@ async fn close_account( context: &crate::evm::Context, state: &mut State, account: Pubkey, -) -> Result> { +) -> Result> { let signer = context.caller; let (signer_pubkey, bump_seed) = state.contract_pubkey(signer); - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], + let seeds = vector![ + vector![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vector(), + vector![bump_seed], ]; let close_account = spl_token::instruction::close_account( @@ -395,10 +399,10 @@ async fn close_account( &[], )?; state - .queue_external_instruction(close_account, vec![seeds], 0, true) + .queue_external_instruction(close_account, vector![seeds], 0, true) .await?; - Ok(vec![]) + Ok(vector![]) } #[maybe_async] @@ -408,14 +412,14 @@ async fn approve( source: Pubkey, target: Pubkey, amount: u64, -) -> Result> { +) -> Result> { let signer = context.caller; let (signer_pubkey, bump_seed) = state.contract_pubkey(signer); - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], + let seeds = vector![ + vector![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vector(), + vector![bump_seed], ]; let approve = spl_token::instruction::approve( @@ -427,10 +431,10 @@ async fn approve( amount, )?; state - .queue_external_instruction(approve, vec![seeds], 0, true) + .queue_external_instruction(approve, vector![seeds], 0, true) .await?; - Ok(vec![]) + Ok(vector![]) } #[maybe_async] @@ -438,22 +442,22 @@ async fn revoke( context: &crate::evm::Context, state: &mut State, account: Pubkey, -) -> Result> { +) -> Result> { let signer = context.caller; let (signer_pubkey, bump_seed) = state.contract_pubkey(signer); - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], + let seeds = vector![ + vector![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vector(), + vector![bump_seed], ]; let revoke = spl_token::instruction::revoke(&spl_token::ID, &account, &signer_pubkey, &[])?; state - .queue_external_instruction(revoke, vec![seeds], 0, true) + .queue_external_instruction(revoke, vector![seeds], 0, true) .await?; - Ok(vec![]) + Ok(vector![]) } #[maybe_async] @@ -463,18 +467,18 @@ async fn transfer( source: Pubkey, target: Pubkey, amount: u64, -) -> Result> { +) -> Result> { if (source == target) || (amount == 0) { - return Ok(vec![]); + return Ok(vector![]); } let signer = context.caller; let (signer_pubkey, bump_seed) = state.contract_pubkey(signer); - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], + let seeds = vector![ + vector![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vector(), + vector![bump_seed], ]; let transfer = spl_token::instruction::transfer( @@ -486,10 +490,10 @@ async fn transfer( amount, )?; state - .queue_external_instruction(transfer, vec![seeds], 0, true) + .queue_external_instruction(transfer, vector![seeds], 0, true) .await?; - Ok(vec![]) + Ok(vector![]) } #[maybe_async] @@ -500,9 +504,9 @@ async fn transfer_with_seed( source: Pubkey, target: Pubkey, amount: u64, -) -> Result> { +) -> Result> { if (source == target) || (amount == 0) { - return Ok(vec![]); + return Ok(vector![]); } let seeds: &[&[u8]] = &[ @@ -513,12 +517,12 @@ async fn transfer_with_seed( ]; let (signer_pubkey, signer_seed) = Pubkey::find_program_address(seeds, state.program_id()); - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - b"AUTH".to_vec(), - context.caller.as_bytes().to_vec(), - seed.to_vec(), - vec![signer_seed], + let seeds = vector![ + vector![ACCOUNT_SEED_VERSION], + b"AUTH".to_vector(), + context.caller.as_bytes().to_vector(), + seed.to_vector(), + vector![signer_seed], ]; let transfer = spl_token::instruction::transfer( @@ -530,10 +534,10 @@ async fn transfer_with_seed( amount, )?; state - .queue_external_instruction(transfer, vec![seeds], 0, true) + .queue_external_instruction(transfer, vector![seeds], 0, true) .await?; - Ok(vec![]) + Ok(vector![]) } #[maybe_async] @@ -543,18 +547,18 @@ async fn mint_to( mint: Pubkey, target: Pubkey, amount: u64, -) -> Result> { +) -> Result> { if amount == 0 { - return Ok(vec![]); + return Ok(vector![]); } let signer = context.caller; let (signer_pubkey, bump_seed) = state.contract_pubkey(signer); - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], + let seeds = vector![ + vector![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vector(), + vector![bump_seed], ]; let mint_to = spl_token::instruction::mint_to( @@ -566,10 +570,10 @@ async fn mint_to( amount, )?; state - .queue_external_instruction(mint_to, vec![seeds], 0, true) + .queue_external_instruction(mint_to, vector![seeds], 0, true) .await?; - Ok(vec![]) + Ok(vector![]) } #[maybe_async] @@ -579,18 +583,18 @@ async fn burn( mint: Pubkey, source: Pubkey, amount: u64, -) -> Result> { +) -> Result> { if amount == 0 { - return Ok(vec![]); + return Ok(vector![]); } let signer = context.caller; let (signer_pubkey, bump_seed) = state.contract_pubkey(signer); - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], + let seeds = vector![ + vector![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vector(), + vector![bump_seed], ]; #[rustfmt::skip] @@ -603,10 +607,10 @@ async fn burn( amount )?; state - .queue_external_instruction(burn, vec![seeds], 0, true) + .queue_external_instruction(burn, vector![seeds], 0, true) .await?; - Ok(vec![]) + Ok(vector![]) } #[maybe_async] @@ -615,14 +619,14 @@ async fn freeze( state: &mut State, mint: Pubkey, target: Pubkey, -) -> Result> { +) -> Result> { let signer = context.caller; let (signer_pubkey, bump_seed) = state.contract_pubkey(signer); - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], + let seeds = vector![ + vector![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vector(), + vector![bump_seed], ]; let freeze = spl_token::instruction::freeze_account( @@ -633,10 +637,10 @@ async fn freeze( &[], )?; state - .queue_external_instruction(freeze, vec![seeds], 0, true) + .queue_external_instruction(freeze, vector![seeds], 0, true) .await?; - Ok(vec![]) + Ok(vector![]) } #[maybe_async] @@ -645,14 +649,14 @@ async fn thaw( state: &mut State, mint: Pubkey, target: Pubkey, -) -> Result> { +) -> Result> { let signer = context.caller; let (signer_pubkey, bump_seed) = state.contract_pubkey(signer); - let seeds = vec![ - vec![ACCOUNT_SEED_VERSION], - signer.as_bytes().to_vec(), - vec![bump_seed], + let seeds = vector![ + vector![ACCOUNT_SEED_VERSION], + signer.as_bytes().to_vector(), + vector![bump_seed], ]; #[rustfmt::skip] @@ -664,10 +668,10 @@ async fn thaw( &[] )?; state - .queue_external_instruction(thaw, vec![seeds], 0, true) + .queue_external_instruction(thaw, vector![seeds], 0, true) .await?; - Ok(vec![]) + Ok(vector![]) } #[allow(clippy::unnecessary_wraps)] @@ -675,7 +679,7 @@ fn find_account( context: &crate::evm::Context, state: &State, seed: &[u8], -) -> Result> { +) -> Result> { let signer = context.caller; let (account_key, _) = Pubkey::find_program_address( @@ -688,7 +692,7 @@ fn find_account( state.program_id(), ); - Ok(account_key.to_bytes().to_vec()) + Ok(account_key.to_bytes().to_vector()) } #[maybe_async] @@ -696,15 +700,15 @@ async fn is_system_account( _context: &crate::evm::Context, state: &State, account: Pubkey, -) -> Result> { +) -> Result> { let account = state.external_account(account).await?; if system_program::check_id(&account.owner) { - let mut result = vec![0_u8; 32]; + let mut result = vector![0_u8; 32]; result[31] = 1; // return true Ok(result) } else { - Ok(vec![0_u8; 32]) + Ok(vector![0_u8; 32]) } } @@ -713,7 +717,7 @@ async fn get_account( _context: &crate::evm::Context, state: &State, account: Pubkey, -) -> Result> { +) -> Result> { let account = state.external_account(account).await?; let token = if spl_token::check_id(&account.owner) { spl_token::state::Account::unpack(&account.data)? @@ -740,7 +744,7 @@ async fn get_account( .unwrap_or_default(); state[31] = token.state as u8; - Ok(result.to_vec()) + Ok(result.to_vector()) } #[maybe_async] @@ -748,7 +752,7 @@ async fn get_mint( _context: &crate::evm::Context, state: &State, account: Pubkey, -) -> Result> { +) -> Result> { let account = state.external_account(account).await?; let mint = if spl_token::check_id(&account.owner) { spl_token::state::Mint::unpack(&account.data)? @@ -776,5 +780,5 @@ async fn get_mint( .map(Pubkey::to_bytes) .unwrap_or_default(); - Ok(result.to_vec()) + Ok(result.to_vector()) } diff --git a/evm_loader/program/src/executor/state.rs b/evm_loader/program/src/executor/state.rs index 3cfe6184d..954525c81 100644 --- a/evm_loader/program/src/executor/state.rs +++ b/evm_loader/program/src/executor/state.rs @@ -13,99 +13,98 @@ use solana_program::instruction::Instruction; use solana_program::pubkey::Pubkey; use solana_program::rent::Rent; +use crate::allocator::acc_allocator; +use crate::types::tree_map::TreeMap; +use crate::types::vector::{Vector, VectorSliceExt, VectorSliceSlowExt}; + use super::action::Action; use super::cache::Cache; use super::precompile_extension::PrecompiledContracts; use super::OwnedAccountInfo; -pub type ExecutionResult = Option<(ExitStatus, Vec)>; -pub type TouchedAccounts = BTreeMap; +pub type ExecutionResult<'a> = Option<(&'a ExitStatus, &'a Vector)>; +pub type TouchedAccounts = TreeMap; /// Represents the state of executor abstracted away from a self.backend. -/// UPDATE `serialize/deserialize` WHEN THIS STRUCTURE CHANGES -pub struct ExecutorState<'a, B: AccountStorage> { - backend: &'a mut B, +/// Persistent part of `ExecutorState`. +#[repr(C)] +pub struct ExecutorStateData { cache: RefCell, - actions: Vec, - stack: Vec, + actions: Vector, + stack: Vector, exit_status: Option, - // #[serde(skip)] touched_accounts: RefCell, } -impl<'a, B: AccountStorage> ExecutorState<'a, B> { - pub fn serialize_into(&self, buffer: &mut [u8]) -> Result { - let mut cursor = std::io::Cursor::new(buffer); - - let value = (&self.cache, &self.actions, &self.stack, &self.exit_status); - bincode::serialize_into(&mut cursor, &value)?; - - cursor.position().try_into().map_err(Error::from) - } - - pub fn deserialize_from(buffer: &[u8], backend: &'a mut B) -> Result { - let (cache, actions, stack, exit_status) = bincode::deserialize(buffer)?; - Ok(Self { - backend, - cache, - actions, - stack, - exit_status, - touched_accounts: RefCell::new(TouchedAccounts::new()), - }) - } +pub struct ExecutorState<'a, B: AccountStorage> { + pub backend: &'a mut B, + pub data: &'a mut ExecutorStateData, +} - #[must_use] - pub fn new(backend: &'a mut B) -> Self { +impl<'a> ExecutorStateData { + pub fn new(backend: &B) -> Self { let cache = Cache { block_number: backend.block_number(), block_timestamp: backend.block_timestamp(), }; Self { - backend, cache: RefCell::new(cache), - actions: Vec::with_capacity(64), - stack: Vec::with_capacity(16), + actions: Vector::with_capacity_in(64, acc_allocator()), + stack: Vector::with_capacity_in(16, acc_allocator()), exit_status: None, touched_accounts: RefCell::new(TouchedAccounts::new()), } } - pub fn deconstruct(self) -> (ExecutionResult, TouchedAccounts) { - let result = if let Some(exit_status) = self.exit_status { - Some((exit_status, self.actions)) + #[must_use] + pub fn deconstruct(&'a mut self) -> (ExecutionResult<'a>, TouchedAccounts) { + let result = if let Some(exit_status) = self.exit_status.as_ref() { + Some((exit_status, &self.actions)) } else { None }; + // Move out the current touched_accounts and replace with a new empty one. The previous touched_accounts object + // is consumed by the caller to update touched_accounts inside StateAccount's Data. + ( + result, + self.touched_accounts.replace(TouchedAccounts::new()), + ) + } - (result, self.touched_accounts.into_inner()) + #[must_use] + pub fn into_actions(&'a self) -> &'a Vector { + &self.actions } +} - pub fn into_actions(self) -> Vec { - assert!(self.stack.is_empty()); - self.actions +impl<'a, B: AccountStorage> ExecutorState<'a, B> { + #[must_use] + pub fn new(backend: &'a mut B, data: &'a mut ExecutorStateData) -> Self { + Self { backend, data } } + #[must_use] pub fn exit_status(&self) -> Option<&ExitStatus> { - self.exit_status.as_ref() + self.data.exit_status.as_ref() } pub fn set_exit_status(&mut self, status: ExitStatus) { - assert!(self.stack.is_empty()); + assert!(self.data.stack.is_empty()); - self.exit_status = Some(status); + self.data.exit_status = Some(status); } + #[must_use] pub fn call_depth(&self) -> usize { - self.stack.len() + self.data.stack.len() } #[maybe_async] async fn balance_internal(&self, from_address: Address, from_chain_id: u64) -> Result { let mut balance = self.backend.balance(from_address, from_chain_id).await; - for action in &self.actions { + for action in &self.data.actions { match action { Action::Transfer { source, @@ -160,10 +159,13 @@ impl<'a, B: AccountStorage> ExecutorState<'a, B> { } fn touch_account(&self, pubkey: Pubkey, count: u64) { - let mut touched_accounts = self.touched_accounts.borrow_mut(); + let mut touched_accounts = self.data.touched_accounts.borrow_mut(); - let counter = touched_accounts.entry(pubkey).or_insert(0); - *counter = counter.checked_add(count).unwrap(); // Technically, this could overflow with infinite compute budget + let cur_counter = touched_accounts + .get(&pubkey) + .map_or(0_u64, |counter| *counter); + // Technically, this could overflow with infinite compute budget + touched_accounts.insert(pubkey, cur_counter.checked_add(count).unwrap()); } } @@ -197,7 +199,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { let mut nonce = self.backend.nonce(from_address, from_chain_id).await; let mut increment = 0_u64; - for action in &self.actions { + for action in &self.data.actions { if let Action::EvmIncrementNonce { address, chain_id } = action { if (&from_address == address) && (&from_chain_id == chain_id) { increment += 1; @@ -212,7 +214,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { async fn increment_nonce(&mut self, address: Address, chain_id: u64) -> Result<()> { let increment = Action::EvmIncrementNonce { address, chain_id }; - self.actions.push(increment); + self.data.actions.push(increment); Ok(()) } @@ -257,7 +259,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { chain_id, value, }; - self.actions.push(transfer); + self.data.actions.push(transfer); Ok(()) } @@ -273,7 +275,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { chain_id, value, }; - self.actions.push(burn); + self.data.actions.push(burn); Ok(()) } @@ -285,7 +287,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { self.touch_contract(from_address); - for action in &self.actions { + for action in &self.data.actions { if let Action::EvmSetCode { address, code, .. } = action { if &from_address == address { return Ok(code.len()); @@ -299,7 +301,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { async fn code(&self, from_address: Address) -> Result { self.touch_contract(from_address); - for action in &self.actions { + for action in &self.data.actions { if let Action::EvmSetCode { address, code, .. } = action { if &from_address == address { return Ok(crate::evm::Buffer::from_slice(code)); @@ -310,7 +312,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { Ok(self.backend.code(from_address).await) } - async fn set_code(&mut self, address: Address, chain_id: u64, code: Vec) -> Result<()> { + async fn set_code(&mut self, address: Address, chain_id: u64, code: Vector) -> Result<()> { if code.starts_with(&[0xEF]) { // https://eips.ethereum.org/EIPS/eip-3541 return Err(Error::EVMObjectFormatNotSupported(address)); @@ -326,7 +328,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { chain_id, code, }; - self.actions.push(set_code); + self.data.actions.push(set_code); Ok(()) } @@ -334,7 +336,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { async fn storage(&self, from_address: Address, from_index: U256) -> Result<[u8; 32]> { self.touch_storage(from_address, from_index); - for action in self.actions.iter().rev() { + for action in self.data.actions.iter().rev() { if let Action::EvmSetStorage { address, index, @@ -356,13 +358,13 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { index, value, }; - self.actions.push(set_storage); + self.data.actions.push(set_storage); Ok(()) } async fn transient_storage(&self, from_address: Address, from_index: U256) -> Result<[u8; 32]> { - for action in self.actions.iter().rev() { + for action in self.data.actions.iter().rev() { if let Action::EvmSetTransientStorage { address, index, @@ -389,7 +391,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { index, value, }; - self.actions.push(set_storage); + self.data.actions.push(set_storage); Ok(()) } @@ -405,7 +407,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { } let number = number.as_u64(); - let block_slot = self.cache.borrow().block_number.as_u64(); + let block_slot = self.data.cache.borrow().block_number.as_u64(); let lower_block_slot = if block_slot < 257 { 0 } else { @@ -420,12 +422,12 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { } fn block_number(&self) -> Result { - let cache = self.cache.borrow(); + let cache = self.data.cache.borrow(); Ok(cache.block_number) } fn block_timestamp(&self) -> Result { - let cache = self.cache.borrow(); + let cache = self.data.cache.borrow(); Ok(cache.block_timestamp) } @@ -433,6 +435,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { self.touch_solana(address); let metas = self + .data .actions .iter() .filter_map(|a| { @@ -459,7 +462,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { accounts.insert(m.pubkey, account); } - for action in &self.actions { + for action in &self.data.actions { if let Action::ExternalInstruction { program_id, data, @@ -529,25 +532,27 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { } fn snapshot(&mut self) { - self.stack.push(self.actions.len()); + self.data.stack.push(self.data.actions.len()); } fn revert_snapshot(&mut self) { let actions_len = self + .data .stack .pop() .expect("Fatal Error: Inconsistent EVM Call Stack"); - self.actions.truncate(actions_len); + self.data.actions.truncate(actions_len); - if self.stack.is_empty() { + if self.data.stack.is_empty() { // sanity check - assert!(self.actions.is_empty()); + assert!(self.data.actions.is_empty()); } } fn commit_snapshot(&mut self) { - self.stack + self.data + .stack .pop() .expect("Fatal Error: Inconsistent EVM Call Stack"); } @@ -558,7 +563,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { address: &Address, data: &[u8], is_static: bool, - ) -> Option>> { + ) -> Option>> { PrecompiledContracts::call_precompile_extension(self, context, address, data, is_static) .await } @@ -574,7 +579,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { async fn contract_chain_id(&self, contract: Address) -> Result { self.touch_contract(contract); - for action in self.actions.iter().rev() { + for action in self.data.actions.iter().rev() { if let Action::EvmSetCode { address, chain_id, .. } = action @@ -591,7 +596,7 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { async fn queue_external_instruction( &mut self, instruction: Instruction, - seeds: Vec>>, + seeds: Vector>>, fee: u64, emulated_internally: bool, ) -> Result<()> { @@ -602,14 +607,14 @@ impl<'a, B: AccountStorage> Database for ExecutorState<'a, B> { let action = Action::ExternalInstruction { program_id: instruction.program_id, - data: instruction.data, - accounts: instruction.accounts, + data: instruction.data.to_vector(), + accounts: instruction.accounts.elementwise_copy_to_vector(), seeds, fee, emulated_internally, }; - self.actions.push(action); + self.data.actions.push(action); Ok(()) } } diff --git a/evm_loader/program/src/executor/synced_state.rs b/evm_loader/program/src/executor/synced_state.rs index c681a0d62..a278f19ef 100644 --- a/evm_loader/program/src/executor/synced_state.rs +++ b/evm_loader/program/src/executor/synced_state.rs @@ -5,10 +5,11 @@ use solana_program::pubkey::Pubkey; use solana_program::rent::Rent; use crate::account_storage::{AccountStorage, LogCollector, SyncedAccountStorage}; +use crate::allocator::acc_allocator; use crate::error::{Error, Result}; use crate::evm::database::Database; use crate::evm::Context; -use crate::types::Address; +use crate::types::{Address, Vector}; use super::precompile_extension::PrecompiledContracts; use super::OwnedAccountInfo; @@ -22,9 +23,9 @@ enum Action { } pub struct SyncedExecutorState<'a, B: AccountStorage> { - backend: &'a mut B, - actions: Vec, - stack: Vec, + pub backend: &'a mut B, + actions: Vector, + stack: Vector, } impl<'a, B: SyncedAccountStorage> SyncedExecutorState<'a, B> { @@ -32,8 +33,8 @@ impl<'a, B: SyncedAccountStorage> SyncedExecutorState<'a, B> { pub fn new(backend: &'a mut B) -> Self { Self { backend, - actions: Vec::with_capacity(64), - stack: Vec::with_capacity(16), + actions: Vector::with_capacity_in(64, acc_allocator()), + stack: Vector::with_capacity_in(16, acc_allocator()), } } @@ -132,7 +133,7 @@ impl<'a, B: SyncedAccountStorage> Database for SyncedExecutorState<'a, B> { Ok(self.backend.code(from_address).await) } - async fn set_code(&mut self, address: Address, chain_id: u64, code: Vec) -> Result<()> { + async fn set_code(&mut self, address: Address, chain_id: u64, code: Vector) -> Result<()> { if code.starts_with(&[0xEF]) { // https://eips.ethereum.org/EIPS/eip-3541 return Err(Error::EVMObjectFormatNotSupported(address)); @@ -279,7 +280,7 @@ impl<'a, B: SyncedAccountStorage> Database for SyncedExecutorState<'a, B> { address: &Address, data: &[u8], is_static: bool, - ) -> Option>> { + ) -> Option>> { PrecompiledContracts::call_precompile_extension(self, context, address, data, is_static) .await } @@ -299,7 +300,7 @@ impl<'a, B: SyncedAccountStorage> Database for SyncedExecutorState<'a, B> { async fn queue_external_instruction( &mut self, instruction: Instruction, - seeds: Vec>>, + seeds: Vector>>, fee: u64, emulated_internally: bool, ) -> Result<()> { diff --git a/evm_loader/program/src/external_programs/metaplex.rs b/evm_loader/program/src/external_programs/metaplex.rs index 08b681294..81fa938ae 100644 --- a/evm_loader/program/src/external_programs/metaplex.rs +++ b/evm_loader/program/src/external_programs/metaplex.rs @@ -13,6 +13,7 @@ use solana_program::{account_info::IntoAccountInfo, program_pack::Pack}; use std::collections::BTreeMap; use crate::executor::OwnedAccountInfo; +use crate::types::vector::VectorVecExt; use solana_program::pubkey::Pubkey; pub fn emulate( @@ -83,7 +84,7 @@ fn create_metadata_accounts_v3( let metadata_account = accounts.get_mut(metadata_account_key).unwrap(); metadata_account.owner = MPL_TOKEN_METADATA_ID; - metadata_account.data = metadata.try_to_vec()?; + metadata_account.data = metadata.try_to_vec()?.into_vector(); metadata_account.lamports = rent.minimum_balance(metadata_account.data.len()); Ok(()) @@ -137,7 +138,7 @@ fn create_master_edition_v3( { let edition_account = accounts.get_mut(edition_account_key).unwrap(); edition_account.owner = MPL_TOKEN_METADATA_ID; - edition_account.data = edition.try_to_vec()?; + edition_account.data = edition.try_to_vec()?.into_vector(); edition_account.lamports = rent.minimum_balance(edition_account.data.len()); } // Metadata Account diff --git a/evm_loader/program/src/instruction/mod.rs b/evm_loader/program/src/instruction/mod.rs index 0159d1928..a27de3dd1 100644 --- a/evm_loader/program/src/instruction/mod.rs +++ b/evm_loader/program/src/instruction/mod.rs @@ -67,6 +67,7 @@ pub enum EvmInstruction { /// Execute Transaction from Instruction in single iteration /// /// Accounts: + /// `[WRITE]` Holder /// `[WRITE,SIGNER]` Operator /// `[WRITE]` Treasury /// `[WRITE]` Operator Balance @@ -80,7 +81,7 @@ pub enum EvmInstruction { /// Execute Transaction from Account in single iteration /// /// Accounts: - /// `[]` Holder + /// `[WRITE]` Holder /// `[WRITE,SIGNER]` Operator /// `[WRITE]` Treasury /// `[WRITE]` Operator Balance @@ -172,6 +173,7 @@ pub enum EvmInstruction { /// Execute Transaction from Instruction in a single iteration with a call to Solana programs /// /// Accounts: + /// `[WRITE]` Holder /// `[WRITE,SIGNER]` Operator /// `[WRITE]` Treasury /// `[WRITE]` Operator Balance @@ -185,7 +187,7 @@ pub enum EvmInstruction { /// Execute Transaction from Account in a single iteration /// /// Accounts: - /// `[]` Holder + /// `[WRITE]` Holder /// `[WRITE,SIGNER]` Operator /// `[WRITE]` Treasury /// `[WRITE]` Operator Balance @@ -224,13 +226,13 @@ impl EvmInstruction { 0x30 => Self::AccountCreateBalance, // 48 0x31 => Self::Deposit, // 49 - 0x32 => Self::TransactionExecuteFromInstruction, // 50 + 0x3D => Self::TransactionExecuteFromInstruction, // 61 0x33 => Self::TransactionExecuteFromAccount, // 51 0x34 => Self::TransactionStepFromInstruction, // 52 0x35 => Self::TransactionStepFromAccount, // 53 0x36 => Self::TransactionStepFromAccountNoChainId, // 54 0x37 => Self::Cancel, // 55 - 0x38 => Self::TransactionExecuteFromInstructionWithSolanaCall, // 56 + 0x3E => Self::TransactionExecuteFromInstructionWithSolanaCall, // 62 0x39 => Self::TransactionExecuteFromAccountWithSolanaCall, // 57 0x3A => Self::OperatorBalanceCreate, // 58 diff --git a/evm_loader/program/src/instruction/transaction_cancel.rs b/evm_loader/program/src/instruction/transaction_cancel.rs index e700cc2ab..52b3763a6 100644 --- a/evm_loader/program/src/instruction/transaction_cancel.rs +++ b/evm_loader/program/src/instruction/transaction_cancel.rs @@ -28,7 +28,7 @@ pub fn process<'a>( log_data(&[b"MINER", operator_balance.address().as_bytes()]); let accounts_db = AccountsDB::new(&accounts[3..], operator, Some(operator_balance), None, None); - let (storage, _) = StateAccount::restore(program_id, storage_info, &accounts_db)?; + let (storage, _) = StateAccount::restore(program_id, &storage_info, &accounts_db)?; validate(&storage, transaction_hash)?; execute(program_id, accounts_db, storage) diff --git a/evm_loader/program/src/instruction/transaction_execute.rs b/evm_loader/program/src/instruction/transaction_execute.rs index 3239a11c3..ae5d4fb7c 100644 --- a/evm_loader/program/src/instruction/transaction_execute.rs +++ b/evm_loader/program/src/instruction/transaction_execute.rs @@ -4,15 +4,15 @@ use crate::debug::log_data; use crate::error::{Error, Result}; use crate::evm::tracing::NoopEventListener; use crate::evm::Machine; -use crate::executor::{ExecutorState, SyncedExecutorState}; +use crate::executor::{ExecutorState, ExecutorStateData, SyncedExecutorState}; use crate::gasometer::Gasometer; use crate::instruction::transaction_step::log_return_value; -use crate::types::{Address, Transaction}; +use crate::types::{boxx::Boxx, Address, Transaction}; pub fn execute( accounts: AccountsDB<'_>, mut gasometer: Gasometer, - trx: Transaction, + trx: Boxx, origin: Address, ) -> Result<()> { let chain_id = trx.chain_id().unwrap_or(crate::config::DEFAULT_CHAIN_ID); @@ -20,29 +20,30 @@ pub fn execute( let gas_price = trx.gas_price(); let mut account_storage = ProgramAccountStorage::new(accounts)?; + let mut backend_data = ExecutorStateData::new(&account_storage); trx.validate(origin, &account_storage)?; account_storage.origin(origin, &trx)?.increment_nonce()?; - let (exit_reason, apply_state, steps_executed) = { - let mut backend = ExecutorState::new(&mut account_storage); + let (exit_reason, steps_executed) = { + let mut backend = ExecutorState::new(&mut account_storage, &mut backend_data); let mut evm = Machine::new(&trx, origin, &mut backend, None::)?; let (result, steps_executed, _) = evm.execute(u64::MAX, &mut backend)?; - let actions = backend.into_actions(); - - (result, actions, steps_executed) + (result, steps_executed) }; + let apply_state = backend_data.into_actions(); + log_data(&[ b"STEPS", &steps_executed.to_le_bytes(), // Iteration steps &steps_executed.to_le_bytes(), // Total steps is the same as iteration steps ]); - let allocate_result = account_storage.allocate(&apply_state)?; + let allocate_result = account_storage.allocate(apply_state)?; if allocate_result != AllocateResult::Ready { return Err(Error::AccountSpaceAllocationFailure); } @@ -69,7 +70,7 @@ pub fn execute( pub fn execute_with_solana_call( accounts: AccountsDB<'_>, mut gasometer: Gasometer, - trx: Transaction, + trx: Boxx, origin: Address, ) -> Result<()> { let chain_id = trx.chain_id().unwrap_or(crate::config::DEFAULT_CHAIN_ID); diff --git a/evm_loader/program/src/instruction/transaction_execute_from_account.rs b/evm_loader/program/src/instruction/transaction_execute_from_account.rs index 18cf02532..fe1256a18 100644 --- a/evm_loader/program/src/instruction/transaction_execute_from_account.rs +++ b/evm_loader/program/src/instruction/transaction_execute_from_account.rs @@ -5,7 +5,7 @@ use crate::account::{ use crate::debug::log_data; use crate::error::Result; use crate::gasometer::Gasometer; -use crate::types::Transaction; +use crate::types::{boxx::boxx, Transaction}; use arrayref::array_ref; use ethnum::U256; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; @@ -20,7 +20,7 @@ pub fn process<'a>( let treasury_index = u32::from_le_bytes(*array_ref![instruction, 0, 4]); - let holder = Holder::from_account(program_id, accounts[0].clone())?; + let mut holder = Holder::from_account(program_id, accounts[0].clone())?; let operator = unsafe { Operator::from_account_not_whitelisted(&accounts[1])? }; let treasury = Treasury::from_account(program_id, treasury_index, &accounts[2])?; @@ -28,7 +28,19 @@ pub fn process<'a>( let system = program::System::from_account(&accounts[4])?; holder.validate_owner(&operator)?; - let trx = Transaction::from_rlp(&holder.transaction())?; + + // We have to initialize the heap before creating Transaction object, but since + // transaction's rlp itself is stored in the holder account, we have two options: + // 1. Copy the rlp and initialize the heap right after the holder's header. + // This way, the space occupied by the rlp within holder will be reused. + // 2. Don't copy the rlp, initialize the heap after transaction rlp in the holder. + // The first option (chosen) saves the holder space in exchange for compute units. + // The second option wastes the holder space (because transaction bytes will be + // stored two times), but doesnt copy. + let transaction_rlp_copy = holder.transaction().to_vec(); + holder.init_heap(0)?; + + let trx = boxx(Transaction::from_rlp(&transaction_rlp_copy)?); holder.validate_transaction(&trx)?; let origin = trx.recover_caller_address()?; diff --git a/evm_loader/program/src/instruction/transaction_execute_from_account_solana_call.rs b/evm_loader/program/src/instruction/transaction_execute_from_account_solana_call.rs index 3cd60c6b1..a78e51721 100644 --- a/evm_loader/program/src/instruction/transaction_execute_from_account_solana_call.rs +++ b/evm_loader/program/src/instruction/transaction_execute_from_account_solana_call.rs @@ -5,7 +5,7 @@ use crate::account::{ use crate::debug::log_data; use crate::error::Result; use crate::gasometer::Gasometer; -use crate::types::Transaction; +use crate::types::{boxx::boxx, Transaction}; use arrayref::array_ref; use ethnum::U256; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; @@ -20,7 +20,7 @@ pub fn process<'a>( let treasury_index = u32::from_le_bytes(*array_ref![instruction, 0, 4]); - let holder = Holder::from_account(program_id, accounts[0].clone())?; + let mut holder = Holder::from_account(program_id, accounts[0].clone())?; let operator = unsafe { Operator::from_account_not_whitelisted(&accounts[1])? }; let treasury = Treasury::from_account(program_id, treasury_index, &accounts[2])?; @@ -28,7 +28,24 @@ pub fn process<'a>( let system = program::System::from_account(&accounts[4])?; holder.validate_owner(&operator)?; - let trx = Transaction::from_rlp(&holder.transaction())?; + + // We have to initialize the heap before creating Transaction object, but since + // transaction's rlp itself is stored in the holder account, we have two options: + // 1. Copy the rlp and initialize the heap right after the holder's header. + // This way, the space occupied by the rlp within holder will be reused. + // 2. Don't copy the rlp, initialize the heap after transaction rlp in the holder. + // The first option (chosen) saves the holder space in exchange for compute units. + // The second option wastes the holder space (because transaction bytes will be + // stored two times), but doesnt copy. + let transaction_rlp_copy = { + let holder_transaction_ref = holder.transaction(); + let mut transaction_copy = vec![0u8; holder_transaction_ref.len()]; + transaction_copy.copy_from_slice(&holder_transaction_ref); + transaction_copy + }; + holder.init_heap(0)?; + + let trx = boxx(Transaction::from_rlp(&transaction_rlp_copy)?); holder.validate_transaction(&trx)?; let origin = trx.recover_caller_address()?; diff --git a/evm_loader/program/src/instruction/transaction_execute_from_instruction.rs b/evm_loader/program/src/instruction/transaction_execute_from_instruction.rs index 355179f8a..14c97d50c 100644 --- a/evm_loader/program/src/instruction/transaction_execute_from_instruction.rs +++ b/evm_loader/program/src/instruction/transaction_execute_from_instruction.rs @@ -1,10 +1,11 @@ use crate::account::{ - program, AccountsDB, Operator, OperatorBalanceAccount, OperatorBalanceValidator, Treasury, + program, AccountsDB, Holder, Operator, OperatorBalanceAccount, OperatorBalanceValidator, + Treasury, }; use crate::debug::log_data; use crate::error::Result; use crate::gasometer::Gasometer; -use crate::types::Transaction; +use crate::types::{boxx::boxx, Transaction}; use arrayref::array_ref; use ethnum::U256; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; @@ -20,12 +21,16 @@ pub fn process<'a>( let treasury_index = u32::from_le_bytes(*array_ref![instruction, 0, 4]); let messsage = &instruction[4..]; - let operator = unsafe { Operator::from_account_not_whitelisted(&accounts[0])? }; - let treasury = Treasury::from_account(program_id, treasury_index, &accounts[1])?; - let operator_balance = OperatorBalanceAccount::try_from_account(program_id, &accounts[2])?; - let system = program::System::from_account(&accounts[3])?; + let mut holder = Holder::from_account(program_id, accounts[0].clone())?; + let operator = unsafe { Operator::from_account_not_whitelisted(&accounts[1])? }; + let treasury = Treasury::from_account(program_id, treasury_index, &accounts[2])?; + let operator_balance = OperatorBalanceAccount::try_from_account(program_id, &accounts[3])?; + let system = program::System::from_account(&accounts[4])?; - let trx = Transaction::from_rlp(messsage)?; + holder.validate_owner(&operator)?; + holder.init_heap(0)?; + + let trx = boxx(Transaction::from_rlp(messsage)?); let origin = trx.recover_caller_address()?; operator_balance.validate_owner(&operator)?; @@ -36,7 +41,7 @@ pub fn process<'a>( log_data(&[b"MINER", miner_address.as_bytes()]); let accounts_db = AccountsDB::new( - &accounts[4..], + &accounts[5..], operator, operator_balance, Some(system), diff --git a/evm_loader/program/src/instruction/transaction_execute_from_instruction_solana_call.rs b/evm_loader/program/src/instruction/transaction_execute_from_instruction_solana_call.rs index 46c3b8a3d..63e259bc8 100644 --- a/evm_loader/program/src/instruction/transaction_execute_from_instruction_solana_call.rs +++ b/evm_loader/program/src/instruction/transaction_execute_from_instruction_solana_call.rs @@ -1,10 +1,11 @@ use crate::account::{ - program, AccountsDB, Operator, OperatorBalanceAccount, OperatorBalanceValidator, Treasury, + program, AccountsDB, Holder, Operator, OperatorBalanceAccount, OperatorBalanceValidator, + Treasury, }; use crate::debug::log_data; use crate::error::Result; use crate::gasometer::Gasometer; -use crate::types::Transaction; +use crate::types::{boxx::boxx, Transaction}; use arrayref::array_ref; use ethnum::U256; use solana_program::{account_info::AccountInfo, pubkey::Pubkey}; @@ -20,12 +21,16 @@ pub fn process<'a>( let treasury_index = u32::from_le_bytes(*array_ref![instruction, 0, 4]); let messsage = &instruction[4..]; - let operator = unsafe { Operator::from_account_not_whitelisted(&accounts[0])? }; - let treasury = Treasury::from_account(program_id, treasury_index, &accounts[1])?; - let operator_balance = OperatorBalanceAccount::try_from_account(program_id, &accounts[2])?; - let system = program::System::from_account(&accounts[3])?; + let mut holder = Holder::from_account(program_id, accounts[0].clone())?; + let operator = unsafe { Operator::from_account_not_whitelisted(&accounts[1])? }; + let treasury = Treasury::from_account(program_id, treasury_index, &accounts[2])?; + let operator_balance = OperatorBalanceAccount::try_from_account(program_id, &accounts[3])?; + let system = program::System::from_account(&accounts[4])?; - let trx = Transaction::from_rlp(messsage)?; + holder.validate_owner(&operator)?; + holder.init_heap(0)?; + + let trx = boxx(Transaction::from_rlp(messsage)?); let origin = trx.recover_caller_address()?; operator_balance.validate_owner(&operator)?; @@ -36,7 +41,7 @@ pub fn process<'a>( log_data(&[b"MINER", miner_address.as_bytes()]); let accounts_db = AccountsDB::new( - &accounts[4..], + &accounts[5..], operator, operator_balance, Some(system), diff --git a/evm_loader/program/src/instruction/transaction_step.rs b/evm_loader/program/src/instruction/transaction_step.rs index 16ce917c2..bdaf3d5f5 100644 --- a/evm_loader/program/src/instruction/transaction_step.rs +++ b/evm_loader/program/src/instruction/transaction_step.rs @@ -1,5 +1,3 @@ -use std::collections::BTreeMap; - use solana_program::pubkey::Pubkey; use crate::account::{AccountsDB, AllocateResult, StateAccount}; @@ -9,8 +7,11 @@ use crate::debug::log_data; use crate::error::{Error, Result}; use crate::evm::tracing::NoopEventListener; use crate::evm::{ExitStatus, Machine}; -use crate::executor::{Action, ExecutorState}; +use crate::executor::{Action, ExecutorState, ExecutorStateData}; use crate::gasometer::Gasometer; +use crate::types::boxx::boxx; +use crate::types::TreeMap; +use crate::types::Vector; type EvmBackend<'a, 'r> = ExecutorState<'r, ProgramAccountStorage<'a>>; type Evm<'a, 'r> = Machine, NoopEventListener>; @@ -42,14 +43,10 @@ pub fn do_begin<'a>( let gas_limit_in_tokens = storage.trx().gas_limit_in_tokens()?; origin_account.burn(gas_limit_in_tokens)?; - // Initialize EVM and serialize it to the Holder - let mut backend = ExecutorState::new(&mut account_storage); - - let evm = Machine::new(storage.trx(), origin, &mut backend, None)?; + allocate_or_reinit_state(&mut account_storage, &mut storage, true)?; + let mut state_data = storage.read_executor_state(); - serialize_evm_state(&mut storage, &backend, &evm)?; - - let (_, touched_accounts) = backend.deconstruct(); + let (_, touched_accounts) = state_data.deconstruct(); finalize( 0, storage, @@ -76,17 +73,14 @@ pub fn do_continue<'a>( } let mut account_storage = ProgramAccountStorage::new(accounts)?; - let (mut backend, mut evm) = if reset { + if reset { log_data(&[b"RESET"]); + } - storage.reset_steps_executed(); - - let mut backend = ExecutorState::new(&mut account_storage); - let evm = Machine::new(storage.trx(), storage.trx_origin(), &mut backend, None)?; - (backend, evm) - } else { - deserialize_evm_state(&storage, &mut account_storage)? - }; + allocate_or_reinit_state(&mut account_storage, &mut storage, reset)?; + let mut state_data = storage.read_executor_state(); + let mut evm = storage.read_evm::(); + let mut backend = ExecutorState::new(&mut account_storage, &mut state_data); let mut steps_executed = 0; if backend.exit_status().is_none() { @@ -98,9 +92,7 @@ pub fn do_continue<'a>( steps_executed = steps_returned; } - serialize_evm_state(&mut storage, &backend, &evm)?; - - let (mut results, touched_accounts) = backend.deconstruct(); + let (mut results, touched_accounts) = state_data.deconstruct(); if steps_executed > EVM_STEPS_LAST_ITERATION_MAX { results = None; } @@ -115,17 +107,44 @@ pub fn do_continue<'a>( ) } -fn finalize<'a>( +fn allocate_or_reinit_state( + account_storage: &mut ProgramAccountStorage<'_>, + storage: &mut StateAccount<'_>, + is_allocate: bool, +) -> Result<()> { + if is_allocate { + storage.reset_steps_executed(); + let mut state_data = boxx(ExecutorStateData::new(account_storage)); + let mut evm_backend = ExecutorState::new(account_storage, &mut state_data); + let evm = boxx(Evm::new( + storage.trx(), + storage.trx_origin(), + &mut evm_backend, + None, + )?); + storage.alloc_evm(evm)?; + storage.alloc_executor_state(state_data)?; + } else { + let mut state_data = storage.read_executor_state(); + let mut evm = storage.read_evm(); + + let evm_backend = ExecutorState::new(account_storage, &mut state_data); + evm.reinit(&evm_backend); + }; + Ok(()) +} + +fn finalize<'a, 'b>( steps_executed: u64, mut storage: StateAccount<'a>, mut accounts: ProgramAccountStorage<'a>, - results: Option<(ExitStatus, Vec)>, + results: Option<(&'b ExitStatus, &'b Vector)>, mut gasometer: Gasometer, - touched_accounts: BTreeMap, + touched_accounts: TreeMap, ) -> Result<()> { debug_print!("finalize"); - storage.update_touched_accounts(touched_accounts)?; + storage.update_touched_accounts(&touched_accounts)?; storage.increment_steps_executed(steps_executed)?; log_data(&[ b"STEPS", @@ -138,7 +157,7 @@ fn finalize<'a>( } let status = if let Some((status, actions)) = results { - if accounts.allocate(&actions)? == AllocateResult::Ready { + if accounts.allocate(actions)? == AllocateResult::Ready { accounts.apply_state_change(actions)?; Some(status) } else { @@ -168,8 +187,6 @@ fn finalize<'a>( storage.refund_unused_gas(&mut origin)?; storage.finalize(accounts.program_id())?; - } else { - storage.save_data()?; } Ok(()) @@ -191,39 +208,3 @@ pub fn log_return_value(status: &ExitStatus) { log_data(&[b"RETURN", &[code]]); } - -fn serialize_evm_state( - state: &mut StateAccount, - backend: &EvmBackend, - machine: &Evm, -) -> Result<()> { - let (evm_state_len, evm_machine_len) = { - let mut buffer = state.buffer_mut(); - let backend_bytes = backend.serialize_into(&mut buffer)?; - - let buffer = &mut buffer[backend_bytes..]; - let evm_bytes = machine.serialize_into(buffer)?; - - (backend_bytes, evm_bytes) - }; - - state.set_buffer_variables(evm_state_len, evm_machine_len); - - Ok(()) -} - -fn deserialize_evm_state<'a, 'r>( - state: &StateAccount<'a>, - account_storage: &'r mut ProgramAccountStorage<'a>, -) -> Result<(EvmBackend<'a, 'r>, Evm<'a, 'r>)> { - let (evm_state_len, evm_machine_len) = state.buffer_variables(); - let buffer = state.buffer(); - - let executor_state_data = &buffer[..evm_state_len]; - let backend = ExecutorState::deserialize_from(executor_state_data, account_storage)?; - - let evm_data = &buffer[evm_state_len..][..evm_machine_len]; - let evm = Machine::deserialize_from(evm_data, &backend)?; - - Ok((backend, evm)) -} diff --git a/evm_loader/program/src/instruction/transaction_step_from_account.rs b/evm_loader/program/src/instruction/transaction_step_from_account.rs index df3c4db12..01207fed8 100644 --- a/evm_loader/program/src/instruction/transaction_step_from_account.rs +++ b/evm_loader/program/src/instruction/transaction_step_from_account.rs @@ -58,11 +58,21 @@ pub fn process_inner<'a>( match tag { TAG_HOLDER | TAG_HOLDER_DEPRECATED => { let mut trx = { - let holder = Holder::from_account(program_id, holder_or_storage.clone())?; + let mut holder = Holder::from_account(program_id, holder_or_storage.clone())?; + + // We have to initialize the heap before creating Transaction object, but since + // transaction's rlp itself is stored in the holder account, we have two options: + // 1. Copy the rlp and initialize the heap right after the holder's header. + // This way, the space occupied by the rlp within holder will be reused. + // 2. Don't copy the rlp, initialize the heap after transaction rlp in the holder. + // The first option (chosen) saves the holder space in exchange for compute units. + // The second option wastes the holder space (because transaction bytes will be + // stored two times), but doesnt copy. + let transaction_rlp_copy = holder.transaction().to_vec(); + holder.init_heap(0)?; holder.validate_owner(&operator)?; - let message = holder.transaction(); - let trx = Transaction::from_rlp(&message)?; + let trx = Transaction::from_rlp(&transaction_rlp_copy)?; holder.validate_transaction(&trx)?; @@ -96,7 +106,7 @@ pub fn process_inner<'a>( } TAG_STATE => { let (storage, accounts_status) = - StateAccount::restore(program_id, holder_or_storage, &accounts_db)?; + StateAccount::restore(program_id, &holder_or_storage, &accounts_db)?; operator_balance.validate_transaction(storage.trx())?; let miner_address = operator_balance.miner(storage.trx_origin()); diff --git a/evm_loader/program/src/instruction/transaction_step_from_instruction.rs b/evm_loader/program/src/instruction/transaction_step_from_instruction.rs index 798a0942f..8de489773 100644 --- a/evm_loader/program/src/instruction/transaction_step_from_instruction.rs +++ b/evm_loader/program/src/instruction/transaction_step_from_instruction.rs @@ -1,6 +1,6 @@ use crate::account::legacy::{TAG_HOLDER_DEPRECATED, TAG_STATE_FINALIZED_DEPRECATED}; use crate::account::{ - program, AccountsDB, AccountsStatus, Operator, OperatorBalanceAccount, + program, AccountsDB, AccountsStatus, Holder, Operator, OperatorBalanceAccount, OperatorBalanceValidator, StateAccount, Treasury, TAG_HOLDER, TAG_STATE, TAG_STATE_FINALIZED, }; use crate::debug::log_data; @@ -50,6 +50,11 @@ pub fn process<'a>( match tag { TAG_HOLDER | TAG_STATE_FINALIZED => { + // Holder's method (fn init_heap) transforms TAG_STATE_FINALIZED into HOLDER + // and it breaks the logic (of throwing StorageAccountFinalized error). + // In this case, an associated function is used instead. + Holder::init_holder_heap(program_id, &mut storage_info.clone(), 0)?; + let trx = Transaction::from_rlp(message)?; let origin = trx.recover_caller_address()?; @@ -72,7 +77,7 @@ pub fn process<'a>( } TAG_STATE => { let (storage, accounts_status) = - StateAccount::restore(program_id, storage_info, &accounts_db)?; + StateAccount::restore(program_id, &storage_info, &accounts_db)?; operator_balance.validate_transaction(storage.trx())?; let miner_address = operator_balance.miner(storage.trx_origin()); diff --git a/evm_loader/program/src/lib.rs b/evm_loader/program/src/lib.rs index 5bb10e2a8..561bb908f 100644 --- a/evm_loader/program/src/lib.rs +++ b/evm_loader/program/src/lib.rs @@ -29,6 +29,7 @@ pub mod external_programs; pub mod gasometer; #[cfg(target_os = "solana")] pub mod instruction; +#[macro_use] pub mod types; // Export current solana-sdk types for downstream users who may also be building with a different diff --git a/evm_loader/program/src/types/boxx.rs b/evm_loader/program/src/types/boxx.rs new file mode 100644 index 000000000..15bb4f498 --- /dev/null +++ b/evm_loader/program/src/types/boxx.rs @@ -0,0 +1,7 @@ +use crate::allocator::{acc_allocator, StateAccountAllocator}; + +pub type Boxx = allocator_api2::boxed::Box; + +pub fn boxx(value: T) -> Boxx { + Boxx::new_in(value, acc_allocator()) +} diff --git a/evm_loader/program/src/types/mod.rs b/evm_loader/program/src/types/mod.rs index 756a5a409..3a074f214 100644 --- a/evm_loader/program/src/types/mod.rs +++ b/evm_loader/program/src/types/mod.rs @@ -4,7 +4,13 @@ pub use transaction::LegacyTx; pub use transaction::StorageKey; pub use transaction::Transaction; pub use transaction::TransactionPayload; +pub use tree_map::TreeMap; +pub use vector::Vector; mod address; -pub mod serde; mod transaction; +pub mod tree_map; +#[macro_use] +pub mod vector; +pub mod boxx; +pub mod read_raw_utils; diff --git a/evm_loader/program/src/types/read_raw_utils.rs b/evm_loader/program/src/types/read_raw_utils.rs new file mode 100644 index 000000000..43cabd734 --- /dev/null +++ b/evm_loader/program/src/types/read_raw_utils.rs @@ -0,0 +1,37 @@ +use std::cmp::{max, min}; +use std::ptr::read_unaligned; +use std::slice; + +pub trait ReconstructRaw { + /// # Safety + /// Function to reconstruct an object from the memory. Should be used by macro and not implemented manually. + /// Also, it must not be used in the EVM Program, only in the Core API. + unsafe fn build(ptr: *const Self, offset: isize) -> Self; +} + +/// Reading the raw memory bits to reconstuct the Vec type. +/// # Safety +/// Low level reads in the memory with offsets to reconstruct the vector. +#[must_use] +pub unsafe fn read_vec(vec_start_ptr: *const usize, offset: isize) -> Vec { + // 1. The Vector's memory layout consists of three usizes: ptr to the buffer, capacity and length. + // 2. There's no alignment between the fields, the Vector occupies exactly the 3*sizeof bytes. + // 3. The order of those fields in the memory is unspecified (no repr is set on the vec struct). + // => The len is the smallest of those three usizes, because it can't realistically be more than the buffer + // ptr value and it's no more than capacity. + // => The buffer ptr is the biggest among them. + let vec_parts = ( + read_unaligned(vec_start_ptr), + read_unaligned(vec_start_ptr.add(1)), + read_unaligned(vec_start_ptr.add(2)), + ); + let vec_len = min(min(vec_parts.0, vec_parts.1), vec_parts.2); + let vec_buf_ptr_unadjusted = max(max(vec_parts.0, vec_parts.1), vec_parts.2) as *const u8; + // Offset the buffer pointer from the state account allocator memory space into the current allocator. + let vec_buf_ptr_adjusted = vec_buf_ptr_unadjusted.offset(offset).cast::().cast_mut(); + + // Allocate a new vec and with the exact number of elements and copy the memory. + let mut res_vec = vec![T::default(); vec_len]; + res_vec.copy_from_slice(slice::from_raw_parts(vec_buf_ptr_adjusted, vec_len)); + res_vec +} diff --git a/evm_loader/program/src/types/serde.rs b/evm_loader/program/src/types/serde.rs deleted file mode 100644 index eb94cfbbe..000000000 --- a/evm_loader/program/src/types/serde.rs +++ /dev/null @@ -1,130 +0,0 @@ -// use ethnum::U256; - -// serde_with::serde_conv!( -// pub U256AsWords, -// U256, -// |value: &U256| { value.into_words() }, -// |words: (u128, u128)| -> Result<_, std::convert::Infallible> { Ok(U256::from_words(words.0, words.1)) } -// ); - -pub mod option_u256 { - use std::fmt::{self, Formatter}; - - use ethnum::U256; - use serde::{de::Visitor, Deserializer, Serializer}; - - pub fn serialize(value: &Option, serializer: S) -> Result - where - S: Serializer, - { - if let Some(value) = value { - serializer.serialize_bytes(&value.to_le_bytes()) - } else { - serializer.serialize_bytes(&[]) - } - } - - struct BytesVisitor; - - impl<'de> Visitor<'de> for BytesVisitor { - type Value = Option; - - fn expecting(&self, f: &mut Formatter) -> fmt::Result { - f.write_str(concat!("32 bytes in little endian")) - } - - fn visit_bytes(self, v: &[u8]) -> Result - where - E: serde::de::Error, - { - if v.is_empty() { - return Ok(None); - } - - let bytes = v - .try_into() - .map_err(|_| E::invalid_length(v.len(), &self))?; - - Ok(Some(U256::from_le_bytes(bytes))) - } - } - - #[doc(hidden)] - pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> - where - D: Deserializer<'de>, - { - deserializer.deserialize_bytes(BytesVisitor) - } -} - -pub mod bytes_32 { - pub fn serialize(value: &[u8; 32], serializer: S) -> Result - where - S: serde::ser::Serializer, - { - if serializer.is_human_readable() { - serializer.serialize_str(&hex::encode(value)) - } else { - serializer.serialize_bytes(value) - } - } - - pub fn deserialize<'de, D>(deserializer: D) -> Result<[u8; 32], D::Error> - where - D: serde::Deserializer<'de>, - { - struct BytesVisitor; - - impl<'de> serde::de::Visitor<'de> for BytesVisitor { - type Value = [u8; 32]; - - fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.write_str("[u8; 32]") - } - - fn visit_str(self, value: &str) -> Result - where - E: serde::de::Error, - { - use serde::de::Unexpected::Str; - - let value = hex::decode(value) - .map_err(|_| serde::de::Error::invalid_value(Str(value), &self))?; - - let value_len = value.len(); - value - .try_into() - .map_err(|_| serde::de::Error::invalid_length(value_len, &self)) - } - - fn visit_bytes(self, value: &[u8]) -> Result - where - E: serde::de::Error, - { - value - .try_into() - .map_err(|_| serde::de::Error::invalid_length(value.len(), &self)) - } - - fn visit_seq(self, mut seq: S) -> Result - where - S: serde::de::SeqAccess<'de>, - { - let mut bytes = Vec::with_capacity(32); - while let Some(b) = seq.next_element()? { - bytes.push(b); - } - bytes - .try_into() - .map_err(|_| serde::de::Error::custom("Invalid [u8; 32] value")) - } - } - - if deserializer.is_human_readable() { - deserializer.deserialize_str(BytesVisitor) - } else { - deserializer.deserialize_bytes(BytesVisitor) - } - } -} diff --git a/evm_loader/program/src/types/transaction.rs b/evm_loader/program/src/types/transaction.rs index 0e5bba532..229868e8f 100644 --- a/evm_loader/program/src/types/transaction.rs +++ b/evm_loader/program/src/types/transaction.rs @@ -1,22 +1,26 @@ use ethnum::U256; use maybe_async::maybe_async; +use rlp::{DecoderError, Rlp}; use serde::{Deserialize, Serialize}; use std::convert::TryInto; +use crate::types::vector::VectorVecExt; use crate::{ - account_storage::AccountStorage, config::GAS_LIMIT_MULTIPLIER_NO_CHAINID, error::Error, + account_storage::AccountStorage, config::GAS_LIMIT_MULTIPLIER_NO_CHAINID, error::Error, vector, }; -use super::{ - serde::{bytes_32, option_u256}, - Address, -}; +use super::vector::VectorSliceExt; +use super::{Address, Vector}; + +use super::read_raw_utils::ReconstructRaw; +use crate::types::read_raw_utils::read_vec; +use evm_loader_macro::ReconstructRaw; #[repr(transparent)] #[derive( Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize, )] -pub struct StorageKey(#[serde(with = "bytes_32")] [u8; 32]); +pub struct StorageKey([u8; 32]); impl rlp::Decodable for StorageKey { fn decode(rlp: &rlp::Rlp) -> Result { @@ -52,6 +56,10 @@ impl AsRef<[u8]> for StorageKey { } } +fn decode_byte_vector(rlp: &Rlp) -> Result, DecoderError> { + rlp.decoder().decode_value(|bytes| Ok(bytes.to_vector())) +} + #[derive(Debug, Clone)] pub enum TransactionEnvelope { Legacy, @@ -76,25 +84,18 @@ impl TransactionEnvelope { } } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, ReconstructRaw)] +#[repr(C)] pub struct LegacyTx { pub nonce: u64, - #[serde(with = "ethnum::serde::bytes::le")] pub gas_price: U256, - #[serde(with = "ethnum::serde::bytes::le")] pub gas_limit: U256, pub target: Option
, - #[serde(with = "ethnum::serde::bytes::le")] pub value: U256, - #[serde(with = "serde_bytes")] - pub call_data: Vec, - #[serde(with = "ethnum::serde::bytes::le")] + pub call_data: Vector, pub v: U256, - #[serde(with = "ethnum::serde::bytes::le")] pub r: U256, - #[serde(with = "ethnum::serde::bytes::le")] pub s: U256, - #[serde(with = "option_u256")] pub chain_id: Option, pub recovery_id: u8, } @@ -126,7 +127,7 @@ impl rlp::Decodable for LegacyTx { } }; let value: U256 = u256(&rlp.at(4)?)?; - let call_data = rlp.val_at(5)?; + let call_data = decode_byte_vector(&rlp.at(5)?)?; let v: U256 = u256(&rlp.at(6)?)?; let r: U256 = u256(&rlp.at(7)?)?; let s: U256 = u256(&rlp.at(8)?)?; @@ -165,26 +166,20 @@ impl rlp::Decodable for LegacyTx { } } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, ReconstructRaw)] +#[repr(C)] pub struct AccessListTx { pub nonce: u64, - #[serde(with = "ethnum::serde::bytes::le")] pub gas_price: U256, - #[serde(with = "ethnum::serde::bytes::le")] pub gas_limit: U256, pub target: Option
, - #[serde(with = "ethnum::serde::bytes::le")] pub value: U256, - #[serde(with = "serde_bytes")] - pub call_data: Vec, - #[serde(with = "ethnum::serde::bytes::le")] + pub call_data: Vector, pub r: U256, - #[serde(with = "ethnum::serde::bytes::le")] pub s: U256, - #[serde(with = "ethnum::serde::bytes::le")] pub chain_id: U256, pub recovery_id: u8, - pub access_list: Vec<(Address, Vec)>, + pub access_list: Vector<(Address, Vector)>, } impl rlp::Decodable for AccessListTx { @@ -216,10 +211,10 @@ impl rlp::Decodable for AccessListTx { }; let value: U256 = u256(&rlp.at(5)?)?; - let call_data = rlp.val_at(6)?; + let call_data = decode_byte_vector(&rlp.at(6)?)?; let rlp_access_list = rlp.at(7)?; - let mut access_list = vec![]; + let mut access_list = vector![]; for entry in &rlp_access_list { // Check if entry is a list @@ -228,7 +223,7 @@ impl rlp::Decodable for AccessListTx { let address: Address = entry.at(0)?.as_val()?; // Get storage keys from second element - let mut storage_keys: Vec = vec![]; + let mut storage_keys: Vector = vector![]; for key in &entry.at(1)? { storage_keys.push(key.as_val()?); @@ -269,19 +264,19 @@ impl rlp::Decodable for AccessListTx { // TODO: Will be added as a part of EIP-1559 // struct DynamicFeeTx {} -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug)] +#[repr(C, u8)] pub enum TransactionPayload { Legacy(LegacyTx), AccessList(AccessListTx), } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug)] +#[repr(C)] pub struct Transaction { pub transaction: TransactionPayload, pub byte_len: usize, - #[serde(with = "bytes_32")] pub hash: [u8; 32], - #[serde(with = "bytes_32")] pub signed_hash: [u8; 32], } @@ -598,7 +593,7 @@ impl Transaction { } #[must_use] - pub fn access_list(&self) -> Option<&Vec<(Address, Vec)>> { + pub fn access_list(&self) -> Option<&Vector<(Address, Vector)>> { match &self.transaction { TransactionPayload::AccessList(AccessListTx { access_list, .. }) => Some(access_list), TransactionPayload::Legacy(_) => None, diff --git a/evm_loader/program/src/types/tree_map.rs b/evm_loader/program/src/types/tree_map.rs new file mode 100644 index 000000000..847a4e82c --- /dev/null +++ b/evm_loader/program/src/types/tree_map.rs @@ -0,0 +1,187 @@ +use std::{ + cmp::Ordering, + fmt::{self, Debug, Display}, + hash::Hash, + ops::Index, + usize, +}; + +use super::Vector; +use crate::allocator::acc_allocator; + +#[derive(Clone)] +#[repr(C)] +pub struct TreeMap { + entries: Vector<(K, V)>, +} + +impl TreeMap { + #[must_use] + pub fn new() -> Self { + TreeMap { + entries: Vector::new_in(acc_allocator()), + } + } + + #[must_use] + pub fn with_capacity(capacity: usize) -> Self { + TreeMap { + entries: Vector::with_capacity_in(capacity, acc_allocator()), + } + } + + #[must_use] + pub fn is_empty(&self) -> bool { + self.entries.is_empty() + } + + #[must_use] + pub fn len(&self) -> usize { + self.entries.len() + } + + pub fn get(&self, key: &K) -> Option<&V> { + self.entries + .binary_search_by_key(key, |&(k, _)| k) + .map_or(Option::None, |idx| Option::Some(&self.entries[idx].1)) + } + + pub fn get_mut(&mut self, key: &K) -> Option<&mut V> { + self.entries + .binary_search_by_key(key, |(k, _)| *k) + .map_or(Option::None, |idx| Option::Some(&mut self.entries[idx].1)) + } + + pub fn insert(&mut self, key: K, value: V) -> Option + where + V: Clone, + { + match self.entries.binary_search_by_key(&key, |(k, _)| *k) { + Ok(idx) => { + // Clone is better in performance than potential vec realloc. + let old = self.entries[idx].1.clone(); + self.entries[idx] = (key, value); + Some(old) + } + Err(idx) => { + self.entries.insert(idx, (key, value)); + None + } + } + } + + pub fn update_or_insert(&mut self, key: K, value: &V, f: F) -> Result<(), E> + where + F: FnOnce(V) -> Result, + V: Clone, + { + match self.entries.binary_search_by_key(&key, |(k, _)| *k) { + Ok(idx) => { + let entry = &self.entries[idx]; + self.entries[idx] = (key, f(entry.1.clone())?); + } + Err(idx) => { + self.entries.insert(idx, (key, value.clone())); + } + } + Ok(()) + } + + pub fn remove(&mut self, key: &K) -> Option { + match self.entries.binary_search_by_key(key, |(k, _)| *k) { + Ok(idx) => { + let entry = self.entries.remove(idx); + Some(entry.1) + } + Err(_) => None, + } + } + + pub fn remove_entry(&mut self, key: &K) -> Option<(K, V)> { + match self.entries.binary_search_by_key(key, |(k, _)| *k) { + Ok(idx) => Some(self.entries.remove(idx)), + Err(_) => None, + } + } + + pub fn keys(&self) -> impl Iterator { + self.entries.iter().map(|(k, _)| k) + } +} + +impl Default for TreeMap { + fn default() -> Self { + Self::new() + } +} + +impl Index for TreeMap { + type Output = V; + + fn index(&self, index: K) -> &Self::Output { + self.get(&index).expect("no entry found for key") + } +} + +impl FromIterator<(K, V)> for TreeMap { + fn from_iter>(iter: T) -> Self { + let mut last_key: Option = None; + let mut entries = Vector::new_in(acc_allocator()); + + for item in iter { + let prev_key = last_key.replace(item.0); + if let Some(ref prev) = prev_key { + match Ord::cmp(prev, &item.0) { + Ordering::Less => (), + // Insert the last one from the consequtive list of equal keys. + Ordering::Equal => continue, + // Panic as we expect to have a valid iterator with non-decreasing keys. + Ordering::Greater => panic!("map keys should be non-decreasing"), + } + } + entries.push(item); + } + + TreeMap { entries } + } +} + +#[allow(clippy::iter_without_into_iter)] +impl<'a, K: 'a, V: 'a> TreeMap { + pub fn iter(&'a self) -> std::slice::Iter<'a, (K, V)> { + self.entries.iter() + } + + pub fn iter_mut(&'a mut self) -> std::slice::IterMut<'a, (K, V)> { + self.entries.iter_mut() + } +} + +impl fmt::Debug for TreeMap { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut res = write!(f, "TreeMap {{"); + for i in 0..self.entries.len() { + let e = &self.entries[i]; + res = res.and(write!(f, "{:?} -> {:?}, ", e.0, e.1)); + } + res.and(write!(f, " }}")) + } +} + +impl fmt::Display for TreeMap { + // This trait requires `fmt` with this exact signature. + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut res = write!(f, "TreeMap {{"); + for i in 0..self.entries.len() { + let e = &self.entries[i]; + res = res.and(write!(f, "{} -> {}, ", e.0, e.1)); + } + res.and(write!(f, " }}")) + } +} + +impl Hash for TreeMap { + fn hash(&self, state: &mut H) { + self.entries.hash(state); + } +} diff --git a/evm_loader/program/src/types/vector.rs b/evm_loader/program/src/types/vector.rs new file mode 100644 index 000000000..e76ff7400 --- /dev/null +++ b/evm_loader/program/src/types/vector.rs @@ -0,0 +1,94 @@ +use crate::allocator::{acc_allocator, StateAccountAllocator}; +use allocator_api2::SliceExt; + +pub type Vector = allocator_api2::vec::Vec; + +#[macro_export] +macro_rules! vector { + () => ( + allocator_api2::vec::Vec::new_in($crate::allocator::acc_allocator()) + ); + ($elem:expr; $n:expr) => ( + allocator_api2::vec::from_elem_in($elem, $n, $crate::allocator::acc_allocator()) + ); + ($($x:expr),+ $(,)?) => ( + allocator_api2::boxed::Box::<[_], $crate::allocator::StateAccountAllocator>::into_vec( + allocator_api2::boxed::Box::slice( + allocator_api2::boxed::Box::new_in([$($x),+], $crate::allocator::acc_allocator()) + ) + ) + ); +} + +pub trait VectorVecExt { + fn into_vector(self) -> Vector + where + T: Copy + Default; +} + +pub trait VectorSliceExt { + fn to_vector(&self) -> Vector + where + T: Copy + Default; +} + +pub trait VectorVecSlowExt { + fn elementwise_copy_into_vector(self) -> Vector + where + T: Clone; +} + +pub trait VectorSliceSlowExt { + fn elementwise_copy_to_vector(&self) -> Vector + where + T: Clone; +} + +impl VectorVecExt for Vec { + fn into_vector(self) -> Vector { + let mut ret = Vector::with_capacity_in(self.len(), crate::allocator::acc_allocator()); + // SAFETY: + // allocated above with the capacity of `self.len()`, and initialize to `self.len()` in + // ptr::copy_to_non_overlapping below. + unsafe { + self.as_ptr() + .copy_to_nonoverlapping(ret.as_mut_ptr(), self.len()); + ret.set_len(self.len()); + } + ret + } +} + +impl VectorSliceExt for [T] { + fn to_vector(&self) -> Vector { + let mut ret = Vector::with_capacity_in(self.len(), crate::allocator::acc_allocator()); + // SAFETY: + // allocated above with the capacity of `self.len()`, and initialize to `self.len()` in + // ptr::copy_to_non_overlapping below. + unsafe { + self.as_ptr() + .copy_to_nonoverlapping(ret.as_mut_ptr(), self.len()); + ret.set_len(self.len()); + } + ret + } +} + +impl VectorSliceSlowExt for [T] { + fn elementwise_copy_to_vector(&self) -> Vector + where + T: Clone, + { + SliceExt::to_vec_in(self, acc_allocator()) + } +} + +impl VectorVecSlowExt for Vec { + fn elementwise_copy_into_vector(self) -> Vector { + let mut ret = Vector::with_capacity_in(self.len(), acc_allocator()); + for item in self { + ret.push(item); + } + ret + } +} From a844470d360bfcc127488364fe6b2cd8985d7714 Mon Sep 17 00:00:00 2001 From: Evgeny Zdanovich Date: Wed, 14 Aug 2024 15:14:30 +0200 Subject: [PATCH 286/318] Set version to 1.15. (#523) --- evm_loader/Cargo.lock | 10 +++++----- evm_loader/api/Cargo.toml | 2 +- evm_loader/cli/Cargo.toml | 2 +- evm_loader/lib/Cargo.toml | 2 +- evm_loader/program/Cargo.toml | 2 +- evm_loader/rpc/Cargo.toml | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 5c6448eeb..95e9098f6 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -2003,7 +2003,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "evm-loader" -version = "1.14.0-dev" +version = "1.15.0-dev" dependencies = [ "allocator-api2", "arrayref", @@ -3414,7 +3414,7 @@ dependencies = [ [[package]] name = "neon-api" -version = "1.14.0-dev" +version = "1.15.0-dev" dependencies = [ "actix-request-identifier", "actix-web", @@ -3437,7 +3437,7 @@ dependencies = [ [[package]] name = "neon-cli" -version = "1.14.0-dev" +version = "1.15.0-dev" dependencies = [ "build-info", "build-info-build", @@ -3459,7 +3459,7 @@ dependencies = [ [[package]] name = "neon-lib" -version = "1.14.0-dev" +version = "1.15.0-dev" dependencies = [ "abi_stable", "anyhow", @@ -3523,7 +3523,7 @@ dependencies = [ [[package]] name = "neon-rpc" -version = "1.14.0-dev" +version = "1.15.0-dev" dependencies = [ "actix-web", "build-info", diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 6ac1b88e5..b4b0939fc 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "neon-api" -version = "1.14.0-dev" +version = "1.15.0-dev" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index 367008d49..a2ff8a695 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "neon-cli" -version = "1.14.0-dev" +version = "1.15.0-dev" authors = ["NeonLabs Maintainers "] edition = "2021" diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 5d2990442..c948e0c54 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "neon-lib" -version = "1.14.0-dev" +version = "1.15.0-dev" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index c78059090..00763c75a 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "evm-loader" -version = "1.14.0-dev" +version = "1.15.0-dev" description = "Neon EVM loader" authors = ["NeonLabs Maintainers "] edition = "2021" diff --git a/evm_loader/rpc/Cargo.toml b/evm_loader/rpc/Cargo.toml index 766a77796..0274a6c6d 100644 --- a/evm_loader/rpc/Cargo.toml +++ b/evm_loader/rpc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "neon-rpc" -version = "1.14.0-dev" +version = "1.15.0-dev" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From 8222602e5e943faf1e6dd6bbad6c2fa55e44dfdb Mon Sep 17 00:00:00 2001 From: iguberman Date: Wed, 21 Aug 2024 16:35:32 -0500 Subject: [PATCH 287/318] PR review comments follow-up --- Dockerfile | 5 +-- evm_loader/Cargo.lock | 1 - evm_loader/lib/Cargo.toml | 1 - evm_loader/lib/src/config.rs | 34 ++++++++++++++------- evm_loader/lib/src/rpc/emulator_client.rs | 2 -- evm_loader/lib/src/types/mod.rs | 28 ++++------------- evm_loader/lib/src/types/tracer_ch_db.rs | 2 +- evm_loader/lib/src/types/tracer_rocks_db.rs | 9 ++---- 8 files changed, 34 insertions(+), 48 deletions(-) diff --git a/Dockerfile b/Dockerfile index 88a6f2055..286194147 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,7 +17,7 @@ WORKDIR /opt/neon-evm/evm_loader ARG REVISION ENV NEON_REVISION=${REVISION} RUN cargo fmt --check && \ -# check cargo clippy --release && \ + check cargo clippy --release && \ cargo build --release && \ cargo test --release && \ cargo build-sbf --manifest-path program/Cargo.toml --features devnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-devnet.so && \ @@ -62,9 +62,6 @@ COPY ci/operator-keypairs/id.json /root/.config/solana/id.json COPY ci/operator-keypairs/id2.json /root/.config/solana/id2.json COPY ci/keys/ /opt/keys -ARG ROCKSDB_HOST -ARG ROCKSDB_PORT - ENV PATH=${PATH}:/opt ENV ROCKSDB_HOST=${ROCKSDB_HOST} ENV ROCKSDB_PORT=${ROCKSDB_PORT} diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index ba769bb86..0a0544808 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -3637,7 +3637,6 @@ dependencies = [ "spl-token", "strum 0.26.3", "strum_macros 0.26.4", - "tempfile", "thiserror", "tokio", "tracing", diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index a163eed7f..7866135ed 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -12,7 +12,6 @@ bincode = "1.3.3" hyper = "0.14" evm-loader = { path = "../program", default-features = false, features = ["log", "async-trait"] } jsonrpsee = { version = "0.20", features = ["server", "ws-client", "macros"] } -tempfile = "3.10.1" solana-sdk.workspace = true solana-client.workspace = true solana-account-decoder.workspace = true diff --git a/evm_loader/lib/src/config.rs b/evm_loader/lib/src/config.rs index bfbbf879c..5c4f9f5e9 100644 --- a/evm_loader/lib/src/config.rs +++ b/evm_loader/lib/src/config.rs @@ -1,8 +1,6 @@ -use crate::types::{ChDbConfig, DbConfig, RocksDbConfig}; -use std::{env, str::FromStr}; - use serde::{Deserialize, Serialize}; use solana_sdk::{commitment_config::CommitmentConfig, pubkey::Pubkey, signature::Keypair}; +use std::{env, str::FromStr}; const DEFAULT_ROCKSDB_PORT: u16 = 9888; @@ -30,6 +28,24 @@ pub struct APIOptions { pub db_config: DbConfig, } +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum DbConfig { + RocksDbConfig(RocksDbConfig), + ChDbConfig(ChDbConfig), +} +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct ChDbConfig { + pub clickhouse_url: Vec, + pub clickhouse_user: Option, + pub clickhouse_password: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct RocksDbConfig { + pub rocksdb_host: String, + pub rocksdb_port: u16, +} + /// # Errors #[must_use] pub fn load_api_config_from_environment() -> APIOptions { @@ -83,14 +99,10 @@ pub fn load_db_config_from_environment() -> DbConfig { env::var("TRACER_DB_TYPE") .ok() .and_then(|db_type| match db_type.to_lowercase().as_str() { - "rocksdb" => Option::from(DbConfig { - rocksdb_config: Option::from(load_rocks_db_config_from_environment()), - chdb_config: None, - }), - "clickhouse" => Option::from(DbConfig { - rocksdb_config: None, - chdb_config: Option::from(load_ch_db_config_from_environment()), - }), + "rocksdb" => Some(DbConfig::RocksDbConfig( + load_rocks_db_config_from_environment(), + )), + "clickhouse" => Some(DbConfig::ChDbConfig(load_ch_db_config_from_environment())), _ => None, }) .expect("TRACER_DB_TYPE variable must be either 'clickhouse' or 'rocksdb'") diff --git a/evm_loader/lib/src/rpc/emulator_client.rs b/evm_loader/lib/src/rpc/emulator_client.rs index a3288aeab..5a63af7f6 100644 --- a/evm_loader/lib/src/rpc/emulator_client.rs +++ b/evm_loader/lib/src/rpc/emulator_client.rs @@ -73,8 +73,6 @@ impl<'rpc, T: Rpc> Rpc for EmulatorAccountStorage<'rpc, T> { j += 1; } - debug!("emulator_client.get_multiple_accounts accounts: {accounts:?}"); - Ok(accounts) } diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index 3af210bc1..0dd38394f 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -4,6 +4,7 @@ pub(crate) mod tracer_ch_db; pub mod tracer_rocks_db; use crate::commands::get_config::ChainInfo; +use crate::config::DbConfig; use crate::tracing::TraceCallConfig; use crate::types::tracer_ch_common::{EthSyncStatus, RevisionMap}; pub use crate::types::tracer_ch_db::ClickHouseDb; @@ -26,25 +27,9 @@ use serde_with::{hex::Hex, serde_as, DisplayFromStr, OneOrMany}; use solana_sdk::signature::Signature; use solana_sdk::{account::Account, pubkey::Pubkey}; use std::collections::HashMap; -pub type DbResult = Result; - -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Default)] -pub struct DbConfig { - pub rocksdb_config: Option, - pub chdb_config: Option, -} -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Default)] -pub struct ChDbConfig { - pub clickhouse_url: Vec, - pub clickhouse_user: Option, - pub clickhouse_password: Option, -} +use DbConfig::{ChDbConfig, RocksDbConfig}; -#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Default)] -pub struct RocksDbConfig { - pub rocksdb_host: String, - pub rocksdb_port: u16, -} +pub type DbResult = Result; #[enum_dispatch] pub enum TracerDbType { @@ -54,10 +39,9 @@ pub enum TracerDbType { impl TracerDbType { pub async fn from_config(db_config: &DbConfig) -> Self { - if let Some(rocksdb_config) = &db_config.rocksdb_config { - RocksDb::new(rocksdb_config).await.into() - } else { - ClickHouseDb::new(&db_config.clone().chdb_config.unwrap()).into() + match db_config { + RocksDbConfig(rocks_db_config) => RocksDb::new(rocks_db_config).await.into(), + ChDbConfig(ch_db_config) => ClickHouseDb::new(ch_db_config).into(), } } } diff --git a/evm_loader/lib/src/types/tracer_ch_db.rs b/evm_loader/lib/src/types/tracer_ch_db.rs index b8d823be9..1264bd05b 100644 --- a/evm_loader/lib/src/types/tracer_ch_db.rs +++ b/evm_loader/lib/src/types/tracer_ch_db.rs @@ -7,7 +7,7 @@ use crate::{ use super::tracer_ch_common::{ChResult, EthSyncStatus, EthSyncing, RevisionMap, SlotParentRooted}; -use crate::types::ChDbConfig; +use crate::config::ChDbConfig; use anyhow::anyhow; use async_trait::async_trait; use clickhouse::Client; diff --git a/evm_loader/lib/src/types/tracer_rocks_db.rs b/evm_loader/lib/src/types/tracer_rocks_db.rs index f8ab52cf5..e129a0d97 100644 --- a/evm_loader/lib/src/types/tracer_rocks_db.rs +++ b/evm_loader/lib/src/types/tracer_rocks_db.rs @@ -1,4 +1,4 @@ -use abi_stable::traits::IntoOwned; +use crate::config::RocksDbConfig; use async_trait::async_trait; use jsonrpsee::core::client::ClientT; use jsonrpsee::core::Serialize; @@ -24,7 +24,7 @@ pub struct AccountParams { } use crate::types::tracer_ch_common::{EthSyncStatus, RevisionMap}; -use crate::types::{DbResult, RocksDbConfig, TracerDb}; +use crate::types::{DbResult, TracerDb}; // use reconnecting_jsonrpsee_ws_client::{Client, CallRetryPolicy, rpc_params, ExponentialBackoff}; #[derive(Clone, Debug)] pub struct RocksDb { @@ -98,10 +98,7 @@ impl TracerDb for RocksDb { let response: String = self .client - .request( - "get_account", - rpc_params![pubkey.into_owned(), slot, tx_index_in_block], - ) + .request("get_account", rpc_params![pubkey, slot, tx_index_in_block]) .await?; let account = from_str::>(response.as_str())?; From aa7bab2bee0c48764767cd4ce0d88d425c69165c Mon Sep 17 00:00:00 2001 From: iguberman Date: Wed, 21 Aug 2024 16:36:37 -0500 Subject: [PATCH 288/318] PR review comments follow-up --- .github/workflows/pipeline.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index c1adf0ec6..d0ca7826f 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -19,7 +19,6 @@ env: DOCKERHUB_ORG_NAME: ${{vars.DOCKERHUB_ORG_NAME}} RUN_LINK_REPO: "neonlabsorg/neon-proxy.py" BUILD_URL: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" - TRACER_DB_TYPE: clickhouse concurrency: group: ${{ github.workflow }}-${{ github.ref }} From d0155a54919a316a7be3066d54934815dbce7afb Mon Sep 17 00:00:00 2001 From: iguberman Date: Wed, 21 Aug 2024 16:40:07 -0500 Subject: [PATCH 289/318] PR review comments follow-up --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 286194147..c653f30e9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,7 +17,7 @@ WORKDIR /opt/neon-evm/evm_loader ARG REVISION ENV NEON_REVISION=${REVISION} RUN cargo fmt --check && \ - check cargo clippy --release && \ + cargo clippy --release && \ cargo build --release && \ cargo test --release && \ cargo build-sbf --manifest-path program/Cargo.toml --features devnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-devnet.so && \ From 8cca968fd2fe525d3bfe7c30f16943eb2de0befa Mon Sep 17 00:00:00 2001 From: iguberman Date: Thu, 22 Aug 2024 00:57:01 -0500 Subject: [PATCH 290/318] Fix clippy errors --- evm_loader/lib/src/commands/init_environment.rs | 5 +++-- evm_loader/lib/src/types/tracer_rocks_db.rs | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/evm_loader/lib/src/commands/init_environment.rs b/evm_loader/lib/src/commands/init_environment.rs index 20f3e7c8a..78d2c0c52 100644 --- a/evm_loader/lib/src/commands/init_environment.rs +++ b/evm_loader/lib/src/commands/init_environment.rs @@ -135,14 +135,15 @@ pub async fn execute( let program_parameters = Parameters::new(read_elf_parameters(config, &data)); let neon_revision = program_parameters.get::("NEON_REVISION")?; - if neon_revision != env!("NEON_REVISION") { + let env_neon_revision = env!("NEON_REVISION"); + if neon_revision != env_neon_revision { if force { warn!("NeonEVM revision doesn't match CLI revision. This check has been disabled with `--force` flag"); } else { error!("NeonEVM revision doesn't match CLI revision. Use appropriate neon-cli version or add `--force` flag"); return Err(EnvironmentError::RevisionMismatch( neon_revision, - env!("NEON_REVISION").to_string(), + env_neon_revision.to_string(), ) .into()); } diff --git a/evm_loader/lib/src/types/tracer_rocks_db.rs b/evm_loader/lib/src/types/tracer_rocks_db.rs index e129a0d97..07bff501f 100644 --- a/evm_loader/lib/src/types/tracer_rocks_db.rs +++ b/evm_loader/lib/src/types/tracer_rocks_db.rs @@ -130,7 +130,8 @@ impl TracerDb for RocksDb { async fn get_neon_revision(&self, slot: Slot, pubkey: &Pubkey) -> DbResult { info!("get_neon_revision for {slot:?}, pubkey: {pubkey:?}"); - Ok(env!("NEON_REVISION").to_string()) + let neon_revision = env!("NEON_REVISION"); + Ok(neon_revision.to_string()) } async fn get_slot_by_blockhash(&self, blockhash: String) -> DbResult { From b1b29a84c810dece37a01e875d574cc5ee7615f3 Mon Sep 17 00:00:00 2001 From: iguberman Date: Mon, 26 Aug 2024 00:52:25 -0500 Subject: [PATCH 291/318] PR comments followup (send Pubkey and String as str in request params) --- evm_loader/lib/src/types/tracer_rocks_db.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/evm_loader/lib/src/types/tracer_rocks_db.rs b/evm_loader/lib/src/types/tracer_rocks_db.rs index 07bff501f..f0f621790 100644 --- a/evm_loader/lib/src/types/tracer_rocks_db.rs +++ b/evm_loader/lib/src/types/tracer_rocks_db.rs @@ -98,7 +98,10 @@ impl TracerDb for RocksDb { let response: String = self .client - .request("get_account", rpc_params![pubkey, slot, tx_index_in_block]) + .request( + "get_account", + rpc_params![pubkey.to_string(), slot, tx_index_in_block], + ) .await?; let account = from_str::>(response.as_str())?; @@ -114,7 +117,7 @@ impl TracerDb for RocksDb { async fn get_transaction_index(&self, signature: Signature) -> DbResult { let response: String = self .client - .request("get_transaction_index", rpc_params![signature]) + .request("get_transaction_index", rpc_params![signature.to_string()]) .await?; info!("get_transaction_index response: {:?}", response); Ok(u64::from_str(response.as_str())?) From 65b213f36bb03c7b574354ad87e81adab1db0537 Mon Sep 17 00:00:00 2001 From: iguberman Date: Mon, 26 Aug 2024 23:14:56 -0500 Subject: [PATCH 292/318] Add missing env var TRACER_DB_TYPE --- .github/workflows/pipeline.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index d0ca7826f..c1adf0ec6 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -19,6 +19,7 @@ env: DOCKERHUB_ORG_NAME: ${{vars.DOCKERHUB_ORG_NAME}} RUN_LINK_REPO: "neonlabsorg/neon-proxy.py" BUILD_URL: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + TRACER_DB_TYPE: clickhouse concurrency: group: ${{ github.workflow }}-${{ github.ref }} From 04b58e0aa355df3c84f1bd96e275444acc9e7921 Mon Sep 17 00:00:00 2001 From: iguberman Date: Mon, 26 Aug 2024 23:33:00 -0500 Subject: [PATCH 293/318] Add missing env var TRACER_DB_TYPE --- .github/workflows/pipeline.yml | 1 - ci/docker-compose-ci.yml | 2 ++ ci/docker-compose-test.yml | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index c1adf0ec6..d0ca7826f 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -19,7 +19,6 @@ env: DOCKERHUB_ORG_NAME: ${{vars.DOCKERHUB_ORG_NAME}} RUN_LINK_REPO: "neonlabsorg/neon-proxy.py" BUILD_URL: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" - TRACER_DB_TYPE: clickhouse concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/ci/docker-compose-ci.yml b/ci/docker-compose-ci.yml index 07b6549f2..5c6355a0a 100644 --- a/ci/docker-compose-ci.yml +++ b/ci/docker-compose-ci.yml @@ -35,6 +35,7 @@ services: SOLANA_KEY_FOR_CONFIG: BMp6gEnveANdvSvspESJUrNczuHz1GF5UQKjVLCkAZih COMMITMENT: confirmed NEON_DB_CLICKHOUSE_URLS: "http://45.250.253.36:8123;http://45.250.253.38:8123" + TRACER_DB_TYPE: clickhouse image: ${EVM_LOADER_IMAGE} ports: - "8085" @@ -65,6 +66,7 @@ services: KEYPAIR: /opt/operator-keypairs/id.json FEEPAIR: /opt/operator-keypairs/id.json SOLANA_KEY_FOR_CONFIG: BMp6gEnveANdvSvspESJUrNczuHz1GF5UQKjVLCkAZih + image: ${EVM_LOADER_IMAGE} ports: - "3100" diff --git a/ci/docker-compose-test.yml b/ci/docker-compose-test.yml index 3f6cf6447..93aa80e52 100644 --- a/ci/docker-compose-test.yml +++ b/ci/docker-compose-test.yml @@ -38,6 +38,7 @@ services: SOLANA_KEY_FOR_CONFIG: BMp6gEnveANdvSvspESJUrNczuHz1GF5UQKjVLCkAZih COMMITMENT: confirmed NEON_DB_CLICKHOUSE_URLS: "http://45.250.253.36:8123;http://45.250.253.38:8123" + TRACER_DB_TYPE: clickhouse image: ${EVM_LOADER_IMAGE} ports: - "8085:8085" From ec1d5c031efd9fbbaec6cb9b186fb109e7a7f4f5 Mon Sep 17 00:00:00 2001 From: Kristina Nikolaeva <112946046+kristinaNikolaevaa@users.noreply.github.com> Date: Tue, 27 Aug 2024 11:25:05 +0200 Subject: [PATCH 294/318] added devnet test chains (#526) --- evm_loader/program/config/devnet.toml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/evm_loader/program/config/devnet.toml b/evm_loader/program/config/devnet.toml index 06761ba8b..656d3add3 100644 --- a/evm_loader/program/config/devnet.toml +++ b/evm_loader/program/config/devnet.toml @@ -408,3 +408,11 @@ token = "So11111111111111111111111111111111111111112" [chain.usdc] id = 245022928 token = "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU" + +[chain.usdt] +id = 245022929 +token = "2duuuuhNJHUYqcnZ7LKfeufeeTBgSJdftf2zM3cZV6ym" + +[chain.eth] +id = 245022930 +token = "EwJYd3UAFAgzodVeHprB2gMQ68r4ZEbbvpoVzCZ1dGq5" \ No newline at end of file From 0f4d167f516aabc223a843aaf42c2596e10be1b6 Mon Sep 17 00:00:00 2001 From: iguberman Date: Tue, 27 Aug 2024 11:34:00 -0500 Subject: [PATCH 295/318] Add missing env var TRACER_DB_TYPE --- ci/docker-compose-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/docker-compose-ci.yml b/ci/docker-compose-ci.yml index 5c6355a0a..1404d0992 100644 --- a/ci/docker-compose-ci.yml +++ b/ci/docker-compose-ci.yml @@ -58,6 +58,7 @@ services: NEON_CHAIN_ID: 111 COMMITMENT: confirmed NEON_DB_CLICKHOUSE_URLS: "http://45.250.253.36:8123;http://45.250.253.38:8123" + TRACER_DB_TYPE: clickhouse NEON_DB_INDEXER_HOST: 45.250.253.32 NEON_DB_INDEXER_PORT: 5432 NEON_DB_INDEXER_DATABASE: indexer From 1463385769556260e530ca6673cdb43396fdeb03 Mon Sep 17 00:00:00 2001 From: iguberman Date: Tue, 27 Aug 2024 13:01:57 -0500 Subject: [PATCH 296/318] Add missing env var TRACER_DB_TYPE --- ci/docker-compose-test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/docker-compose-test.yml b/ci/docker-compose-test.yml index 93aa80e52..925be1da6 100644 --- a/ci/docker-compose-test.yml +++ b/ci/docker-compose-test.yml @@ -62,6 +62,7 @@ services: NEON_CHAIN_ID: 111 COMMITMENT: confirmed NEON_DB_CLICKHOUSE_URLS: "http://45.250.253.36:8123;http://45.250.253.38:8123" + TRACER_DB_TYPE: clickhouse NEON_DB_INDEXER_HOST: 45.250.253.32 NEON_DB_INDEXER_PORT: 5432 NEON_DB_INDEXER_DATABASE: indexer From 4a76204cff64cb61e6c722bb938c8164a8c96a87 Mon Sep 17 00:00:00 2001 From: iguberman Date: Tue, 27 Aug 2024 17:06:14 -0500 Subject: [PATCH 297/318] Temporary set clickhouse to be default for TRACER_DB_TYPE (to pass CI tests) --- evm_loader/lib/src/config.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/evm_loader/lib/src/config.rs b/evm_loader/lib/src/config.rs index 5c4f9f5e9..af593fa10 100644 --- a/evm_loader/lib/src/config.rs +++ b/evm_loader/lib/src/config.rs @@ -103,7 +103,9 @@ pub fn load_db_config_from_environment() -> DbConfig { load_rocks_db_config_from_environment(), )), "clickhouse" => Some(DbConfig::ChDbConfig(load_ch_db_config_from_environment())), - _ => None, + // TODO, this env should be explicitely set but for now I create a default to pass CI tests + // as I am not sure where else to set it + _ => Some(DbConfig::ChDbConfig(load_ch_db_config_from_environment())), }) .expect("TRACER_DB_TYPE variable must be either 'clickhouse' or 'rocksdb'") } From c3bd80090ce1125a5b82f16f9f4b82287d4ae4e6 Mon Sep 17 00:00:00 2001 From: iguberman Date: Tue, 27 Aug 2024 19:28:57 -0500 Subject: [PATCH 298/318] Temporary set clickhouse to be default for TRACER_DB_TYPE (to pass CI tests) + fix clippy warning --- evm_loader/lib/src/config.rs | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/evm_loader/lib/src/config.rs b/evm_loader/lib/src/config.rs index af593fa10..58ba9c4c2 100644 --- a/evm_loader/lib/src/config.rs +++ b/evm_loader/lib/src/config.rs @@ -96,18 +96,15 @@ pub fn load_api_config_from_environment() -> APIOptions { #[must_use] pub fn load_db_config_from_environment() -> DbConfig { - env::var("TRACER_DB_TYPE") - .ok() - .and_then(|db_type| match db_type.to_lowercase().as_str() { - "rocksdb" => Some(DbConfig::RocksDbConfig( - load_rocks_db_config_from_environment(), - )), - "clickhouse" => Some(DbConfig::ChDbConfig(load_ch_db_config_from_environment())), - // TODO, this env should be explicitely set but for now I create a default to pass CI tests - // as I am not sure where else to set it - _ => Some(DbConfig::ChDbConfig(load_ch_db_config_from_environment())), - }) - .expect("TRACER_DB_TYPE variable must be either 'clickhouse' or 'rocksdb'") + match env::var("TRACER_DB_TYPE") + .unwrap_or_else(|_| "clickhouse".to_string()) + .to_lowercase() + .as_str() + { + "rocksdb" => DbConfig::RocksDbConfig(load_rocks_db_config_from_environment()), + "clickhouse" => DbConfig::ChDbConfig(load_ch_db_config_from_environment()), + _ => panic!("TRACER_DB_TYPE env var must be either 'clickhouse' or 'rocksdb'"), + } } pub fn load_ch_db_config_from_environment() -> ChDbConfig { From 7755184fb71e93ddb71853f238580c6732606394 Mon Sep 17 00:00:00 2001 From: iguberman Date: Tue, 27 Aug 2024 20:33:29 -0500 Subject: [PATCH 299/318] Temporary set clickhouse to be default for TRACER_DB_TYPE (to pass CI tests) --- evm_loader/lib/src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm_loader/lib/src/config.rs b/evm_loader/lib/src/config.rs index 58ba9c4c2..c5e3f2a9b 100644 --- a/evm_loader/lib/src/config.rs +++ b/evm_loader/lib/src/config.rs @@ -102,7 +102,7 @@ pub fn load_db_config_from_environment() -> DbConfig { .as_str() { "rocksdb" => DbConfig::RocksDbConfig(load_rocks_db_config_from_environment()), - "clickhouse" => DbConfig::ChDbConfig(load_ch_db_config_from_environment()), + "clickhouse" | "" => DbConfig::ChDbConfig(load_ch_db_config_from_environment()), _ => panic!("TRACER_DB_TYPE env var must be either 'clickhouse' or 'rocksdb'"), } } From 8c56fb804c407aba3e6abd331b62c3932f355e7b Mon Sep 17 00:00:00 2001 From: iguberman Date: Tue, 27 Aug 2024 21:18:12 -0500 Subject: [PATCH 300/318] Temporary set clickhouse to be default for TRACER_DB_TYPE (to pass CI tests) --- evm_loader/lib/src/config.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/evm_loader/lib/src/config.rs b/evm_loader/lib/src/config.rs index c5e3f2a9b..2c8591525 100644 --- a/evm_loader/lib/src/config.rs +++ b/evm_loader/lib/src/config.rs @@ -102,8 +102,7 @@ pub fn load_db_config_from_environment() -> DbConfig { .as_str() { "rocksdb" => DbConfig::RocksDbConfig(load_rocks_db_config_from_environment()), - "clickhouse" | "" => DbConfig::ChDbConfig(load_ch_db_config_from_environment()), - _ => panic!("TRACER_DB_TYPE env var must be either 'clickhouse' or 'rocksdb'"), + _ => DbConfig::ChDbConfig(load_ch_db_config_from_environment()), } } From 6f479dd49b4100a00d49e6a571ea5b030b53e8f0 Mon Sep 17 00:00:00 2001 From: iguberman Date: Tue, 27 Aug 2024 22:18:39 -0500 Subject: [PATCH 301/318] Temporary set clickhouse to be default for TRACER_DB_TYPE (to pass CI tests) --- evm_loader/lib/src/config.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/evm_loader/lib/src/config.rs b/evm_loader/lib/src/config.rs index 2c8591525..05f0277ae 100644 --- a/evm_loader/lib/src/config.rs +++ b/evm_loader/lib/src/config.rs @@ -1,6 +1,7 @@ use serde::{Deserialize, Serialize}; use solana_sdk::{commitment_config::CommitmentConfig, pubkey::Pubkey, signature::Keypair}; use std::{env, str::FromStr}; +use tracing::info; const DEFAULT_ROCKSDB_PORT: u16 = 9888; @@ -96,13 +97,17 @@ pub fn load_api_config_from_environment() -> APIOptions { #[must_use] pub fn load_db_config_from_environment() -> DbConfig { - match env::var("TRACER_DB_TYPE") + if env::var("TRACER_DB_TYPE") .unwrap_or_else(|_| "clickhouse".to_string()) .to_lowercase() .as_str() + == "rocksdb" { - "rocksdb" => DbConfig::RocksDbConfig(load_rocks_db_config_from_environment()), - _ => DbConfig::ChDbConfig(load_ch_db_config_from_environment()), + info!("Loading rocksdb config from env!"); + DbConfig::RocksDbConfig(load_rocks_db_config_from_environment()) + } else { + info!("Loading clickhouse config from env!"); + DbConfig::ChDbConfig(load_ch_db_config_from_environment()) } } From 66a73d367df17a323bcaa41c9a2b7318636b9eec Mon Sep 17 00:00:00 2001 From: iguberman Date: Tue, 27 Aug 2024 23:17:44 -0500 Subject: [PATCH 302/318] Undo default to clickhouse and keep TRACER_DB_TYPE env var manadatory --- evm_loader/lib/src/config.rs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/evm_loader/lib/src/config.rs b/evm_loader/lib/src/config.rs index 05f0277ae..033ab4a57 100644 --- a/evm_loader/lib/src/config.rs +++ b/evm_loader/lib/src/config.rs @@ -97,18 +97,16 @@ pub fn load_api_config_from_environment() -> APIOptions { #[must_use] pub fn load_db_config_from_environment() -> DbConfig { - if env::var("TRACER_DB_TYPE") - .unwrap_or_else(|_| "clickhouse".to_string()) - .to_lowercase() - .as_str() - == "rocksdb" - { - info!("Loading rocksdb config from env!"); - DbConfig::RocksDbConfig(load_rocks_db_config_from_environment()) - } else { - info!("Loading clickhouse config from env!"); - DbConfig::ChDbConfig(load_ch_db_config_from_environment()) - } + env::var("TRACER_DB_TYPE") + .ok() + .and_then(|db_type| match db_type.to_lowercase().as_str() { + "rocksdb" => Some(DbConfig::RocksDbConfig( + load_rocks_db_config_from_environment(), + )), + "clickhouse" => Some(DbConfig::ChDbConfig(load_ch_db_config_from_environment())), + _ => None, + }) + .expect("TRACER_DB_TYPE variable must be either 'clickhouse' or 'rocksdb'") } pub fn load_ch_db_config_from_environment() -> ChDbConfig { From 956b401c33f82afb5dc1c413440c4077e572a885 Mon Sep 17 00:00:00 2001 From: iguberman Date: Tue, 27 Aug 2024 23:23:49 -0500 Subject: [PATCH 303/318] Undo default to clickhouse and keep TRACER_DB_TYPE env var manadatory --- evm_loader/lib/src/config.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/evm_loader/lib/src/config.rs b/evm_loader/lib/src/config.rs index 033ab4a57..5c4f9f5e9 100644 --- a/evm_loader/lib/src/config.rs +++ b/evm_loader/lib/src/config.rs @@ -1,7 +1,6 @@ use serde::{Deserialize, Serialize}; use solana_sdk::{commitment_config::CommitmentConfig, pubkey::Pubkey, signature::Keypair}; use std::{env, str::FromStr}; -use tracing::info; const DEFAULT_ROCKSDB_PORT: u16 = 9888; From daae9c967bfdbc046f0321165fbfad34cf1256df Mon Sep 17 00:00:00 2001 From: ancientmage Date: Wed, 28 Aug 2024 11:08:09 +0200 Subject: [PATCH 304/318] =?UTF-8?q?NDEV-3096.=20Get=20Account=20State=20af?= =?UTF-8?q?ter=20emulation=20for=20debug=5FtraceTransacti=E2=80=A6=20(#520?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * NDEV-3096. Get Account State after emulation for debug_traceTransaction rpc * NDEV-3096. Add db request: get_accounts_in_transaction for tracer debug_traceTransaction --- evm_loader/lib/src/account_data.rs | 8 +++- evm_loader/lib/src/commands/emulate.rs | 43 +++++++++++++++++--- evm_loader/lib/src/types/mod.rs | 13 +++++- evm_loader/lib/src/types/tracer_ch_common.rs | 40 +++++++++++++++--- evm_loader/lib/src/types/tracer_ch_db.rs | 39 ++++++++++++++++-- evm_loader/program/src/account/mod.rs | 2 +- 6 files changed, 127 insertions(+), 18 deletions(-) diff --git a/evm_loader/lib/src/account_data.rs b/evm_loader/lib/src/account_data.rs index 9c1535d62..b78ac8574 100644 --- a/evm_loader/lib/src/account_data.rs +++ b/evm_loader/lib/src/account_data.rs @@ -11,13 +11,19 @@ use solana_sdk::{ pub use evm_loader::account_storage::{AccountStorage, SyncedAccountStorage}; use evm_loader::solana_program::debug_account_data::debug_account_data; +use serde::{Deserialize, Serialize}; +use serde_with::hex::Hex; +use serde_with::serde_as; -#[derive(Clone)] +#[allow(clippy::unsafe_derive_deserialize)] +#[serde_as] +#[derive(Clone, Serialize, Deserialize)] #[repr(C)] pub struct AccountData { original_length: u32, pub pubkey: Pubkey, pub lamports: u64, + #[serde_as(as = "Hex")] data: Vec, pub owner: Pubkey, pub executable: bool, diff --git a/evm_loader/lib/src/commands/emulate.rs b/evm_loader/lib/src/commands/emulate.rs index d1f16a334..bec08eb1c 100644 --- a/evm_loader/lib/src/commands/emulate.rs +++ b/evm_loader/lib/src/commands/emulate.rs @@ -1,7 +1,8 @@ +use crate::account_data::AccountData; use crate::commands::get_config::BuildConfigSimulator; use crate::rpc::Rpc; use crate::tracing::tracers::Tracer; -use crate::types::{EmulateRequest, TxParams}; +use crate::types::{AccountInfoLevel, EmulateRequest, TxParams}; use crate::{ account_storage::{EmulatorAccountStorage, SyncedAccountStorage}, errors::NeonError, @@ -30,6 +31,7 @@ pub struct SolanaAccount { pub is_writable: bool, pub is_legacy: bool, } + #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] pub struct EmulateResponse { @@ -44,6 +46,7 @@ pub struct EmulateResponse { pub iterations: u64, pub solana_accounts: Vec, pub logs: Vec, + pub accounts_data: Option>, } impl EmulateResponse { @@ -64,6 +67,7 @@ impl EmulateResponse { iterations: 0, solana_accounts: vec![], logs: backend.backend().logs(), + accounts_data: None, } } } @@ -104,7 +108,8 @@ pub async fn execute( let step_limit = emulate_request.step_limit.unwrap_or(100_000); - let result = emulate_trx(emulate_request.tx.clone(), &mut storage, step_limit, tracer).await?; + let mut result = + emulate_trx(emulate_request.tx.clone(), &mut storage, step_limit, tracer).await?; if storage.is_timestamp_used() { let mut storage2 = @@ -134,13 +139,14 @@ pub async fn execute( } }); - let emul_response = EmulateResponse { + result.0 = EmulateResponse { // We get the result from the first response (as it is executed on the current time) result: response.result.clone(), exit_status: response.exit_status.to_string(), external_solana_call: response.external_solana_call, reverts_before_solana_calls: response.reverts_before_solana_calls, reverts_after_solana_calls: response.reverts_after_solana_calls, + accounts_data: None, // ...and consumed resources from the both responses (because the real execution can occur in the future) steps_executed: response.steps_executed.max(response2.steps_executed), @@ -149,11 +155,17 @@ pub async fn execute( solana_accounts: combined_solana_accounts, logs: response.logs.clone(), }; - - return Ok((emul_response, result.1)); } } + if let Some(level) = emulate_request.provide_account_info { + result.0.accounts_data = Some(provide_account_data( + &storage, + &result.0.solana_accounts, + &level, + )); + } + Ok(result) } @@ -234,7 +246,28 @@ async fn emulate_trx( result: exit_status.into_result().unwrap_or_default(), iterations, logs, + accounts_data: None, }, tracer.map(|tracer| tracer.into_traces(used_gas)), )) } + +fn provide_account_data( + storage: &EmulatorAccountStorage, + solana_accounts: &Vec, + level: &AccountInfoLevel, +) -> Vec { + let mut accounts_data = Vec::::new(); + + for account in solana_accounts { + if !account.is_writable && AccountInfoLevel::Changed == *level { + continue; + } + + if let Some(account_data) = storage.accounts_get(&account.pubkey) { + accounts_data.push(account_data.clone()); + } + } + + accounts_data +} diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index 00103d72d..388ae61af 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -158,6 +158,13 @@ impl From<&SerializedAccount> for Account { } } +#[serde_as] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub enum AccountInfoLevel { + Changed, + All, +} + #[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] pub struct EmulateRequest { @@ -169,6 +176,7 @@ pub struct EmulateRequest { pub accounts: Vec, #[serde_as(as = "Option>")] pub solana_overrides: Option>>, + pub provide_account_info: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -381,8 +389,9 @@ mod tests { "rent_epoch": 0, "data": "0102030405" } - } - } + }, + "provide_account_info": null + } "#; let request: super::EmulateRequest = serde_json::from_str(txt).unwrap(); diff --git a/evm_loader/lib/src/types/tracer_ch_common.rs b/evm_loader/lib/src/types/tracer_ch_common.rs index 8e50def58..a38da0712 100644 --- a/evm_loader/lib/src/types/tracer_ch_common.rs +++ b/evm_loader/lib/src/types/tracer_ch_common.rs @@ -8,6 +8,8 @@ use std::collections::BTreeMap; use std::time::Instant; use thiserror::Error; +use crate::account_data::AccountData; + pub const ROOT_BLOCK_DELAY: u8 = 100; #[derive(Error, Debug)] @@ -65,6 +67,7 @@ pub struct RevisionRow { #[derive(Row, serde::Deserialize, Clone)] pub struct AccountRow { + pub pubkey: Vec, pub owner: Vec, pub lamports: u64, pub executable: bool, @@ -78,6 +81,7 @@ impl fmt::Debug for AccountRow { let mut debug_struct = f.debug_struct("AccountRow"); debug_struct + .field("pubkey", &bs58::encode(&self.pubkey).into_string()) .field("owner", &bs58::encode(&self.owner).into_string()) .field("lamports", &self.lamports) .field("executable", &self.executable) @@ -101,16 +105,20 @@ impl fmt::Debug for AccountRow { } } +fn pubkey_from(src: Vec) -> Result { + Pubkey::try_from(src).map_err(|src| { + format!( + "Incorrect slice length ({}) while converting owner from: {src:?}", + src.len(), + ) + }) +} + impl TryInto for AccountRow { type Error = String; fn try_into(self) -> Result { - let owner = Pubkey::try_from(self.owner).map_err(|src| { - format!( - "Incorrect slice length ({}) while converting owner from: {src:?}", - src.len(), - ) - })?; + let owner = pubkey_from(self.owner)?; Ok(Account { lamports: self.lamports, @@ -122,6 +130,26 @@ impl TryInto for AccountRow { } } +impl TryInto for AccountRow { + type Error = String; + + fn try_into(self) -> Result { + let owner = pubkey_from(self.owner)?; + let pubkey = pubkey_from(self.pubkey)?; + + Ok(AccountData::new_from_account( + pubkey, + &Account { + lamports: self.lamports, + data: self.data, + owner, + rent_epoch: self.rent_epoch, + executable: self.executable, + }, + )) + } +} + pub enum EthSyncStatus { Syncing(EthSyncing), Synced, diff --git a/evm_loader/lib/src/types/tracer_ch_db.rs b/evm_loader/lib/src/types/tracer_ch_db.rs index 673d3f9c1..3eeb1351f 100644 --- a/evm_loader/lib/src/types/tracer_ch_db.rs +++ b/evm_loader/lib/src/types/tracer_ch_db.rs @@ -5,6 +5,7 @@ use crate::{ use super::tracer_ch_common::{ChResult, EthSyncStatus, EthSyncing, RevisionMap, SlotParentRooted}; +use crate::account_data::AccountData; use crate::types::ChDbConfig; use clickhouse::Client; use log::{debug, error, info}; @@ -265,7 +266,7 @@ impl ClickHouseDb { None } else { let query = r" - SELECT owner, lamports, executable, rent_epoch, data, txn_signature + SELECT pubkey, owner, lamports, executable, rent_epoch, data, txn_signature FROM events.update_account_distributed WHERE pubkey = ? AND slot IN ? @@ -326,7 +327,7 @@ impl ClickHouseDb { ); let query = r" - SELECT owner, lamports, executable, rent_epoch, data, txn_signature + SELECT pubkey, owner, lamports, executable, rent_epoch, data, txn_signature FROM events.update_account_distributed WHERE pubkey = ? AND slot = ? @@ -363,6 +364,38 @@ impl ClickHouseDb { Ok(account) } + pub async fn get_accounts_in_transaction( + &self, + sol_sig: &[u8], + slot: u64, + ) -> ChResult> { + info!("get_accounts_in_transaction {{signature: {sol_sig:?} }}"); + + let query = r" + SELECT DISTINCT ON (pubkey) + pubkey, owner, lamports, executable, rent_epoch, data, txn_signature + FROM events.update_account_distributed + WHERE txn_signature = ? + AND slot = ? + ORDER BY write_version DESC + "; + + let rows = self + .client + .query(query) + .bind(sol_sig) + .bind(slot) + .fetch_all::() + .await?; + + rows.into_iter() + .map(|row: AccountRow| { + row.try_into() + .map_err(|err| ChError::Db(clickhouse::error::Error::Custom(err))) + }) + .collect() + } + async fn get_older_account_row_at( &self, pubkey: &str, @@ -478,7 +511,7 @@ impl ClickHouseDb { // Try to find account changes within the given slot. let query = r" SELECT DISTINCT ON (pubkey, txn_signature, write_version) - owner, lamports, executable, rent_epoch, data, txn_signature + pubkey, owner, lamports, executable, rent_epoch, data, txn_signature FROM events.update_account_distributed WHERE slot = ? AND pubkey = ? ORDER BY write_version DESC diff --git a/evm_loader/program/src/account/mod.rs b/evm_loader/program/src/account/mod.rs index 92a429df8..47b75114e 100644 --- a/evm_loader/program/src/account/mod.rs +++ b/evm_loader/program/src/account/mod.rs @@ -8,7 +8,7 @@ pub use crate::{account_storage::FAKE_OPERATOR, config::ACCOUNT_SEED_VERSION}; pub use ether_balance::{BalanceAccount, Header as BalanceHeader}; pub use ether_contract::{AllocateResult, ContractAccount, Header as ContractHeader}; -pub use ether_storage::{Header as StorageCellHeader, StorageCell, StorageCellAddress}; +pub use ether_storage::{Cell, Header as StorageCellHeader, StorageCell, StorageCellAddress}; pub use holder::{Header as HolderHeader, Holder}; pub use incinerator::Incinerator; pub use operator::Operator; From b79ff9ed1753722c0d2a2d30c85dfcc7d5299595 Mon Sep 17 00:00:00 2001 From: Evgeny Zdanovich Date: Wed, 28 Aug 2024 12:03:58 +0200 Subject: [PATCH 305/318] Deallocate EVM and ExecutorState in case of reset before the allocation of new EVM and ExecutorState objects. (#527) --- evm_loader/program/src/account/state.rs | 59 +++++++++++++------ .../src/instruction/transaction_step.rs | 13 +++- 2 files changed, 51 insertions(+), 21 deletions(-) diff --git a/evm_loader/program/src/account/state.rs b/evm_loader/program/src/account/state.rs index 71d0ebd5b..440e55973 100644 --- a/evm_loader/program/src/account/state.rs +++ b/evm_loader/program/src/account/state.rs @@ -106,7 +106,7 @@ struct Data { #[repr(C, packed)] pub struct Header { pub executor_state_offset: usize, - pub evm_machine_offset: usize, + pub evm_offset: usize, pub data_offset: usize, } impl AccountHeader for Header { @@ -207,7 +207,7 @@ impl<'a> StateAccount<'a> { // Set header let mut header = super::header_mut::
(&info); header.executor_state_offset = 0; - header.evm_machine_offset = 0; + header.evm_offset = 0; header.data_offset = data_offset; } @@ -399,18 +399,50 @@ impl<'a> StateAccount<'a> { // Implementation of functional to save/restore persistent state of iterative transactions. impl<'a> StateAccount<'a> { - pub fn alloc_executor_state(&self, data: Boxx) -> Result<()> { + pub fn alloc_executor_state(&self, data: Boxx) { let offset = self.leak_and_offset(data); let mut header = super::header_mut::
(&self.account); header.executor_state_offset = offset; - Ok(()) } - pub fn alloc_evm(&self, evm: Boxx>) -> Result<()> { + pub fn dealloc_executor_state(&self) { + unsafe { ManuallyDrop::drop(&mut self.read_executor_state()) }; + let mut header = super::header_mut::
(&self.account); + header.executor_state_offset = 0; + } + + #[must_use] + pub fn read_executor_state(&self) -> ManuallyDrop> { + let header = super::header::
(&self.account); + self.map_obj(header.executor_state_offset) + } + + #[must_use] + pub fn is_executor_state_alloced(&self) -> bool { + super::header_mut::
(&self.account).executor_state_offset != 0 + } + + pub fn alloc_evm(&self, evm: Boxx>) { let offset = self.leak_and_offset(evm); let mut header = super::header_mut::
(&self.account); - header.evm_machine_offset = offset; - Ok(()) + header.evm_offset = offset; + } + + pub fn dealloc_evm(&self) { + unsafe { ManuallyDrop::drop(&mut self.read_evm::()) }; + let mut header = super::header_mut::
(&self.account); + header.evm_offset = 0; + } + + #[must_use] + pub fn read_evm(&self) -> ManuallyDrop>> { + let header = super::header::
(&self.account); + self.map_obj(header.evm_offset) + } + + #[must_use] + pub fn is_evm_alloced(&self) -> bool { + super::header_mut::
(&self.account).evm_offset != 0 } /// Leak the Box's underlying data and returns offset from the account data start. @@ -429,19 +461,8 @@ impl<'a> StateAccount<'a> { } } - #[must_use] - pub fn read_evm(&self) -> ManuallyDrop>> { - let header = super::header::
(&self.account); - self.map_obj(header.evm_machine_offset) - } - - #[must_use] - pub fn read_executor_state(&self) -> ManuallyDrop> { - let header = super::header::
(&self.account); - self.map_obj(header.executor_state_offset) - } - fn map_obj(&self, offset: usize) -> ManuallyDrop> { + assert!(offset > 0); let data = self.account.data.borrow().as_ptr(); unsafe { let ptr = data.add(offset).cast_mut(); diff --git a/evm_loader/program/src/instruction/transaction_step.rs b/evm_loader/program/src/instruction/transaction_step.rs index bdaf3d5f5..d101dc4de 100644 --- a/evm_loader/program/src/instruction/transaction_step.rs +++ b/evm_loader/program/src/instruction/transaction_step.rs @@ -114,6 +114,15 @@ fn allocate_or_reinit_state( ) -> Result<()> { if is_allocate { storage.reset_steps_executed(); + + // Dealloc objects that were potentially alloced in previous iterations before the reset. + if storage.is_evm_alloced() { + storage.dealloc_evm::(); + } + if storage.is_executor_state_alloced() { + storage.dealloc_executor_state(); + } + let mut state_data = boxx(ExecutorStateData::new(account_storage)); let mut evm_backend = ExecutorState::new(account_storage, &mut state_data); let evm = boxx(Evm::new( @@ -122,8 +131,8 @@ fn allocate_or_reinit_state( &mut evm_backend, None, )?); - storage.alloc_evm(evm)?; - storage.alloc_executor_state(state_data)?; + storage.alloc_evm(evm); + storage.alloc_executor_state(state_data); } else { let mut state_data = storage.read_executor_state(); let mut evm = storage.read_evm(); From bfce5977d48e418ba2cd2bebb070c2ac572e7766 Mon Sep 17 00:00:00 2001 From: Kristina Nikolaeva <112946046+kristinaNikolaevaa@users.noreply.github.com> Date: Thu, 29 Aug 2024 09:23:16 +0200 Subject: [PATCH 306/318] ci refactoring (#528) --- .github/workflows/deploy.py | 209 +++++++++++++++---------- .github/workflows/github_api_client.py | 8 +- .github/workflows/pipeline.yml | 97 +++++------- 3 files changed, 175 insertions(+), 139 deletions(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index 75d30904c..20545bc8d 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -7,6 +7,7 @@ import subprocess import requests import json +import typing as tp from urllib.parse import urlparse from github_api_client import GithubClient @@ -36,6 +37,8 @@ SOLANA_BPF_VERSION = 'v1.18.18' VERSION_BRANCH_TEMPLATE = r"[vt]{1}\d{1,2}\.\d{1,2}\.x.*" +RELEASE_TAG_TEMPLATE = r"[vt]{1}\d{1,2}\.\d{1,2}\.\d{1,2}" + docker_client = docker.APIClient() NEON_TEST_IMAGE_NAME = f"{DOCKERHUB_ORG_NAME.lower()}/neon_tests" @@ -48,51 +51,105 @@ def cli(): pass +def ref_to_image_tag(ref): + return ref.split('/')[-1] + + +def set_github_env(envs: tp.Dict, upper=True) -> None: + """Set environment for github action""" + path = os.getenv("GITHUB_ENV", str()) + if os.path.exists(path): + print(f"Set environment variables: {envs}") + with open(path, "a") as env_file: + for key, value in envs.items(): + env_file.write(f"\n{key.upper() if upper else key}={str(value)}") + + +def is_image_exist(image, tag): + response = requests.get( + url=f"https://registry.hub.docker.com/v2/repositories/{DOCKERHUB_ORG_NAME}/{image}/tags/{tag}") + return response.status_code == 200 + + +@cli.command(name="specify_image_tags") +@click.option('--git_ref') +@click.option('--git_head_ref') +@click.option('--git_base_ref') +def specify_image_tags(git_ref, + git_head_ref, + git_base_ref): + # evm_tag + if "refs/pull" in git_ref: + evm_tag = ref_to_image_tag(git_head_ref) + elif git_ref == "refs/heads/develop": + evm_tag = "latest" + else: + evm_tag = ref_to_image_tag(git_ref) + + # evm_pr_version_branch + evm_pr_version_branch = "" + if git_base_ref: + if re.match(VERSION_BRANCH_TEMPLATE, ref_to_image_tag(git_base_ref)) is not None: + evm_pr_version_branch = ref_to_image_tag(git_base_ref) + + # is_evm_release + if "refs/tags/" in git_ref: + is_evm_release = True + else: + is_evm_release = False + + # test_image_tag + if evm_tag and is_image_exist("neon-tests", evm_tag): + neon_test_tag = evm_tag + elif is_evm_release: + neon_test_tag = re.sub(r'\.[0-9]*$', '.x', evm_tag) + if not is_image_exist("neon-tests", neon_test_tag): + raise RuntimeError(f"neon-tests image with {neon_test_tag} tag isn't found") + elif evm_pr_version_branch and is_image_exist("neon-tests", evm_pr_version_branch): + neon_test_tag = evm_pr_version_branch + else: + neon_test_tag = "latest" + + env = dict(evm_tag=evm_tag, + evm_pr_version_branch=evm_pr_version_branch, + is_evm_release=is_evm_release, + neon_test_tag=neon_test_tag) + set_github_env(env) + + @cli.command(name="build_docker_image") -@click.option('--github_sha') -def build_docker_image(github_sha): +@click.option('--evm_sha_tag') +def build_docker_image(evm_sha_tag): solana_image = f'solanalabs/solana:{SOLANA_NODE_VERSION}' docker_client.pull(solana_image) - buildargs = {"REVISION": github_sha, + buildargs = {"REVISION": evm_sha_tag, "SOLANA_IMAGE": solana_image, "SOLANA_BPF_VERSION": SOLANA_BPF_VERSION} - tag = f"{IMAGE_NAME}:{github_sha}" + tag = f"{IMAGE_NAME}:{evm_sha_tag}" click.echo("start build") output = docker_client.build(tag=tag, buildargs=buildargs, path="./", decode=True) process_output(output) @cli.command(name="publish_image") -@click.option('--github_sha') -@click.option('--github_ref_name') -@click.option('--head_ref') -def publish_image(github_sha, github_ref_name, head_ref): - push_image_with_tag(github_sha, github_sha) - branch_name_tag = "" - if head_ref: - branch_name_tag = head_ref.split('/')[-1] - elif re.match(VERSION_BRANCH_TEMPLATE, github_ref_name): - branch_name_tag = github_ref_name - if branch_name_tag: - push_image_with_tag(github_sha, branch_name_tag) +@click.option('--evm_sha_tag') +@click.option('--evm_tag') +def publish_image(evm_sha_tag, evm_tag): + push_image_with_tag(evm_sha_tag, evm_sha_tag) + # push latest and version tags only on the finalizing step + if evm_tag != "latest" and re.match(RELEASE_TAG_TEMPLATE, evm_tag) is None: + push_image_with_tag(evm_sha_tag, evm_tag) @cli.command(name="finalize_image") -@click.option('--github_ref') -@click.option('--github_sha') -def finalize_image(github_ref, github_sha): - tag = None - if 'refs/tags/' in github_ref: - tag = github_ref.replace("refs/tags/", "") - elif github_ref == 'refs/heads/develop': - tag = 'latest' - if tag: - out = docker_client.pull(f"{IMAGE_NAME}:{github_sha}", decode=True, stream=True) - process_output(out) - push_image_with_tag(github_sha, tag) +@click.option('--evm_sha_tag') +@click.option('--evm_tag') +def finalize_image(evm_sha_tag, evm_tag): + if re.match(RELEASE_TAG_TEMPLATE, evm_tag) is not None or evm_tag == "latest": + push_image_with_tag(evm_sha_tag, evm_tag) else: - click.echo("The image is not published") + click.echo(f"Nothing to finalize, the tag {evm_tag} is not version tag or latest") def push_image_with_tag(sha, tag): @@ -108,24 +165,14 @@ def run_subprocess(command): @cli.command(name="run_tests") -@click.option('--github_sha') -@click.option('--neon_test_branch') -@click.option('--base_ref_branch') +@click.option('--evm_sha_tag') +@click.option('--neon_test_tag') @click.option('--run_number') @click.option('--run_attempt') -def run_tests(github_sha, neon_test_branch, base_ref_branch, run_number, run_attempt): - os.environ["EVM_LOADER_IMAGE"] = f"{IMAGE_NAME}:{github_sha}" - - if GithubClient.is_branch_exist(NEON_TESTS_ENDPOINT, neon_test_branch) \ - and neon_test_branch not in ('master', 'develop'): - neon_test_image_tag = neon_test_branch - elif re.match(VERSION_BRANCH_TEMPLATE, base_ref_branch): # PR to version branch - neon_test_image_tag = base_ref_branch - else: - neon_test_image_tag = 'latest' - os.environ["NEON_TESTS_IMAGE"] = f"{NEON_TEST_IMAGE_NAME}:{neon_test_image_tag}" - click.echo(f"NEON_TESTS_IMAGE: {os.environ['NEON_TESTS_IMAGE']}") - project_name = f"neon-evm-{github_sha}-{run_number}-{run_attempt}" +def run_tests(evm_sha_tag, neon_test_tag, run_number, run_attempt): + os.environ["EVM_LOADER_IMAGE"] = f"{IMAGE_NAME}:{evm_sha_tag}" + os.environ["NEON_TESTS_IMAGE"] = f"{NEON_TEST_IMAGE_NAME}:{neon_test_tag}" + project_name = f"neon-evm-{evm_sha_tag}-{run_number}-{run_attempt}" stop_containers(project_name) run_subprocess(f"docker-compose -p {project_name} -f ./ci/docker-compose-ci.yml pull") @@ -134,7 +181,7 @@ def run_tests(github_sha, neon_test_branch, base_ref_branch, run_number, run_att click.echo("Start tests") exec_id = docker_client.exec_create( - container=test_container_name, cmd="python3 clickfile.py run evm --numprocesses 6") + container=test_container_name, cmd="python3 clickfile.py run evm --numprocesses 8 --network docker_net") logs = docker_client.exec_start(exec_id['Id'], stream=True) tests_are_failed = False @@ -173,37 +220,35 @@ def stop_containers(project_name): @cli.command(name="trigger_proxy_action") -@click.option('--head_ref_branch') -@click.option('--base_ref_branch') -@click.option('--github_ref') -@click.option('--github_sha') +@click.option('--evm_pr_version_branch') +@click.option('--is_evm_release') +@click.option('--evm_sha_tag') +@click.option('--evm_tag') @click.option('--token') @click.option('--labels') @click.option('--pr_url') @click.option('--pr_number') -def trigger_proxy_action(head_ref_branch, base_ref_branch, github_ref, github_sha, token, labels, +def trigger_proxy_action(evm_pr_version_branch, is_evm_release, evm_sha_tag, evm_tag, token, labels, pr_url, pr_number): - is_develop_branch = github_ref in ['refs/heads/develop', 'refs/heads/master'] - is_tag_creating = 'refs/tags/' in github_ref - is_version_branch = re.match(VERSION_BRANCH_TEMPLATE, github_ref.replace("refs/heads/", "")) is not None + is_version_branch = re.match(VERSION_BRANCH_TEMPLATE, evm_tag) is not None is_FTS_labeled = 'fullTestSuit' in labels - if is_develop_branch or is_tag_creating or is_version_branch or is_FTS_labeled: + if evm_tag == "latest" or is_evm_release == 'True' or is_version_branch or is_FTS_labeled: full_test_suite = True else: full_test_suite = False github = GithubClient(token) - if GithubClient.is_branch_exist(PROXY_ENDPOINT, head_ref_branch): - proxy_branch = head_ref_branch - elif re.match(VERSION_BRANCH_TEMPLATE, base_ref_branch): - proxy_branch = base_ref_branch - elif is_tag_creating: - neon_evm_tag = github_ref.replace("refs/tags/", "") - proxy_branch = re.sub(r'\.\d+$', '.x', neon_evm_tag) + # get proxy branch by evm_tag + if GithubClient.is_branch_exist(PROXY_ENDPOINT, evm_tag): + proxy_branch = evm_tag + elif evm_pr_version_branch: + proxy_branch = evm_pr_version_branch + elif is_evm_release == 'True': + proxy_branch = re.sub(r'\.\d+$', '.x', evm_tag) elif is_version_branch: - proxy_branch = github_ref.replace("refs/heads/", "") + proxy_branch = evm_tag else: proxy_branch = 'develop' click.echo(f"Proxy branch: {proxy_branch}") @@ -212,8 +257,7 @@ def trigger_proxy_action(head_ref_branch, base_ref_branch, github_ref, github_sh runs_before = github.get_proxy_runs_list(proxy_branch) runs_count_before = github.get_proxy_runs_count(proxy_branch) - neon_evm_branch = head_ref_branch if head_ref_branch else github_ref - github.run_proxy_dispatches(proxy_branch, neon_evm_branch, github_sha, full_test_suite, initial_pr) + github.run_proxy_dispatches(proxy_branch, evm_tag, evm_sha_tag, evm_pr_version_branch, full_test_suite, initial_pr) wait_condition(lambda: github.get_proxy_runs_count(proxy_branch) > runs_count_before) runs_after = github.get_proxy_runs_list(proxy_branch) @@ -243,20 +287,27 @@ def wait_condition(func_cond, timeout_sec=60, delay=0.5): @cli.command(name="send_notification", help="Send notification to slack") -@click.option("-u", "--url", help="slack app endpoint url.") -@click.option("-b", "--build_url", help="github action test build url.") -def send_notification(url, build_url): - tpl = ERR_MSG_TPL.copy() - - parsed_build_url = urlparse(build_url).path.split("/") - build_id = parsed_build_url[-1] - repo_name = f"{parsed_build_url[1]}/{parsed_build_url[2]}" - - tpl["blocks"][0]["text"]["text"] = ( - f"*Build <{build_url}|`{build_id}`> of repository `{repo_name}` is failed.*" - f"\n<{build_url}|View build details>" - ) - requests.post(url=url, data=json.dumps(tpl)) +@click.option("--evm_tag", help="slack app endpoint url.") +@click.option("--url", help="slack app endpoint url.") +@click.option("--build_url", help="github action test build url.") +def send_notification(evm_tag, url, build_url): + + if re.match(RELEASE_TAG_TEMPLATE, evm_tag) is not None \ + or re.match(VERSION_BRANCH_TEMPLATE, evm_tag) is not None \ + or evm_tag == "latest": + tpl = ERR_MSG_TPL.copy() + + parsed_build_url = urlparse(build_url).path.split("/") + build_id = parsed_build_url[-1] + repo_name = f"{parsed_build_url[1]}/{parsed_build_url[2]}" + + tpl["blocks"][0]["text"]["text"] = ( + f"*Build <{build_url}|`{build_id}`> of repository `{repo_name}` is failed.*" + f"\n<{build_url}|View build details>" + ) + requests.post(url=url, data=json.dumps(tpl)) + else: + click.echo(f"Notification is not sent, the tag {evm_tag} is not version tag or latest") def process_output(output): diff --git a/.github/workflows/github_api_client.py b/.github/workflows/github_api_client.py index ec91ccd42..3787847ec 100644 --- a/.github/workflows/github_api_client.py +++ b/.github/workflows/github_api_client.py @@ -23,11 +23,13 @@ def get_proxy_runs_count(self, proxy_branch): f"{self.proxy_endpoint}/actions/workflows/pipeline.yml/runs?branch={proxy_branch}", headers=self.headers) return int(response.json()["total_count"]) - def run_proxy_dispatches(self, proxy_branch, neon_evm_branch, github_sha, full_test_suite, initial_pr): + def run_proxy_dispatches(self, proxy_branch, evm_tag, evm_sha_tag, evm_pr_version_branch, full_test_suite, + initial_pr): data = {"ref": proxy_branch, "inputs": {"full_test_suite": f"{full_test_suite}".lower(), - "neon_evm_commit": github_sha, - "neon_evm_branch": neon_evm_branch, + "evm_sha_tag": evm_sha_tag, + "evm_tag": evm_tag, + "evm_pr_version_branch": evm_pr_version_branch, "initial_pr": initial_pr} } response = requests.post( diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index d0ca7826f..61d426606 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -24,59 +24,54 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: - build-neon-evm: + build-image: runs-on: neon-evm-1 + outputs: + evm_tag: ${{ steps.tags.outputs.evm_tag }} + evm_sha_tag: ${{ steps.tags.outputs.evm_sha_tag }} + evm_pr_version_branch: ${{ steps.tags.outputs.evm_pr_version_branch }} + is_evm_release: ${{ steps.tags.outputs.is_evm_release }} + neon_test_tag: ${{ steps.tags.outputs.neon_test_tag }} steps: - uses: actions/checkout@v4 with: fetch-depth: 0 + - name: Specify image tags + run: | + python3 ./.github/workflows/deploy.py specify_image_tags \ + --git_ref=${{ github.ref }} \ + --git_head_ref=${{ github.head_ref }} \ + --git_base_ref=${{ github.base_ref }} + - name: Set outputs + id: tags + run: | + echo "evm_tag=${{ env.EVM_TAG }}" >> "$GITHUB_OUTPUT" + echo "evm_sha_tag=${{ github.sha }}" >> "$GITHUB_OUTPUT" + echo "evm_pr_version_branch=${{ env.PROXY_PR_VERSION_BRANCH }}" >> "$GITHUB_OUTPUT" + echo "is_evm_release=${{ env.IS_EVM_RELEASE }}" >> "$GITHUB_OUTPUT" + echo "neon_test_tag=${{ env.NEON_TEST_TAG }}" >> "$GITHUB_OUTPUT" - name: build docker image run: | python3 ./.github/workflows/deploy.py build_docker_image \ - --github_sha=${GITHUB_SHA} + --evm_sha_tag=${{ steps.tags.outputs.evm_sha_tag }} - name: publish image run: | python3 ./.github/workflows/deploy.py publish_image \ - --github_sha=${GITHUB_SHA} \ - --head_ref=${{ github.head_ref }} \ - --github_ref_name=${{github.ref_name}} - run-neon-evm-tests: + --evm_sha_tag=${{ steps.tags.outputs.evm_sha_tag }} \ + --evm_tag=${{ steps.tags.outputs.evm_tag }} + run-evm-tests: runs-on: test-runner needs: - - build-neon-evm + - build-image steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Define base branch if the action is tag creation - id: tag_creation - if: startsWith(github.ref , 'refs/tags/') - run: | - base_branch=`echo ${{ github.ref_name }} | sed 's/\.[0-9]*$/\.x/'` - echo "base_branch=$base_branch" >> $GITHUB_OUTPUT - echo "base_branch=$base_branch" - - name: Define neon test branch - id: neon_test_branch - run: | - if [[ "${{ github.ref }}" =~ "refs/heads/"[vt][0-9]+\.[0-9]+\.x ]]; then # version branch - tag=${GITHUB_REF/refs\/heads\//} - - elif [[ "${{ steps.tag_creation.outputs.base_branch }}" != "" ]]; then # tag creation - tag=${{ steps.tag_creation.outputs.base_branch }} - - elif [[ "${{ github.head_ref }}" != "" ]]; then # pr to feature or version branch or develop - tag=${{ github.head_ref }} - else - tag='develop' - fi - echo "value=${tag}" - echo "value=${tag}" >> $GITHUB_OUTPUT - name: Run tests run: | python3 ./.github/workflows/deploy.py run_tests \ - --github_sha=${GITHUB_SHA} \ - --neon_test_branch=${{ steps.neon_test_branch.outputs.value }} \ - --base_ref_branch=${{ github.base_ref }} \ + --evm_sha_tag=${{ needs.build-image.outputs.evm_sha_tag }} \ + --neon_test_tag=${{ needs.build-image.outputs.neon_test_tag }} \ --run_number=${{ github.run_number }} \ --run_attempt=${{ github.run_attempt }} - name: Cancel the build if job failed @@ -85,7 +80,7 @@ jobs: trigger-proxy-tests: runs-on: trigger-runner needs: - - build-neon-evm + - build-image steps: - uses: actions/checkout@v4 with: @@ -93,10 +88,10 @@ jobs: - name: Trigger proxy build run: | python3 ./.github/workflows/deploy.py trigger_proxy_action \ - --github_sha=${GITHUB_SHA} \ - --head_ref_branch=${{ github.head_ref }} \ - --base_ref_branch=${{ github.base_ref }} \ - --github_ref=${{ github.ref }} \ + --evm_pr_version_branch=${{ needs.build-image.outputs.evm_pr_version_branch }} \ + --is_evm_release=${{ needs.build-image.outputs.is_evm_release }} \ + --evm_sha_tag=${{ needs.build-image.outputs.evm_sha_tag }} \ + --evm_tag=${{ needs.build-image.outputs.evm_tag }} \ --token=${{secrets.GHTOKEN }} \ --labels='${{ toJson(github.event.pull_request.labels.*.name) }}' \ --pr_url="${{ github.api_url }}/repos/${{ github.repository }}/issues" \ @@ -107,8 +102,9 @@ jobs: finalize-image: runs-on: neon-evm-1 needs: + - build-image - trigger-proxy-tests - - run-neon-evm-tests + - run-evm-tests steps: - uses: actions/checkout@v4 with: @@ -116,26 +112,13 @@ jobs: - name: Finalize image run: | python3 ./.github/workflows/deploy.py finalize_image \ - --github_ref=${GITHUB_REF} \ - --github_sha=${GITHUB_SHA} - - name: Check if it version branch - id: is_version_branch - run: | - if [[ "${{ github.ref }}" =~ "refs/heads/"[vt][0-9]+\.[0-9]+\.x ]]; then - echo "value=true" - echo "value=true" >> $GITHUB_OUTPUT - else - echo "value=false" - echo "value=false" >> $GITHUB_OUTPUT - fi + --evm_sha_tag=${{ needs.build-image.outputs.evm_sha_tag }} \ + --evm_tag=${{ needs.build-image.outputs.evm_tag }} + - name: Send notification to slack - if: | - failure() && - (github.ref_name == 'develop' || - github.ref_name == 'master' || - steps.is_version_branch.outputs.value || - startsWith(github.ref , 'refs/tags/')) + if: failure() run: | python3 ./.github/workflows/deploy.py send_notification \ + --evm_tag=${{ needs.build-image.outputs.evm_tag }} \ --url=${{secrets.SLACK_EVM_CHANNEL_URL}} \ --build_url=${BUILD_URL} From d1f5cec80feaef43975f643b3dc375ed1ae0f693 Mon Sep 17 00:00:00 2001 From: Evgeny Zdanovich Date: Thu, 29 Aug 2024 12:10:18 +0200 Subject: [PATCH 307/318] Support of EIP-1559 in the Neon EVM (#409) * Introduce DynamicGas transaction type. * Implement instruction inspection for Compute Budget to calculate priority fee. * Implement validation of priority fee and transfer. * Add PRIORITYFEE logging to be able to parse it from the proxy. * Implement BASEFEE opcode, take it from the transaction. * Support DynamicFee transaction type in the transaction emulation TxParams. * Expose additional transaction data from get_holder API: tx_type, max_fee_per_gas, max_priority_fee_per_gas. * Minor review changes, part1. * Handle transaction parsed rlp gracefully in the get_holder api method. * Fix after rebase on develop. * Remove validation of compute units from instructions for DynamicGas Transactions. Also, cover the case max_fee_per_gas=max_priority_fee_per_gas - treat it as a legacy transaction. * Make priority fee work the same as usual gas: charge the whole amount in the first iteration, track how much was granted to operator in the middle, refund the user in the end. * Forbid CPI calls of neon-evm with DynamicFee transactions inside. --- evm_loader/lib/src/commands/get_holder.rs | 40 +++- evm_loader/lib/src/types/mod.rs | 53 +++-- evm_loader/program/src/account/state.rs | 51 +++- .../program/src/account_storage/apply.rs | 1 - evm_loader/program/src/error.rs | 14 ++ evm_loader/program/src/evm/opcode.rs | 7 +- evm_loader/program/src/instruction/mod.rs | 1 + .../priority_fee_txn_calculator.rs | 138 +++++++++++ .../src/instruction/transaction_cancel.rs | 4 +- .../src/instruction/transaction_execute.rs | 7 +- .../src/instruction/transaction_step.rs | 24 +- evm_loader/program/src/types/mod.rs | 1 + evm_loader/program/src/types/transaction.rs | 225 ++++++++++++++++-- 13 files changed, 511 insertions(+), 55 deletions(-) create mode 100644 evm_loader/program/src/instruction/priority_fee_txn_calculator.rs diff --git a/evm_loader/lib/src/commands/get_holder.rs b/evm_loader/lib/src/commands/get_holder.rs index 0c0e8d108..d4bdf3dce 100644 --- a/evm_loader/lib/src/commands/get_holder.rs +++ b/evm_loader/lib/src/commands/get_holder.rs @@ -1,18 +1,16 @@ -use evm_loader::{ - account::{ - legacy::{ - LegacyFinalizedData, LegacyHolderData, TAG_HOLDER_DEPRECATED, - TAG_STATE_FINALIZED_DEPRECATED, - }, - Holder, StateAccount, StateFinalizedAccount, TAG_HOLDER, TAG_STATE, TAG_STATE_FINALIZED, +use ethnum::U256; +use evm_loader::account::{ + legacy::{ + LegacyFinalizedData, LegacyHolderData, TAG_HOLDER_DEPRECATED, + TAG_STATE_FINALIZED_DEPRECATED, }, - types::Address, + Holder, StateAccount, StateFinalizedAccount, TAG_HOLDER, TAG_STATE, TAG_STATE_FINALIZED, }; use serde::{Deserialize, Serialize}; use solana_sdk::{account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey}; use std::fmt::Display; -use crate::{account_storage::account_info, rpc::Rpc, types::TxParams, NeonResult}; +use crate::{account_storage::account_info, rpc::Rpc, types::Address, types::TxParams, NeonResult}; use serde_with::{hex::Hex, serde_as, skip_serializing_none, DisplayFromStr}; @@ -46,6 +44,9 @@ pub struct GetHolderResponse { #[serde_as(as = "Option")] pub tx: Option<[u8; 32]>, pub tx_data: Option, + pub tx_type: Option, + pub max_fee_per_gas: Option, + pub max_priority_fee_per_gas: Option, pub chain_id: Option, pub origin: Option
, @@ -78,11 +79,15 @@ pub fn read_holder(program_id: &Pubkey, info: AccountInfo) -> NeonResult { let holder = Holder::from_account(program_id, info)?; + Ok(GetHolderResponse { status: Status::Holder, len: Some(data_len), owner: Some(holder.owner()), tx: Some(holder.transaction_hash()), + // Holder may not yet contain the transaction and empty rlp panics. + // TODO: check the behavior. + tx_type: Some(0), ..GetHolderResponse::default() }) } @@ -93,6 +98,10 @@ pub fn read_holder(program_id: &Pubkey, info: AccountInfo) -> NeonResult NeonResult NeonResult NeonResult, pub actual_gas_used: Option, pub gas_price: Option, + pub max_fee_per_gas: Option, + pub max_priority_fee_per_gas: Option, pub access_list: Option>, pub chain_id: Option, } @@ -68,20 +71,38 @@ impl TxParams { .map(|a| (a.address, a.storage_keys.into_vector())) .collect(); - let access_list_tx = AccessListTx { - nonce, - gas_price: U256::ZERO, - gas_limit: self.gas_limit.unwrap_or(U256::MAX), - target: self.to, - value: self.value.unwrap_or_default(), - call_data: self.data.unwrap_or_default().into_vector(), - chain_id: U256::from(chain_id), - access_list: access_list.elementwise_copy_into_vector(), - r: U256::ZERO, - s: U256::ZERO, - recovery_id: 0, - }; - TransactionPayload::AccessList(access_list_tx) + if let Some(max_priority_fee_per_gas) = self.max_priority_fee_per_gas { + let dynamic_fee_tx = DynamicFeeTx { + nonce, + max_priority_fee_per_gas, + max_fee_per_gas: self.max_fee_per_gas.unwrap_or(max_priority_fee_per_gas * 2), + gas_limit: self.gas_limit.unwrap_or(U256::MAX), + target: self.to, + value: self.value.unwrap_or_default(), + call_data: self.data.unwrap_or_default().into_vector(), + chain_id: U256::from(chain_id), + access_list: access_list.elementwise_copy_into_vector(), + r: U256::ZERO, + s: U256::ZERO, + recovery_id: 0, + }; + TransactionPayload::DynamicFee(dynamic_fee_tx) + } else { + let access_list_tx = AccessListTx { + nonce, + gas_price: U256::ZERO, + gas_limit: self.gas_limit.unwrap_or(U256::MAX), + target: self.to, + value: self.value.unwrap_or_default(), + call_data: self.data.unwrap_or_default().into_vector(), + chain_id: U256::from(chain_id), + access_list: access_list.elementwise_copy_into_vector(), + r: U256::ZERO, + s: U256::ZERO, + recovery_id: 0, + }; + TransactionPayload::AccessList(access_list_tx) + } } else { let legacy_tx = LegacyTx { nonce, @@ -119,6 +140,8 @@ impl TxParams { value: Some(tx.value()), gas_limit: Some(tx.gas_limit()), gas_price: Some(tx.gas_price()), + max_fee_per_gas: tx.max_fee_per_gas(), + max_priority_fee_per_gas: tx.max_priority_fee_per_gas(), chain_id: tx.chain_id(), access_list: None, actual_gas_used: None, diff --git a/evm_loader/program/src/account/state.rs b/evm_loader/program/src/account/state.rs index 440e55973..a0b104bc5 100644 --- a/evm_loader/program/src/account/state.rs +++ b/evm_loader/program/src/account/state.rs @@ -12,6 +12,7 @@ use crate::evm::tracing::EventListener; use crate::evm::Machine; use crate::executor::ExecutorStateData; use crate::types::boxx::{boxx, Boxx}; +use crate::types::DynamicFeeTx; use crate::types::{ read_raw_utils::{read_vec, ReconstructRaw}, AccessListTx, Address, LegacyTx, Transaction, TransactionPayload, TreeMap, @@ -97,6 +98,8 @@ struct Data { pub touched_accounts: TreeMap, /// Ethereum transaction gas used and paid pub gas_used: U256, + /// Ethereum transaction priority fee used and paid in tokens + pub priority_fee_used: U256, /// Steps executed in the transaction pub steps_executed: u64, } @@ -190,6 +193,7 @@ impl<'a> StateAccount<'a> { revisions, touched_accounts: TreeMap::new(), gas_used: U256::ZERO, + priority_fee_used: U256::ZERO, steps_executed: 0_u64, }); @@ -323,10 +327,17 @@ impl<'a> StateAccount<'a> { } #[must_use] - pub fn gas_available(&self) -> U256 { + fn gas_available(&self) -> U256 { self.trx().gas_limit().saturating_sub(self.gas_used()) } + fn priority_fee_in_tokens_available(&self) -> Result { + Ok(self + .trx() + .priority_fee_limit_in_tokens()? + .saturating_sub(self.data.priority_fee_used)) + } + fn use_gas(&mut self, amount: U256) -> Result { if amount == U256::ZERO { return Ok(U256::ZERO); @@ -346,12 +357,31 @@ impl<'a> StateAccount<'a> { .ok_or(Error::IntegerOverflow) } + fn use_priority_fee_tokens(&mut self, tokens: U256) -> Result<()> { + let total_priority_fee_used = self.data.priority_fee_used.saturating_add(tokens); + let priority_fee_limit = self.trx().priority_fee_limit_in_tokens()?; + + if total_priority_fee_used > priority_fee_limit { + return Err(Error::OutOfPriorityFee( + priority_fee_limit, + total_priority_fee_used, + )); + } + + self.data.priority_fee_used = total_priority_fee_used; + Ok(()) + } + pub fn consume_gas( &mut self, amount: U256, + priority_fee_tokens: U256, receiver: Option, ) -> Result<()> { - let tokens = self.use_gas(amount)?; + self.use_priority_fee_tokens(priority_fee_tokens)?; + let gas_fee_tokens = self.use_gas(amount)?; + + let tokens = gas_fee_tokens + priority_fee_tokens; if tokens == U256::ZERO { return Ok(()); } @@ -373,8 +403,12 @@ impl<'a> StateAccount<'a> { assert!(origin.address() == self.trx_origin()); let unused_gas = self.gas_available(); - let tokens = self.use_gas(unused_gas)?; - origin.mint(tokens) + let gas_fee_tokens = self.use_gas(unused_gas)?; + + let unused_priority_fee = self.priority_fee_in_tokens_available()?; + self.use_priority_fee_tokens(unused_priority_fee)?; + + origin.mint(gas_fee_tokens + unused_priority_fee) } #[must_use] @@ -533,6 +567,15 @@ impl<'a> StateAccount<'a> { memory_space_delta, )) } + 2 => { + let dynamic_fee_payload_ptr = payload_ptr + .wrapping_add(payload_ptr.align_offset(align_of::())); + + TransactionPayload::DynamicFee(DynamicFeeTx::build( + dynamic_fee_payload_ptr.cast::(), + memory_space_delta, + )) + } _ => { return Err(Error::Custom( "Incorrect transaction payload type.".to_owned(), diff --git a/evm_loader/program/src/account_storage/apply.rs b/evm_loader/program/src/account_storage/apply.rs index baae5ff7f..c0d2acfa8 100644 --- a/evm_loader/program/src/account_storage/apply.rs +++ b/evm_loader/program/src/account_storage/apply.rs @@ -41,7 +41,6 @@ impl<'a> ProgramAccountStorage<'a> { let mut source = BalanceAccount::from_account(&crate::ID, source)?; let mut target = self.accounts.operator_balance(); - source.increment_revision(&self.rent, &self.accounts)?; target.consume_gas(&mut source, value) } diff --git a/evm_loader/program/src/error.rs b/evm_loader/program/src/error.rs index fcbcc3380..2e2cd61f0 100644 --- a/evm_loader/program/src/error.rs +++ b/evm_loader/program/src/error.rs @@ -107,6 +107,9 @@ pub enum Error { #[error("Out of Gas, limit = {0}, required = {1}")] OutOfGas(U256, U256), + #[error("Out of Priority Fee, limit = {0}, required = {1}")] + OutOfPriorityFee(U256, U256), + #[error("Invalid gas balance account")] GasReceiverInvalidChainId, @@ -203,6 +206,17 @@ pub enum Error { #[error("Operator Balance - invalid address")] OperatorBalanceInvalidAddress, + + #[error( + "Instructions that execute Ethereum DynamicGas transaction (EIP-1559) should specify priority fee." + )] + PriorityFeeNotSpecified, + + #[error("Error while parsing priority fee instructions: {0}")] + PriorityFeeParsingError(String), + + #[error("Priority fee calculation error: {0}")] + PriorityFeeError(String), } pub type Result = std::result::Result; diff --git a/evm_loader/program/src/evm/opcode.rs b/evm_loader/program/src/evm/opcode.rs index 0c88eb792..f7cc9df7b 100644 --- a/evm_loader/program/src/evm/opcode.rs +++ b/evm_loader/program/src/evm/opcode.rs @@ -751,11 +751,12 @@ impl Machine { Ok(Action::Continue) } - /// London hardfork, EIP-3198: current block's base fee - /// NOT SUPPORTED + /// London hardfork, EIP-3198: current block's base fee, taken from the transaction. + /// N.B. for DynamicFee transaction (EIP-1559), gas_price here is equal to: + /// `max_fee_per_gas` - `max_priority_fee_per_gas`. #[maybe_async] pub async fn opcode_basefee(&mut self, _backend: &mut B) -> Result { - self.stack.push_zero()?; + self.stack.push_u256(self.gas_price)?; Ok(Action::Continue) } diff --git a/evm_loader/program/src/instruction/mod.rs b/evm_loader/program/src/instruction/mod.rs index a27de3dd1..33cafddfe 100644 --- a/evm_loader/program/src/instruction/mod.rs +++ b/evm_loader/program/src/instruction/mod.rs @@ -271,6 +271,7 @@ pub mod neon_tokens_deposit; pub mod operator_create_balance; pub mod operator_delete_balance; pub mod operator_withdraw_balance; +pub mod priority_fee_txn_calculator; pub mod transaction_cancel; pub mod transaction_execute; pub mod transaction_execute_from_account; diff --git a/evm_loader/program/src/instruction/priority_fee_txn_calculator.rs b/evm_loader/program/src/instruction/priority_fee_txn_calculator.rs new file mode 100644 index 000000000..eec143b14 --- /dev/null +++ b/evm_loader/program/src/instruction/priority_fee_txn_calculator.rs @@ -0,0 +1,138 @@ +use crate::debug::log_data; +use crate::gasometer::LAMPORTS_PER_SIGNATURE; +use crate::types::Transaction; +use crate::types::TransactionPayload; +use crate::{error::Error, types::DynamicFeeTx}; +use ethnum::U256; +use solana_program::{instruction::get_processed_sibling_instruction, pubkey, pubkey::Pubkey}; +use std::convert::From; + +// Because ComputeBudget program is not accessible through CPI, it's not a part of the standard +// solana_program library crate. Thus, we have to hardcode a couple of constants. +// The pubkey of the Compute Budget. +const COMPUTE_BUDGET_ADDRESS: Pubkey = pubkey!("ComputeBudget111111111111111111111111111111"); +// The Compute Budget SetComputeUnitLimit instruction tag. +const COMPUTE_UNIT_LIMIT_TAG: u8 = 0x2; +// The Compute Budget SetComputeUnitPrice instruction tag. +const COMPUTE_UNIT_PRICE_TAG: u8 = 0x3; +// The default compute units limit for Solana transactions. +const DEFAULT_COMPUTE_UNIT_LIMIT: u32 = 200_000; + +// Conversion from "total micro lamports" to lamports per gas unit. +const CONVERSION_MULTIPLIER: u64 = 1_000_000 / LAMPORTS_PER_SIGNATURE; + +/// Handles priority fee: +/// - No-op for anything but DynamicFee transactions, +/// - Calculates and logs the priority fee in tokens for DynamicFee transactions. +pub fn handle_priority_fee(txn: &Transaction, gas_amount: U256) -> Result { + if let TransactionPayload::DynamicFee(ref dynamic_fee_payload) = txn.transaction { + let priority_fee_in_tokens = get_priority_fee_in_tokens(dynamic_fee_payload, gas_amount)?; + log_data(&[b"PRIORITYFEE", &priority_fee_in_tokens.to_le_bytes()]); + return Ok(priority_fee_in_tokens); + } + Ok(U256::ZERO) +} + +/// Returns the amount of "priority fee in tokens" that User have to pay to the Operator. +pub fn get_priority_fee_in_tokens(txn: &DynamicFeeTx, gas_amount: U256) -> Result { + let max_fee = txn.max_fee_per_gas; + let max_priority_fee = txn.max_priority_fee_per_gas; + + if max_priority_fee > max_fee { + return Err(Error::PriorityFeeError( + "max_priority_fee_per_gas > max_fee_per_gas".to_string(), + )); + } + + if max_fee == max_priority_fee { + // If max_fee_per_gas == max_priority_fee_per_gas, we handle transaction as legacy: + // - charge max_fee_per_gas * gas_used, + // - do not charge any priority fee. + return Ok(U256::ZERO); + } + + if max_priority_fee == U256::ZERO { + // If the User set priority fee to zero, the resulting priority fee is 0. + return Ok(U256::ZERO); + } + + let (cu_limit, cu_price) = get_compute_budget_priority_fee()?; + + let priority_fee_per_gas_in_lamports: u64 = cu_price + .checked_mul(CONVERSION_MULTIPLIER * cu_limit as u64) + .ok_or(Error::PriorityFeeError( + "cu_limit * cu_price overflow".to_string(), + ))?; + let base_fee_per_gas = max_fee - max_priority_fee; + + // Get minimum value of priority_fee_per_gas from what the User sets as max_priority_fee_per_gas + // and what the operator paid as Compute Budget (as converted to gas tokens). + Ok( + max_priority_fee.min(base_fee_per_gas * U256::from(priority_fee_per_gas_in_lamports)) + * gas_amount, + ) +} + +/// Extracts the data about compute units from instructions within the current transaction. +/// Returns the pair of (`compute_budget_unit_limit`, `compute_budget_unit_price`) +/// N.B. the `compute_budget_unit_price` is denominated in micro Lamports. +fn get_compute_budget_priority_fee() -> Result<(u32, u64), Error> { + // Intent is to check first several instructions in hopes to find ComputeBudget ones. + let max_idx = 5; + + let mut idx = 0; + let mut compute_unit_limit: Option = None; + let mut compute_unit_price: Option = None; + while (compute_unit_limit.is_none() || compute_unit_price.is_none()) && idx < max_idx { + let ixn_option = get_processed_sibling_instruction(idx); + if ixn_option.is_none() { + // If the current instruction is empty, break from the cycle. + break; + } + + let cur_ixn = ixn_option.unwrap(); + // Skip all instructions that do not target Compute Budget Program. + if cur_ixn.program_id != COMPUTE_BUDGET_ADDRESS { + idx += 1; + continue; + } + + // As of now, data of ComputeBudgetInstruction is always non-empty. + // This is a sanity check to have a safe future-proof implementation. + let tag = cur_ixn.data.first().unwrap_or(&0); + match *tag { + COMPUTE_UNIT_LIMIT_TAG => { + compute_unit_limit = Some(u32::from_le_bytes( + cur_ixn.data[1..].try_into().map_err(|_| { + Error::PriorityFeeParsingError( + "Invalid format of compute unit limit.".to_string(), + ) + })?, + )); + } + COMPUTE_UNIT_PRICE_TAG => { + compute_unit_price = Some(u64::from_le_bytes( + cur_ixn.data[1..].try_into().map_err(|_| { + Error::PriorityFeeParsingError( + "Invalid format of compute unit price.".to_string(), + ) + })?, + )); + } + _ => (), + } + idx += 1; + } + + if compute_unit_price.is_none() { + return Err(Error::PriorityFeeNotSpecified); + } + + // Caller may not specify the compute unit limit, the default should take effect. + if compute_unit_limit.is_none() { + compute_unit_limit = Some(DEFAULT_COMPUTE_UNIT_LIMIT); + } + + // Both are not none, it's safe to unwrap. + Ok((compute_unit_limit.unwrap(), compute_unit_price.unwrap())) +} diff --git a/evm_loader/program/src/instruction/transaction_cancel.rs b/evm_loader/program/src/instruction/transaction_cancel.rs index 52b3763a6..86e30e046 100644 --- a/evm_loader/program/src/instruction/transaction_cancel.rs +++ b/evm_loader/program/src/instruction/transaction_cancel.rs @@ -3,6 +3,7 @@ use crate::config::DEFAULT_CHAIN_ID; use crate::debug::log_data; use crate::error::{Error, Result}; use crate::gasometer::{CANCEL_TRX_COST, LAST_ITERATION_COST}; +use crate::instruction::priority_fee_txn_calculator; use arrayref::array_ref; use ethnum::U256; use solana_program::rent::Rent; @@ -61,7 +62,8 @@ fn execute<'a>( ]); let gas = U256::from(CANCEL_TRX_COST + LAST_ITERATION_COST); - let _ = storage.consume_gas(gas, accounts.try_operator_balance()); // ignore error + let priority_fee = priority_fee_txn_calculator::handle_priority_fee(storage.trx(), gas)?; + let _ = storage.consume_gas(gas, priority_fee, accounts.try_operator_balance()); // ignore error let origin = storage.trx_origin(); let (origin_pubkey, _) = origin.find_balance_address(program_id, trx_chain_id); diff --git a/evm_loader/program/src/instruction/transaction_execute.rs b/evm_loader/program/src/instruction/transaction_execute.rs index ae5d4fb7c..ef5330ce4 100644 --- a/evm_loader/program/src/instruction/transaction_execute.rs +++ b/evm_loader/program/src/instruction/transaction_execute.rs @@ -6,6 +6,7 @@ use crate::evm::tracing::NoopEventListener; use crate::evm::Machine; use crate::executor::{ExecutorState, ExecutorStateData, SyncedExecutorState}; use crate::gasometer::Gasometer; +use crate::instruction::priority_fee_txn_calculator; use crate::instruction::transaction_step::log_return_value; use crate::types::{boxx::Boxx, Address, Transaction}; @@ -60,7 +61,8 @@ pub fn execute( log_data(&[b"GAS", &used_gas.to_le_bytes(), &used_gas.to_le_bytes()]); let gas_cost = used_gas.saturating_mul(gas_price); - account_storage.transfer_gas_payment(origin, chain_id, gas_cost)?; + let priority_fee = priority_fee_txn_calculator::handle_priority_fee(&trx, used_gas)?; + account_storage.transfer_gas_payment(origin, chain_id, gas_cost + priority_fee)?; log_return_value(&exit_reason); @@ -110,7 +112,8 @@ pub fn execute_with_solana_call( log_data(&[b"GAS", &used_gas.to_le_bytes(), &used_gas.to_le_bytes()]); let gas_cost = used_gas.saturating_mul(gas_price); - account_storage.transfer_gas_payment(origin, chain_id, gas_cost)?; + let priority_fee = priority_fee_txn_calculator::handle_priority_fee(&trx, used_gas)?; + account_storage.transfer_gas_payment(origin, chain_id, gas_cost + priority_fee)?; log_return_value(&exit_reason); diff --git a/evm_loader/program/src/instruction/transaction_step.rs b/evm_loader/program/src/instruction/transaction_step.rs index d101dc4de..8a62b6b1f 100644 --- a/evm_loader/program/src/instruction/transaction_step.rs +++ b/evm_loader/program/src/instruction/transaction_step.rs @@ -8,7 +8,8 @@ use crate::error::{Error, Result}; use crate::evm::tracing::NoopEventListener; use crate::evm::{ExitStatus, Machine}; use crate::executor::{Action, ExecutorState, ExecutorStateData}; -use crate::gasometer::Gasometer; +use crate::gasometer::{Gasometer, LAMPORTS_PER_SIGNATURE}; +use crate::instruction::priority_fee_txn_calculator; use crate::types::boxx::boxx; use crate::types::TreeMap; use crate::types::Vector; @@ -37,11 +38,12 @@ pub fn do_begin<'a>( origin_account.increment_revision(account_storage.rent(), account_storage.db())?; origin_account.increment_nonce()?; - // Burn `gas_limit` tokens from the origin account - // Later we will mint them to the operator - // Remaining tokens are returned to the origin in the last iteration + // Burn `gas_limit` tokens (both base fee and priority, if any) from the origin account. + // Later we will mint them to the operator. + // Remaining tokens are returned to the origin in the last iteration. let gas_limit_in_tokens = storage.trx().gas_limit_in_tokens()?; - origin_account.burn(gas_limit_in_tokens)?; + let max_priority_fee_in_tokens = storage.trx().priority_fee_limit_in_tokens()?; + origin_account.burn(gas_limit_in_tokens + max_priority_fee_in_tokens)?; allocate_or_reinit_state(&mut account_storage, &mut storage, true)?; let mut state_data = storage.read_executor_state(); @@ -186,7 +188,17 @@ fn finalize<'a, 'b>( &total_used_gas.to_le_bytes(), ]); - storage.consume_gas(used_gas, accounts.db().try_operator_balance())?; + // Calculate priority fee for the current iteration. + let priority_fee_in_tokens = priority_fee_txn_calculator::handle_priority_fee( + storage.trx(), + LAMPORTS_PER_SIGNATURE.into(), + )?; + + storage.consume_gas( + used_gas, + priority_fee_in_tokens, + accounts.db().try_operator_balance(), + )?; if let Some(status) = status { log_return_value(&status); diff --git a/evm_loader/program/src/types/mod.rs b/evm_loader/program/src/types/mod.rs index 3a074f214..d6e7fff22 100644 --- a/evm_loader/program/src/types/mod.rs +++ b/evm_loader/program/src/types/mod.rs @@ -1,5 +1,6 @@ pub use address::Address; pub use transaction::AccessListTx; +pub use transaction::DynamicFeeTx; pub use transaction::LegacyTx; pub use transaction::StorageKey; pub use transaction::Transaction; diff --git a/evm_loader/program/src/types/transaction.rs b/evm_loader/program/src/types/transaction.rs index 229868e8f..b04c319b3 100644 --- a/evm_loader/program/src/types/transaction.rs +++ b/evm_loader/program/src/types/transaction.rs @@ -2,6 +2,7 @@ use ethnum::U256; use maybe_async::maybe_async; use rlp::{DecoderError, Rlp}; use serde::{Deserialize, Serialize}; +use solana_program::instruction::{get_stack_height, TRANSACTION_LEVEL_STACK_HEIGHT}; use std::convert::TryInto; use crate::types::vector::VectorVecExt; @@ -261,14 +262,117 @@ impl rlp::Decodable for AccessListTx { } } -// TODO: Will be added as a part of EIP-1559 -// struct DynamicFeeTx {} +#[derive(Debug, ReconstructRaw)] +#[repr(C)] +pub struct DynamicFeeTx { + pub nonce: u64, + pub max_priority_fee_per_gas: U256, + pub max_fee_per_gas: U256, + pub gas_limit: U256, + pub target: Option
, + pub value: U256, + pub call_data: Vector, + pub r: U256, + pub s: U256, + pub chain_id: U256, + pub recovery_id: u8, + pub access_list: Vector<(Address, Vector)>, +} + +impl rlp::Decodable for DynamicFeeTx { + fn decode(rlp: &rlp::Rlp) -> Result { + let rlp_len = { + let info = rlp.payload_info()?; + info.header_len + info.value_len + }; + + if rlp.as_raw().len() != rlp_len { + return Err(rlp::DecoderError::RlpInconsistentLengthAndData); + } + + let chain_id: U256 = u256(&rlp.at(0)?)?; + let nonce: u64 = rlp.val_at(1)?; + + let max_priority_fee_per_gas: U256 = u256(&rlp.at(2)?)?; + let max_fee_per_gas: U256 = u256(&rlp.at(3)?)?; + if max_fee_per_gas < max_priority_fee_per_gas { + return Err(rlp::DecoderError::Custom( + "max_fee_per_gas < max_priority_fee_per_gas", + )); + } + + let gas_limit: U256 = u256(&rlp.at(4)?)?; + let target: Option
= { + let target = rlp.at(5)?; + if target.is_empty() { + if target.is_data() { + None + } else { + return Err(rlp::DecoderError::RlpExpectedToBeData); + } + } else { + Some(target.as_val()?) + } + }; + + let value: U256 = u256(&rlp.at(6)?)?; + let call_data = decode_byte_vector(&rlp.at(7)?)?; + + let rlp_access_list = rlp.at(8)?; + let mut access_list = vector![]; + + for entry in &rlp_access_list { + // Check if entry is a list + if entry.is_list() { + // Parse address from first element + let address: Address = entry.at(0)?.as_val()?; + + // Get storage keys from second element + let mut storage_keys: Vector = vector![]; + + for key in &entry.at(1)? { + storage_keys.push(key.as_val()?); + } + + access_list.push((address, storage_keys)); + } else { + return Err(rlp::DecoderError::RlpExpectedToBeList); + } + } + + let y_parity: u8 = rlp.at(9)?.as_val()?; + let r: U256 = u256(&rlp.at(10)?)?; + let s: U256 = u256(&rlp.at(11)?)?; + + if rlp.at(12).is_ok() { + return Err(rlp::DecoderError::RlpIncorrectListLen); + } + + let tx = DynamicFeeTx { + nonce, + max_priority_fee_per_gas, + max_fee_per_gas, + gas_limit, + target, + value, + call_data, + r, + s, + chain_id, + recovery_id: y_parity, + access_list, + }; + + Ok(tx) + } +} #[derive(Debug)] #[repr(C, u8)] pub enum TransactionPayload { Legacy(LegacyTx), AccessList(AccessListTx), + DynamicFee(DynamicFeeTx), } #[derive(Debug)] @@ -304,6 +408,14 @@ impl Transaction { (hash, signed_hash) } + // Dynamic Fee transaction + Some(TransactionEnvelope::DynamicFee) => { + let hash = + solana_program::keccak::hashv(&[&[0x02], transaction_rlp.as_raw()]).to_bytes(); + let signed_hash = Self::eip2718_signed_hash(&[0x02], transaction_rlp, 9)?; + + (hash, signed_hash) + } // Legacy trasaction None => { let hash = solana_program::keccak::hash(transaction_rlp.as_raw()).to_bytes(); @@ -311,7 +423,6 @@ impl Transaction { (hash, signed_hash) } - _ => unimplemented!(), }; let info = transaction_rlp.payload_info()?; @@ -463,13 +574,24 @@ impl Transaction { tx, )? } + Some(TransactionEnvelope::DynamicFee) => { + let dynamic_fee_tx = + rlp::decode::(transaction).map_err(Error::from)?; + let chain_id = dynamic_fee_tx.chain_id; + let tx = TransactionPayload::DynamicFee(dynamic_fee_tx); + Transaction::from_payload( + &Some(TransactionEnvelope::DynamicFee), + Some(chain_id), + &rlp::Rlp::new(transaction), + tx, + )? + } None => { let legacy_tx = rlp::decode::(transaction).map_err(Error::from)?; let chain_id = legacy_tx.chain_id; let tx = TransactionPayload::Legacy(legacy_tx); Transaction::from_payload(&None, chain_id, &rlp::Rlp::new(transaction), tx)? } - Some(TransactionEnvelope::DynamicFee) => unimplemented!(), }; Ok(tx) @@ -492,7 +614,8 @@ impl Transaction { pub fn nonce(&self) -> u64 { match self.transaction { TransactionPayload::Legacy(LegacyTx { nonce, .. }) - | TransactionPayload::AccessList(AccessListTx { nonce, .. }) => nonce, + | TransactionPayload::AccessList(AccessListTx { nonce, .. }) + | TransactionPayload::DynamicFee(DynamicFeeTx { nonce, .. }) => nonce, } } @@ -501,6 +624,25 @@ impl Transaction { match self.transaction { TransactionPayload::Legacy(LegacyTx { gas_price, .. }) | TransactionPayload::AccessList(AccessListTx { gas_price, .. }) => gas_price, + TransactionPayload::DynamicFee(DynamicFeeTx { + max_priority_fee_per_gas, + max_fee_per_gas, + .. + }) => { + // Metamask case. + // Currently, the Metamask does not use native RPC methods for gas estimation and + // sets max_priority_fee_per_gas = max_fee_per_gas for DynamicGas transactions + // when it can't estimate the gas price. + // For such a case, we will treat DynamicGas transactions as legacy ones: + // - gas_price is equal to max_fee_per_gas, + // - we do not charge the Priority Fee from the User (gas is charged as for Legacy txn). + if max_fee_per_gas == max_priority_fee_per_gas { + max_fee_per_gas + } else { + // return base_fee_per_gas as a gas_price - priority fee is charged per iteration separately. + max_fee_per_gas - max_priority_fee_per_gas + } + } } } @@ -508,7 +650,8 @@ impl Transaction { pub fn gas_limit(&self) -> U256 { match self.transaction { TransactionPayload::Legacy(LegacyTx { gas_limit, .. }) - | TransactionPayload::AccessList(AccessListTx { gas_limit, .. }) => gas_limit, + | TransactionPayload::AccessList(AccessListTx { gas_limit, .. }) + | TransactionPayload::DynamicFee(DynamicFeeTx { gas_limit, .. }) => gas_limit, } } @@ -518,11 +661,19 @@ impl Transaction { .ok_or(Error::IntegerOverflow) } + pub fn priority_fee_limit_in_tokens(&self) -> Result { + self.max_priority_fee_per_gas() + .unwrap_or_default() + .checked_mul(self.gas_limit()) + .ok_or(Error::IntegerOverflow) + } + #[must_use] pub fn target(&self) -> Option
{ match self.transaction { TransactionPayload::Legacy(LegacyTx { target, .. }) - | TransactionPayload::AccessList(AccessListTx { target, .. }) => target, + | TransactionPayload::AccessList(AccessListTx { target, .. }) + | TransactionPayload::DynamicFee(DynamicFeeTx { target, .. }) => target, } } @@ -530,7 +681,8 @@ impl Transaction { pub fn value(&self) -> U256 { match self.transaction { TransactionPayload::Legacy(LegacyTx { value, .. }) - | TransactionPayload::AccessList(AccessListTx { value, .. }) => value, + | TransactionPayload::AccessList(AccessListTx { value, .. }) + | TransactionPayload::DynamicFee(DynamicFeeTx { value, .. }) => value, } } @@ -538,7 +690,8 @@ impl Transaction { pub fn call_data(&self) -> &[u8] { match &self.transaction { TransactionPayload::Legacy(LegacyTx { call_data, .. }) - | TransactionPayload::AccessList(AccessListTx { call_data, .. }) => call_data, + | TransactionPayload::AccessList(AccessListTx { call_data, .. }) + | TransactionPayload::DynamicFee(DynamicFeeTx { call_data, .. }) => call_data, } } @@ -546,7 +699,8 @@ impl Transaction { pub fn r(&self) -> U256 { match self.transaction { TransactionPayload::Legacy(LegacyTx { r, .. }) - | TransactionPayload::AccessList(AccessListTx { r, .. }) => r, + | TransactionPayload::AccessList(AccessListTx { r, .. }) + | TransactionPayload::DynamicFee(DynamicFeeTx { r, .. }) => r, } } @@ -554,7 +708,8 @@ impl Transaction { pub fn s(&self) -> U256 { match self.transaction { TransactionPayload::Legacy(LegacyTx { s, .. }) - | TransactionPayload::AccessList(AccessListTx { s, .. }) => s, + | TransactionPayload::AccessList(AccessListTx { s, .. }) + | TransactionPayload::DynamicFee(DynamicFeeTx { s, .. }) => s, } } @@ -562,7 +717,8 @@ impl Transaction { pub fn chain_id(&self) -> Option { match self.transaction { TransactionPayload::Legacy(LegacyTx { chain_id, .. }) => chain_id, - TransactionPayload::AccessList(AccessListTx { chain_id, .. }) => Some(chain_id), + TransactionPayload::AccessList(AccessListTx { chain_id, .. }) + | TransactionPayload::DynamicFee(DynamicFeeTx { chain_id, .. }) => Some(chain_id), } .map(std::convert::TryInto::try_into) .transpose() @@ -573,7 +729,8 @@ impl Transaction { pub fn recovery_id(&self) -> u8 { match self.transaction { TransactionPayload::Legacy(LegacyTx { recovery_id, .. }) - | TransactionPayload::AccessList(AccessListTx { recovery_id, .. }) => recovery_id, + | TransactionPayload::AccessList(AccessListTx { recovery_id, .. }) + | TransactionPayload::DynamicFee(DynamicFeeTx { recovery_id, .. }) => recovery_id, } } @@ -592,10 +749,41 @@ impl Transaction { self.signed_hash } + #[must_use] + pub fn tx_type(&self) -> u8 { + match self.transaction { + TransactionPayload::Legacy(_) => 0, + TransactionPayload::AccessList(_) => 1, + TransactionPayload::DynamicFee(_) => 2, + } + } + + #[must_use] + pub fn max_fee_per_gas(&self) -> Option { + match self.transaction { + TransactionPayload::Legacy(_) | TransactionPayload::AccessList(_) => None, + TransactionPayload::DynamicFee(DynamicFeeTx { + max_fee_per_gas, .. + }) => Some(max_fee_per_gas), + } + } + + #[must_use] + pub fn max_priority_fee_per_gas(&self) -> Option { + match self.transaction { + TransactionPayload::Legacy(_) | TransactionPayload::AccessList(_) => None, + TransactionPayload::DynamicFee(DynamicFeeTx { + max_priority_fee_per_gas, + .. + }) => Some(max_priority_fee_per_gas), + } + } + #[must_use] pub fn access_list(&self) -> Option<&Vector<(Address, Vector)>> { match &self.transaction { - TransactionPayload::AccessList(AccessListTx { access_list, .. }) => Some(access_list), + TransactionPayload::AccessList(AccessListTx { access_list, .. }) + | TransactionPayload::DynamicFee(DynamicFeeTx { access_list, .. }) => Some(access_list), TransactionPayload::Legacy(_) => None, } } @@ -605,6 +793,7 @@ impl Transaction { match &mut self.transaction { TransactionPayload::AccessList(AccessListTx { gas_limit, .. }) + | TransactionPayload::DynamicFee(DynamicFeeTx { gas_limit, .. }) | TransactionPayload::Legacy(LegacyTx { gas_limit, .. }) => { *gas_limit = gas_limit.saturating_mul(gas_multiplier); } @@ -631,6 +820,14 @@ impl Transaction { return Err(error); } + // The reason to forbid the calls for DynamicFee transactions - priority fee calculation + // uses get_processed_sibling_instruction syscall which doesn't work well for CPI. + if self.tx_type() == 2 && get_stack_height() != TRANSACTION_LEVEL_STACK_HEIGHT { + return Err(Error::Custom( + "CPI calls of Neon EVM are forbidden for DynamicFee transaction type.".to_owned(), + )); + } + Ok(()) } } From 04fdf8bfb52de342473338d56fab3edd83f80983 Mon Sep 17 00:00:00 2001 From: iguberman Date: Thu, 29 Aug 2024 21:20:22 -0500 Subject: [PATCH 308/318] Add support for "none" TRACER_DB_TYPE --- evm_loader/lib/src/config.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/evm_loader/lib/src/config.rs b/evm_loader/lib/src/config.rs index 5c4f9f5e9..d284a0476 100644 --- a/evm_loader/lib/src/config.rs +++ b/evm_loader/lib/src/config.rs @@ -80,7 +80,9 @@ pub fn load_api_config_from_environment() -> APIOptions { .and_then(|v| Pubkey::from_str(&v).ok()) .expect("SOLANA_KEY_FOR_CONFIG variable must be a valid pubkey"); - let db_config = load_db_config_from_environment(); + // Mandatory db config here + let db_config = load_db_config_from_environment() + .expect("TRACER_DB_TYPE variable must be either 'clickhouse', 'rocksdb'"); APIOptions { solana_cli_config_path, @@ -95,7 +97,7 @@ pub fn load_api_config_from_environment() -> APIOptions { } #[must_use] -pub fn load_db_config_from_environment() -> DbConfig { +pub fn load_db_config_from_environment() -> Option { env::var("TRACER_DB_TYPE") .ok() .and_then(|db_type| match db_type.to_lowercase().as_str() { @@ -103,9 +105,11 @@ pub fn load_db_config_from_environment() -> DbConfig { load_rocks_db_config_from_environment(), )), "clickhouse" => Some(DbConfig::ChDbConfig(load_ch_db_config_from_environment())), - _ => None, + "none" => None, + _ => { + panic!("TRACER_DB_TYPE variable must be either 'clickhouse', 'rocksdb', or 'none'") + } }) - .expect("TRACER_DB_TYPE variable must be either 'clickhouse' or 'rocksdb'") } pub fn load_ch_db_config_from_environment() -> ChDbConfig { From e380af1ca99f8fdb1446cebf801f216e457f2be5 Mon Sep 17 00:00:00 2001 From: iguberman Date: Fri, 30 Aug 2024 00:11:11 -0500 Subject: [PATCH 309/318] experimental change with fully implemented NoDbConfig and correpsonding NoDb TracerDbType which returns Err result for every method --- evm_loader/lib/src/config.rs | 17 ++++---- evm_loader/lib/src/types/mod.rs | 7 +++- evm_loader/lib/src/types/no_db.rs | 65 +++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 9 deletions(-) create mode 100644 evm_loader/lib/src/types/no_db.rs diff --git a/evm_loader/lib/src/config.rs b/evm_loader/lib/src/config.rs index d284a0476..8ff349e59 100644 --- a/evm_loader/lib/src/config.rs +++ b/evm_loader/lib/src/config.rs @@ -32,6 +32,7 @@ pub struct APIOptions { pub enum DbConfig { RocksDbConfig(RocksDbConfig), ChDbConfig(ChDbConfig), + NoDbConfig(NoDbConfig), } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct ChDbConfig { @@ -46,6 +47,9 @@ pub struct RocksDbConfig { pub rocksdb_port: u16, } +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct NoDbConfig {} + /// # Errors #[must_use] pub fn load_api_config_from_environment() -> APIOptions { @@ -80,9 +84,7 @@ pub fn load_api_config_from_environment() -> APIOptions { .and_then(|v| Pubkey::from_str(&v).ok()) .expect("SOLANA_KEY_FOR_CONFIG variable must be a valid pubkey"); - // Mandatory db config here - let db_config = load_db_config_from_environment() - .expect("TRACER_DB_TYPE variable must be either 'clickhouse', 'rocksdb'"); + let db_config = load_db_config_from_environment(); APIOptions { solana_cli_config_path, @@ -97,7 +99,7 @@ pub fn load_api_config_from_environment() -> APIOptions { } #[must_use] -pub fn load_db_config_from_environment() -> Option { +pub fn load_db_config_from_environment() -> DbConfig { env::var("TRACER_DB_TYPE") .ok() .and_then(|db_type| match db_type.to_lowercase().as_str() { @@ -105,11 +107,10 @@ pub fn load_db_config_from_environment() -> Option { load_rocks_db_config_from_environment(), )), "clickhouse" => Some(DbConfig::ChDbConfig(load_ch_db_config_from_environment())), - "none" => None, - _ => { - panic!("TRACER_DB_TYPE variable must be either 'clickhouse', 'rocksdb', or 'none'") - } + "none" => Some(DbConfig::NoDbConfig(NoDbConfig {})), + _ => None, }) + .expect("TRACER_DB_TYPE variable must be either 'clickhouse', 'rocksdb', or 'none'") } pub fn load_ch_db_config_from_environment() -> ChDbConfig { diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index a8da07ae1..a2314f0f5 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -1,11 +1,13 @@ pub mod tracer_ch_common; +pub mod no_db; pub(crate) mod tracer_ch_db; pub mod tracer_rocks_db; use crate::commands::get_config::ChainInfo; use crate::config::DbConfig; use crate::tracing::TraceCallConfig; +pub use crate::types::no_db::NoDb; use crate::types::tracer_ch_common::{EthSyncStatus, RevisionMap}; pub use crate::types::tracer_ch_db::ClickHouseDb; pub use crate::types::tracer_rocks_db::RocksDb; @@ -28,7 +30,7 @@ use serde_with::{hex::Hex, serde_as, DisplayFromStr, OneOrMany}; use solana_sdk::signature::Signature; use solana_sdk::{account::Account, pubkey::Pubkey}; use std::collections::HashMap; -use DbConfig::{ChDbConfig, RocksDbConfig}; +use DbConfig::{ChDbConfig, NoDbConfig, RocksDbConfig}; pub type DbResult = Result; @@ -36,6 +38,7 @@ pub type DbResult = Result; pub enum TracerDbType { ClickHouseDb, RocksDb, + NoDb, } impl TracerDbType { @@ -43,6 +46,7 @@ impl TracerDbType { match db_config { RocksDbConfig(rocks_db_config) => RocksDb::new(rocks_db_config).await.into(), ChDbConfig(ch_db_config) => ClickHouseDb::new(ch_db_config).into(), + NoDbConfig(..) => NoDb::default().into(), } } } @@ -52,6 +56,7 @@ impl Clone for TracerDbType { match self { Self::RocksDb(r) => r.clone().into(), Self::ClickHouseDb(c) => c.clone().into(), + Self::NoDb(n) => n.clone().into(), } } } diff --git a/evm_loader/lib/src/types/no_db.rs b/evm_loader/lib/src/types/no_db.rs new file mode 100644 index 000000000..17fce4f59 --- /dev/null +++ b/evm_loader/lib/src/types/no_db.rs @@ -0,0 +1,65 @@ +use super::tracer_ch_common::{EthSyncStatus, RevisionMap}; +use crate::types::{DbResult, TracerDb}; +use async_trait::async_trait; +use solana_sdk::signature::Signature; +use solana_sdk::{ + account::Account, + clock::{Slot, UnixTimestamp}, + pubkey::Pubkey, +}; +#[derive(Clone, Debug, Default)] +pub struct NoDb {} + +#[async_trait] +impl TracerDb for NoDb { + async fn get_block_time(&self, slot: Slot) -> DbResult { + Err(anyhow::anyhow!( + "No DB configured for get_block_time({slot})" + )) + } + + async fn get_earliest_rooted_slot(&self) -> DbResult { + Err(anyhow::anyhow!( + "No DB configured for get_earliest_rooted_slot" + )) + } + + async fn get_latest_block(&self) -> DbResult { + Err(anyhow::anyhow!("No DB configured for get_latest_block")) + } + + async fn get_account_at( + &self, + _pubkey: &Pubkey, + slot: u64, + _tx_index_in_block: Option, + ) -> DbResult> { + Err(anyhow::anyhow!( + "No DB configured for get_account_at slot {slot}" + )) + } + + async fn get_transaction_index(&self, _signature: Signature) -> DbResult { + Err(anyhow::anyhow!("No DB configured to get_transaction_index")) + } + + async fn get_neon_revisions(&self, _pubkey: &Pubkey) -> DbResult { + Err(anyhow::anyhow!( + "No DB configured to get_neon_revisions for pubkey" + )) + } + + async fn get_neon_revision(&self, slot: Slot, _pubkey: &Pubkey) -> DbResult { + Err(anyhow::anyhow!( + "No DB configured to get_neon_revisions for slot {slot}" + )) + } + + async fn get_slot_by_blockhash(&self, _blockhash: String) -> DbResult { + Err(anyhow::anyhow!("No DB configured to get_slot_by_blockhash")) + } + + async fn get_sync_status(&self) -> DbResult { + Err(anyhow::anyhow!("No DB configured to get_sync_status")) + } +} From 001079a322ea11a5dbfa211a3c1f9af2e0a61be5 Mon Sep 17 00:00:00 2001 From: Kristina Nikolaeva <112946046+kristinaNikolaevaa@users.noreply.github.com> Date: Mon, 2 Sep 2024 12:18:26 +0200 Subject: [PATCH 310/318] fix CI (#532) --- .github/workflows/deploy.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index 20545bc8d..10d2540a3 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -40,7 +40,7 @@ RELEASE_TAG_TEMPLATE = r"[vt]{1}\d{1,2}\.\d{1,2}\.\d{1,2}" docker_client = docker.APIClient() -NEON_TEST_IMAGE_NAME = f"{DOCKERHUB_ORG_NAME.lower()}/neon_tests" +NEON_TEST_IMAGE_NAME = "neon_tests" PROXY_ENDPOINT = os.environ.get("PROXY_ENDPOINT") NEON_TESTS_ENDPOINT = os.environ.get("NEON_TESTS_ENDPOINT") @@ -99,13 +99,13 @@ def specify_image_tags(git_ref, is_evm_release = False # test_image_tag - if evm_tag and is_image_exist("neon-tests", evm_tag): + if evm_tag and is_image_exist(NEON_TEST_IMAGE_NAME, evm_tag): neon_test_tag = evm_tag elif is_evm_release: neon_test_tag = re.sub(r'\.[0-9]*$', '.x', evm_tag) - if not is_image_exist("neon-tests", neon_test_tag): - raise RuntimeError(f"neon-tests image with {neon_test_tag} tag isn't found") - elif evm_pr_version_branch and is_image_exist("neon-tests", evm_pr_version_branch): + if not is_image_exist(NEON_TEST_IMAGE_NAME, neon_test_tag): + raise RuntimeError(f"{NEON_TEST_IMAGE_NAME} image with {neon_test_tag} tag isn't found") + elif evm_pr_version_branch and is_image_exist(NEON_TEST_IMAGE_NAME, evm_pr_version_branch): neon_test_tag = evm_pr_version_branch else: neon_test_tag = "latest" @@ -171,7 +171,7 @@ def run_subprocess(command): @click.option('--run_attempt') def run_tests(evm_sha_tag, neon_test_tag, run_number, run_attempt): os.environ["EVM_LOADER_IMAGE"] = f"{IMAGE_NAME}:{evm_sha_tag}" - os.environ["NEON_TESTS_IMAGE"] = f"{NEON_TEST_IMAGE_NAME}:{neon_test_tag}" + os.environ["NEON_TESTS_IMAGE"] = f"{DOCKERHUB_ORG_NAME}/{NEON_TEST_IMAGE_NAME}:{neon_test_tag}" project_name = f"neon-evm-{evm_sha_tag}-{run_number}-{run_attempt}" stop_containers(project_name) From 967644d27c864d4b5440af75bc2dec455d9c5dd9 Mon Sep 17 00:00:00 2001 From: iguberman Date: Mon, 2 Sep 2024 20:24:41 -0500 Subject: [PATCH 311/318] make TRACER_DB_TYPE env var optional and APIConfig db_config an option --- evm_loader/lib/src/abi/state.rs | 17 ++++++-- evm_loader/lib/src/config.rs | 23 ++++++----- evm_loader/lib/src/types/mod.rs | 15 ++++--- evm_loader/lib/src/types/no_db.rs | 65 ------------------------------- 4 files changed, 33 insertions(+), 87 deletions(-) delete mode 100644 evm_loader/lib/src/types/no_db.rs diff --git a/evm_loader/lib/src/abi/state.rs b/evm_loader/lib/src/abi/state.rs index 23fdae208..6509a6795 100644 --- a/evm_loader/lib/src/abi/state.rs +++ b/evm_loader/lib/src/abi/state.rs @@ -4,17 +4,19 @@ use crate::types::TracerDbType; use crate::NeonError; pub struct State { - pub tracer_db: TracerDbType, + pub tracer_db: Option, pub rpc_client: CloneRpcClient, + // TODO: Where is this used other than new? Do we need this as field pub config: APIOptions, } impl State { #[must_use] pub async fn new(config: APIOptions) -> Self { - let tracer_db = TracerDbType::from_config(&config.db_config).await; + // let tracer_db = TracerDbType::maybe_from_config(&config.db_config).await; + Self { - tracer_db, + tracer_db: TracerDbType::maybe_from_config(&config.db_config).await, rpc_client: CloneRpcClient::new_from_api_config(&config), config, } @@ -27,7 +29,14 @@ impl State { ) -> Result { Ok(if let Some(slot) = slot { RpcEnum::CallDbClient( - CallDbClient::new(self.tracer_db.clone(), slot, tx_index_in_block).await?, + CallDbClient::new( + self.tracer_db + .clone() + .expect("TracerDB must be configured for CallDbClient"), + slot, + tx_index_in_block, + ) + .await?, ) } else { RpcEnum::CloneRpcClient(self.rpc_client.clone()) diff --git a/evm_loader/lib/src/config.rs b/evm_loader/lib/src/config.rs index 8ff349e59..75d46f908 100644 --- a/evm_loader/lib/src/config.rs +++ b/evm_loader/lib/src/config.rs @@ -25,14 +25,13 @@ pub struct APIOptions { pub solana_max_retries: usize, pub evm_loader: Pubkey, pub key_for_config: Pubkey, - pub db_config: DbConfig, + pub db_config: Option, } #[derive(Serialize, Deserialize, Debug, Clone)] pub enum DbConfig { RocksDbConfig(RocksDbConfig), ChDbConfig(ChDbConfig), - NoDbConfig(NoDbConfig), } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct ChDbConfig { @@ -47,9 +46,6 @@ pub struct RocksDbConfig { pub rocksdb_port: u16, } -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct NoDbConfig {} - /// # Errors #[must_use] pub fn load_api_config_from_environment() -> APIOptions { @@ -99,18 +95,21 @@ pub fn load_api_config_from_environment() -> APIOptions { } #[must_use] -pub fn load_db_config_from_environment() -> DbConfig { - env::var("TRACER_DB_TYPE") +pub fn load_db_config_from_environment() -> Option { + if let Some(var) = env::var("TRACER_DB_TYPE") .ok() - .and_then(|db_type| match db_type.to_lowercase().as_str() { + .map(|var| var.to_lowercase()) + { + match var.as_str() { "rocksdb" => Some(DbConfig::RocksDbConfig( load_rocks_db_config_from_environment(), )), "clickhouse" => Some(DbConfig::ChDbConfig(load_ch_db_config_from_environment())), - "none" => Some(DbConfig::NoDbConfig(NoDbConfig {})), - _ => None, - }) - .expect("TRACER_DB_TYPE variable must be either 'clickhouse', 'rocksdb', or 'none'") + _ => panic!("TRACER_DB_TYPE env var must be either 'clickhouse' or 'rocksdb'"), + } + } else { + None + } } pub fn load_ch_db_config_from_environment() -> ChDbConfig { diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index a2314f0f5..6641fb1d9 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -1,13 +1,11 @@ pub mod tracer_ch_common; -pub mod no_db; pub(crate) mod tracer_ch_db; pub mod tracer_rocks_db; use crate::commands::get_config::ChainInfo; use crate::config::DbConfig; use crate::tracing::TraceCallConfig; -pub use crate::types::no_db::NoDb; use crate::types::tracer_ch_common::{EthSyncStatus, RevisionMap}; pub use crate::types::tracer_ch_db::ClickHouseDb; pub use crate::types::tracer_rocks_db::RocksDb; @@ -30,7 +28,7 @@ use serde_with::{hex::Hex, serde_as, DisplayFromStr, OneOrMany}; use solana_sdk::signature::Signature; use solana_sdk::{account::Account, pubkey::Pubkey}; use std::collections::HashMap; -use DbConfig::{ChDbConfig, NoDbConfig, RocksDbConfig}; +use DbConfig::{ChDbConfig, RocksDbConfig}; pub type DbResult = Result; @@ -38,7 +36,6 @@ pub type DbResult = Result; pub enum TracerDbType { ClickHouseDb, RocksDb, - NoDb, } impl TracerDbType { @@ -46,7 +43,14 @@ impl TracerDbType { match db_config { RocksDbConfig(rocks_db_config) => RocksDb::new(rocks_db_config).await.into(), ChDbConfig(ch_db_config) => ClickHouseDb::new(ch_db_config).into(), - NoDbConfig(..) => NoDb::default().into(), + } + } + + pub async fn maybe_from_config(maybe_db_config: &Option) -> Option { + if let Some(db_config) = maybe_db_config { + Some(Self::from_config(&db_config).await) + } else { + None } } } @@ -56,7 +60,6 @@ impl Clone for TracerDbType { match self { Self::RocksDb(r) => r.clone().into(), Self::ClickHouseDb(c) => c.clone().into(), - Self::NoDb(n) => n.clone().into(), } } } diff --git a/evm_loader/lib/src/types/no_db.rs b/evm_loader/lib/src/types/no_db.rs deleted file mode 100644 index 17fce4f59..000000000 --- a/evm_loader/lib/src/types/no_db.rs +++ /dev/null @@ -1,65 +0,0 @@ -use super::tracer_ch_common::{EthSyncStatus, RevisionMap}; -use crate::types::{DbResult, TracerDb}; -use async_trait::async_trait; -use solana_sdk::signature::Signature; -use solana_sdk::{ - account::Account, - clock::{Slot, UnixTimestamp}, - pubkey::Pubkey, -}; -#[derive(Clone, Debug, Default)] -pub struct NoDb {} - -#[async_trait] -impl TracerDb for NoDb { - async fn get_block_time(&self, slot: Slot) -> DbResult { - Err(anyhow::anyhow!( - "No DB configured for get_block_time({slot})" - )) - } - - async fn get_earliest_rooted_slot(&self) -> DbResult { - Err(anyhow::anyhow!( - "No DB configured for get_earliest_rooted_slot" - )) - } - - async fn get_latest_block(&self) -> DbResult { - Err(anyhow::anyhow!("No DB configured for get_latest_block")) - } - - async fn get_account_at( - &self, - _pubkey: &Pubkey, - slot: u64, - _tx_index_in_block: Option, - ) -> DbResult> { - Err(anyhow::anyhow!( - "No DB configured for get_account_at slot {slot}" - )) - } - - async fn get_transaction_index(&self, _signature: Signature) -> DbResult { - Err(anyhow::anyhow!("No DB configured to get_transaction_index")) - } - - async fn get_neon_revisions(&self, _pubkey: &Pubkey) -> DbResult { - Err(anyhow::anyhow!( - "No DB configured to get_neon_revisions for pubkey" - )) - } - - async fn get_neon_revision(&self, slot: Slot, _pubkey: &Pubkey) -> DbResult { - Err(anyhow::anyhow!( - "No DB configured to get_neon_revisions for slot {slot}" - )) - } - - async fn get_slot_by_blockhash(&self, _blockhash: String) -> DbResult { - Err(anyhow::anyhow!("No DB configured to get_slot_by_blockhash")) - } - - async fn get_sync_status(&self) -> DbResult { - Err(anyhow::anyhow!("No DB configured to get_sync_status")) - } -} From 0f0002432f894225025638df03f58443c789b49d Mon Sep 17 00:00:00 2001 From: iguberman Date: Mon, 2 Sep 2024 21:02:19 -0500 Subject: [PATCH 312/318] fix clippy errors --- evm_loader/lib/src/config.rs | 11 +++-------- evm_loader/lib/src/types/mod.rs | 2 +- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/evm_loader/lib/src/config.rs b/evm_loader/lib/src/config.rs index 75d46f908..3c4fbffc2 100644 --- a/evm_loader/lib/src/config.rs +++ b/evm_loader/lib/src/config.rs @@ -96,20 +96,15 @@ pub fn load_api_config_from_environment() -> APIOptions { #[must_use] pub fn load_db_config_from_environment() -> Option { - if let Some(var) = env::var("TRACER_DB_TYPE") + env::var("TRACER_DB_TYPE") .ok() - .map(|var| var.to_lowercase()) - { - match var.as_str() { + .map(|var| match var.to_lowercase().as_str() { "rocksdb" => Some(DbConfig::RocksDbConfig( load_rocks_db_config_from_environment(), )), "clickhouse" => Some(DbConfig::ChDbConfig(load_ch_db_config_from_environment())), _ => panic!("TRACER_DB_TYPE env var must be either 'clickhouse' or 'rocksdb'"), - } - } else { - None - } + })? } pub fn load_ch_db_config_from_environment() -> ChDbConfig { diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index 6641fb1d9..114c10352 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -48,7 +48,7 @@ impl TracerDbType { pub async fn maybe_from_config(maybe_db_config: &Option) -> Option { if let Some(db_config) = maybe_db_config { - Some(Self::from_config(&db_config).await) + Some(Self::from_config(db_config).await) } else { None } From c91bfa3a7898e9f4cd5aafe0d7b608a42cf9d6c9 Mon Sep 17 00:00:00 2001 From: iguberman Date: Mon, 2 Sep 2024 22:40:41 -0500 Subject: [PATCH 313/318] add support for "none" TRACER_DB_TYPE --- evm_loader/lib/src/config.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/evm_loader/lib/src/config.rs b/evm_loader/lib/src/config.rs index 3c4fbffc2..1f648c222 100644 --- a/evm_loader/lib/src/config.rs +++ b/evm_loader/lib/src/config.rs @@ -103,7 +103,8 @@ pub fn load_db_config_from_environment() -> Option { load_rocks_db_config_from_environment(), )), "clickhouse" => Some(DbConfig::ChDbConfig(load_ch_db_config_from_environment())), - _ => panic!("TRACER_DB_TYPE env var must be either 'clickhouse' or 'rocksdb'"), + "none" => None, + _ => panic!("TRACER_DB_TYPE env var must be either 'clickhouse', 'rocksdb', or 'none'"), })? } From 91de02c0ece7017c1a0c006879f8da1b09669d01 Mon Sep 17 00:00:00 2001 From: iguberman Date: Mon, 2 Sep 2024 23:39:33 -0500 Subject: [PATCH 314/318] Address PR comments --- Dockerfile | 2 -- evm_loader/lib/src/errors.rs | 1 - 2 files changed, 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index c653f30e9..b82ac9665 100644 --- a/Dockerfile +++ b/Dockerfile @@ -63,7 +63,5 @@ COPY ci/operator-keypairs/id2.json /root/.config/solana/id2.json COPY ci/keys/ /opt/keys ENV PATH=${PATH}:/opt -ENV ROCKSDB_HOST=${ROCKSDB_HOST} -ENV ROCKSDB_PORT=${ROCKSDB_PORT} ENTRYPOINT [ "/opt/solana-run-neon.sh" ] diff --git a/evm_loader/lib/src/errors.rs b/evm_loader/lib/src/errors.rs index aab10182d..996db22ea 100644 --- a/evm_loader/lib/src/errors.rs +++ b/evm_loader/lib/src/errors.rs @@ -98,7 +98,6 @@ pub enum NeonError { Panic(String), #[error("ClickHouse: {0}")] ClickHouse(ChError), - // TODO from rocksdb::Error #[error("RocksDbError {0}")] RocksDb(anyhow::Error), #[error("Slot {0} is less than earliest_rooted_slot={1}")] From cefae97eeb00c08c0aa483f80c2ba1b3cd44a054 Mon Sep 17 00:00:00 2001 From: Kristina Nikolaeva <112946046+kristinaNikolaevaa@users.noreply.github.com> Date: Tue, 3 Sep 2024 15:06:16 +0200 Subject: [PATCH 315/318] fix deploy.py script for manual run (#537) * fix deploy.py script for manual run * fix organization name in image name --- .github/workflows/deploy.py | 21 +++++++++++---------- .github/workflows/pipeline.yml | 1 - .github/workflows/requirements.txt | 3 +++ 3 files changed, 14 insertions(+), 11 deletions(-) create mode 100644 .github/workflows/requirements.txt diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index 10d2540a3..40f5a5d7e 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -30,7 +30,7 @@ DOCKER_USER = os.environ.get("DHUBU") DOCKER_PASSWORD = os.environ.get("DHUBP") -IMAGE_NAME = os.environ.get("IMAGE_NAME") +IMAGE_NAME = os.environ.get("IMAGE_NAME", "evm_loader") RUN_LINK_REPO = os.environ.get("RUN_LINK_REPO") DOCKERHUB_ORG_NAME = os.environ.get("DOCKERHUB_ORG_NAME") SOLANA_NODE_VERSION = 'v1.18.18' @@ -126,7 +126,7 @@ def build_docker_image(evm_sha_tag): "SOLANA_IMAGE": solana_image, "SOLANA_BPF_VERSION": SOLANA_BPF_VERSION} - tag = f"{IMAGE_NAME}:{evm_sha_tag}" + tag = f"{DOCKERHUB_ORG_NAME}/{IMAGE_NAME}:{evm_sha_tag}" click.echo("start build") output = docker_client.build(tag=tag, buildargs=buildargs, path="./", decode=True) process_output(output) @@ -153,9 +153,10 @@ def finalize_image(evm_sha_tag, evm_tag): def push_image_with_tag(sha, tag): + image = f"{DOCKERHUB_ORG_NAME}/{IMAGE_NAME}" docker_client.login(username=DOCKER_USER, password=DOCKER_PASSWORD) - docker_client.tag(f"{IMAGE_NAME}:{sha}", f"{IMAGE_NAME}:{tag}") - out = docker_client.push(f"{IMAGE_NAME}:{tag}", decode=True, stream=True) + docker_client.tag(f"{image}:{sha}", f"{image}:{tag}") + out = docker_client.push(f"{image}:{tag}", decode=True, stream=True) process_output(out) @@ -167,10 +168,10 @@ def run_subprocess(command): @cli.command(name="run_tests") @click.option('--evm_sha_tag') @click.option('--neon_test_tag') -@click.option('--run_number') -@click.option('--run_attempt') +@click.option('--run_number', default=1) +@click.option('--run_attempt', default=1) def run_tests(evm_sha_tag, neon_test_tag, run_number, run_attempt): - os.environ["EVM_LOADER_IMAGE"] = f"{IMAGE_NAME}:{evm_sha_tag}" + os.environ["EVM_LOADER_IMAGE"] = f"{DOCKERHUB_ORG_NAME}/{IMAGE_NAME}:{evm_sha_tag}" os.environ["NEON_TESTS_IMAGE"] = f"{DOCKERHUB_ORG_NAME}/{NEON_TEST_IMAGE_NAME}:{neon_test_tag}" project_name = f"neon-evm-{evm_sha_tag}-{run_number}-{run_attempt}" stop_containers(project_name) @@ -180,6 +181,7 @@ def run_tests(evm_sha_tag, neon_test_tag, run_number, run_attempt): test_container_name = get_container_name(project_name, "tests") click.echo("Start tests") + print(test_container_name) exec_id = docker_client.exec_create( container=test_container_name, cmd="python3 clickfile.py run evm --numprocesses 8 --network docker_net") logs = docker_client.exec_start(exec_id['Id'], stream=True) @@ -190,7 +192,7 @@ def run_tests(evm_sha_tag, neon_test_tag, run_number, run_attempt): current_line = line.decode('utf-8') all_logs += current_line click.echo(current_line) - if 'ERROR ' in current_line or 'FAILED ' in current_line: + if 'ERROR ' in current_line or 'FAILED ' in current_line or 'Error: ' in current_line: tests_are_failed = True print("Tests are failed") @@ -209,8 +211,7 @@ def get_container_name(project_name, service_name): f"docker-compose -p {project_name} -f ./ci/docker-compose-ci.yml ps", shell=True, capture_output=True, text=True).stdout click.echo(data) - pattern = rf'{project_name}_{service_name}_[1-9]+' - + pattern = rf'{project_name}[-_]{service_name}[-_]1' match = re.search(pattern, data) return match.group(0) diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index 61d426606..ccc528447 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -13,7 +13,6 @@ on: env: DHUBU: ${{secrets.DHUBU}} DHUBP: ${{secrets.DHUBP}} - IMAGE_NAME: ${{vars.IMAGE_NAME}} PROXY_ENDPOINT: "https://api.github.com/repos/neonlabsorg/neon-proxy.py" NEON_TESTS_ENDPOINT: ${{vars.NEON_TESTS_ENDPOINT}} DOCKERHUB_ORG_NAME: ${{vars.DOCKERHUB_ORG_NAME}} diff --git a/.github/workflows/requirements.txt b/.github/workflows/requirements.txt new file mode 100644 index 000000000..1a3655d55 --- /dev/null +++ b/.github/workflows/requirements.txt @@ -0,0 +1,3 @@ +docker==7.1.0 +requests==2.31.0 +click==8.1.3 \ No newline at end of file From ae50b8772d9a87da36312f96f3e38ce7881d26c0 Mon Sep 17 00:00:00 2001 From: ancientmage Date: Tue, 3 Sep 2024 17:09:17 +0200 Subject: [PATCH 316/318] NDEV-3265. Fix /api/emulate failed with precompiled contracts (#529) --- evm_loader/program/src/evm/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/evm_loader/program/src/evm/mod.rs b/evm_loader/program/src/evm/mod.rs index ad4f50fca..f81fe808a 100644 --- a/evm_loader/program/src/evm/mod.rs +++ b/evm_loader/program/src/evm/mod.rs @@ -370,6 +370,7 @@ impl Machine { let value = Self::precompile(&self.context.contract, &self.call_data).unwrap(); backend.commit_snapshot(); + end_vm!(self, backend, ExitStatus::Return(value.clone())); ExitStatus::Return(value) } else { loop { From db3dc4af1804e461735d2121d47647ac43a01b6d Mon Sep 17 00:00:00 2001 From: s-medvedev <40623263+s-medvedev@users.noreply.github.com> Date: Tue, 3 Sep 2024 23:03:30 +0700 Subject: [PATCH 317/318] NDEV-3050 Small fixes (#539) Co-authored-by: Semen Medvedev --- evm_loader/cli/src/main.rs | 13 ++++++------- evm_loader/lib/src/abi/mod.rs | 4 ++-- evm_loader/lib/src/abi/state.rs | 9 +++------ evm_loader/lib/src/rpc/db_call_client.rs | 6 +++--- evm_loader/lib/src/types/mod.rs | 10 +++++----- evm_loader/lib/src/types/tracer_ch_db.rs | 6 ++---- evm_loader/lib/src/types/tracer_rocks_db.rs | 6 +++--- 7 files changed, 24 insertions(+), 30 deletions(-) diff --git a/evm_loader/cli/src/main.rs b/evm_loader/cli/src/main.rs index 68cb20995..95db4f099 100644 --- a/evm_loader/cli/src/main.rs +++ b/evm_loader/cli/src/main.rs @@ -32,7 +32,7 @@ use evm_loader::types::Address; use neon_lib::errors::NeonError; use neon_lib::rpc::{CallDbClient, RpcEnum}; use neon_lib::tracing::tracers::TracerTypeEnum; -use neon_lib::types::TracerDbType; +use neon_lib::types::TracerDb; use solana_clap_utils::keypair::signer_from_path; use solana_sdk::signature::Signer; @@ -154,13 +154,12 @@ async fn build_rpc(options: &ArgMatches<'_>, config: &Config) -> Result State { +pub fn init_state_sync() -> State { tokio::runtime::Runtime::new() .unwrap() .block_on(async { State::new(load_config()).await }) diff --git a/evm_loader/lib/src/abi/state.rs b/evm_loader/lib/src/abi/state.rs index 6509a6795..9bf0d25ea 100644 --- a/evm_loader/lib/src/abi/state.rs +++ b/evm_loader/lib/src/abi/state.rs @@ -1,22 +1,19 @@ use crate::config::APIOptions; use crate::rpc::{CallDbClient, CloneRpcClient, RpcEnum}; -use crate::types::TracerDbType; +use crate::types::TracerDb; use crate::NeonError; pub struct State { - pub tracer_db: Option, + pub tracer_db: Option, pub rpc_client: CloneRpcClient, - // TODO: Where is this used other than new? Do we need this as field pub config: APIOptions, } impl State { #[must_use] pub async fn new(config: APIOptions) -> Self { - // let tracer_db = TracerDbType::maybe_from_config(&config.db_config).await; - Self { - tracer_db: TracerDbType::maybe_from_config(&config.db_config).await, + tracer_db: TracerDb::maybe_from_config(&config.db_config).await, rpc_client: CloneRpcClient::new_from_api_config(&config), config, } diff --git a/evm_loader/lib/src/rpc/db_call_client.rs b/evm_loader/lib/src/rpc/db_call_client.rs index 56f2f133d..32e97b9d5 100644 --- a/evm_loader/lib/src/rpc/db_call_client.rs +++ b/evm_loader/lib/src/rpc/db_call_client.rs @@ -1,5 +1,5 @@ use super::{e, Rpc}; -use crate::types::{TracerDb, TracerDbType}; +use crate::types::{TracerDb, TracerDbTrait}; use crate::NeonError; use crate::NeonError::RocksDb; use async_trait::async_trait; @@ -15,14 +15,14 @@ use solana_sdk::{ }; pub struct CallDbClient { - tracer_db: TracerDbType, + tracer_db: TracerDb, slot: u64, tx_index_in_block: Option, } impl CallDbClient { pub async fn new( - tracer_db: TracerDbType, + tracer_db: TracerDb, slot: u64, tx_index_in_block: Option, ) -> Result { diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index 114c10352..5ecdf782e 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -33,12 +33,12 @@ use DbConfig::{ChDbConfig, RocksDbConfig}; pub type DbResult = Result; #[enum_dispatch] -pub enum TracerDbType { +pub enum TracerDb { ClickHouseDb, RocksDb, } -impl TracerDbType { +impl TracerDb { pub async fn from_config(db_config: &DbConfig) -> Self { match db_config { RocksDbConfig(rocks_db_config) => RocksDb::new(rocks_db_config).await.into(), @@ -55,7 +55,7 @@ impl TracerDbType { } } -impl Clone for TracerDbType { +impl Clone for TracerDb { fn clone(&self) -> Self { match self { Self::RocksDb(r) => r.clone().into(), @@ -65,8 +65,8 @@ impl Clone for TracerDbType { } #[async_trait] -#[enum_dispatch(TracerDbType)] -pub trait TracerDb { +#[enum_dispatch(TracerDb)] +pub trait TracerDbTrait { async fn get_block_time(&self, slot: Slot) -> DbResult; async fn get_earliest_rooted_slot(&self) -> DbResult; diff --git a/evm_loader/lib/src/types/tracer_ch_db.rs b/evm_loader/lib/src/types/tracer_ch_db.rs index 40f8bbc97..0d5239d67 100644 --- a/evm_loader/lib/src/types/tracer_ch_db.rs +++ b/evm_loader/lib/src/types/tracer_ch_db.rs @@ -1,8 +1,7 @@ -#![allow(dead_code)] use crate::{ commands::get_neon_elf::get_elf_parameter, types::tracer_ch_common::{AccountRow, ChError, RevisionRow, SlotParent, ROOT_BLOCK_DELAY}, - types::{DbResult, TracerDb}, + types::{DbResult, TracerDbTrait}, }; use super::tracer_ch_common::{ChResult, EthSyncStatus, EthSyncing, RevisionMap, SlotParentRooted}; @@ -33,9 +32,8 @@ pub struct ClickHouseDb { pub client: Client, } -#[allow(dead_code)] #[async_trait] -impl TracerDb for ClickHouseDb { +impl TracerDbTrait for ClickHouseDb { // Returned value is not used for tracer methods. async fn get_block_time(&self, slot: Slot) -> DbResult { let time_start = Instant::now(); diff --git a/evm_loader/lib/src/types/tracer_rocks_db.rs b/evm_loader/lib/src/types/tracer_rocks_db.rs index f0f621790..be88513fb 100644 --- a/evm_loader/lib/src/types/tracer_rocks_db.rs +++ b/evm_loader/lib/src/types/tracer_rocks_db.rs @@ -24,7 +24,7 @@ pub struct AccountParams { } use crate::types::tracer_ch_common::{EthSyncStatus, RevisionMap}; -use crate::types::{DbResult, TracerDb}; +use crate::types::{DbResult, TracerDbTrait}; // use reconnecting_jsonrpsee_ws_client::{Client, CallRetryPolicy, rpc_params, ExponentialBackoff}; #[derive(Clone, Debug)] pub struct RocksDb { @@ -51,13 +51,13 @@ impl RocksDb { tracing::info!("Created rocksdb client at {url}"); Self { url, client: arc_c } } - Err(e) => panic!("Couln't start rocksDb client at {url}: {e}"), + Err(e) => panic!("Couldn't start rocksDb client at {url}: {e}"), } } } #[async_trait] -impl TracerDb for RocksDb { +impl TracerDbTrait for RocksDb { async fn get_block_time(&self, slot: Slot) -> DbResult { let response: String = self .client From f99a3ceecb50e3d16368e76d56a4f75bc92b31e7 Mon Sep 17 00:00:00 2001 From: iguberman Date: Tue, 3 Sep 2024 23:39:03 -0500 Subject: [PATCH 318/318] add get_accounts_in_transaction method --- evm_loader/lib/src/types/mod.rs | 7 +++ evm_loader/lib/src/types/tracer_ch_db.rs | 70 +++++++++++---------- evm_loader/lib/src/types/tracer_rocks_db.rs | 10 +++ 3 files changed, 55 insertions(+), 32 deletions(-) diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index 5ecdf782e..c7787274d 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -3,6 +3,7 @@ pub mod tracer_ch_common; pub(crate) mod tracer_ch_db; pub mod tracer_rocks_db; +use crate::account_data::AccountData; use crate::commands::get_config::ChainInfo; use crate::config::DbConfig; use crate::tracing::TraceCallConfig; @@ -89,6 +90,12 @@ pub trait TracerDbTrait { async fn get_slot_by_blockhash(&self, blockhash: String) -> DbResult; async fn get_sync_status(&self) -> DbResult; + + async fn get_accounts_in_transaction( + &self, + sol_sig: &[u8], + slot: u64, + ) -> DbResult>; } #[serde_as] diff --git a/evm_loader/lib/src/types/tracer_ch_db.rs b/evm_loader/lib/src/types/tracer_ch_db.rs index 0d5239d67..15dddd982 100644 --- a/evm_loader/lib/src/types/tracer_ch_db.rs +++ b/evm_loader/lib/src/types/tracer_ch_db.rs @@ -264,6 +264,44 @@ impl TracerDbTrait for ClickHouseDb { Ok(EthSyncStatus::new(None)) } + + async fn get_accounts_in_transaction( + &self, + sol_sig: &[u8], + slot: u64, + ) -> DbResult> { + info!("get_accounts_in_transaction {{signature: {sol_sig:?} }}"); + + let query = r" + SELECT DISTINCT ON (pubkey) + pubkey, owner, lamports, executable, rent_epoch, data, txn_signature + FROM events.update_account_distributed + WHERE txn_signature = ? + AND slot = ? + ORDER BY write_version DESC + "; + + let rows = self + .client + .query(query) + .bind(sol_sig) + .bind(slot) + .fetch_all::() + .await?; + + let mut accounts: Vec = Vec::new(); + + for row in rows { + let account_data = row.try_into().map_err(|e| { + anyhow!(ChError::Db(clickhouse::error::Error::Custom(format!( + "get_accounts_in_transaction: Failed to convert row to AccountData, error: {e}", + )))) + })?; + accounts.push(account_data); + } + + Ok(accounts) + } } impl ClickHouseDb { @@ -528,38 +566,6 @@ impl ClickHouseDb { Ok(account) } - pub async fn get_accounts_in_transaction( - &self, - sol_sig: &[u8], - slot: u64, - ) -> ChResult> { - info!("get_accounts_in_transaction {{signature: {sol_sig:?} }}"); - - let query = r" - SELECT DISTINCT ON (pubkey) - pubkey, owner, lamports, executable, rent_epoch, data, txn_signature - FROM events.update_account_distributed - WHERE txn_signature = ? - AND slot = ? - ORDER BY write_version DESC - "; - - let rows = self - .client - .query(query) - .bind(sol_sig) - .bind(slot) - .fetch_all::() - .await?; - - rows.into_iter() - .map(|row: AccountRow| { - row.try_into() - .map_err(|err| ChError::Db(clickhouse::error::Error::Custom(err))) - }) - .collect() - } - async fn get_older_account_row_at( &self, pubkey: &str, diff --git a/evm_loader/lib/src/types/tracer_rocks_db.rs b/evm_loader/lib/src/types/tracer_rocks_db.rs index be88513fb..d36fb5218 100644 --- a/evm_loader/lib/src/types/tracer_rocks_db.rs +++ b/evm_loader/lib/src/types/tracer_rocks_db.rs @@ -1,3 +1,4 @@ +use crate::account_data::AccountData; use crate::config::RocksDbConfig; use async_trait::async_trait; use jsonrpsee::core::client::ClientT; @@ -149,4 +150,13 @@ impl TracerDbTrait for RocksDb { async fn get_sync_status(&self) -> DbResult { Ok(EthSyncStatus::new(None)) } + + async fn get_accounts_in_transaction( + &self, + _sol_sig: &[u8], + _slot: u64, + ) -> DbResult> { + // TODO implement + Ok(Vec::new()) + } }

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 Iy862T0PuTkL;wH) literal 0 HcmV?d00001 From 95d5c757d01468a9985daa53eac5f5a27aa882b2 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Fri, 15 Sep 2023 12:07:22 +0300 Subject: [PATCH 024/318] NDEV-2184: Report error when requested too early slot (#195) * Remove #[allow(dead_code)] * NDEV-2184: Report error when requested too early slot --- .../api/src/api_server/handlers/emulate.rs | 2 +- .../handlers/get_ether_account_data.rs | 2 +- .../src/api_server/handlers/get_storage_at.rs | 2 +- evm_loader/api/src/api_server/handlers/mod.rs | 2 ++ .../api/src/api_server/handlers/trace.rs | 2 +- .../api_server/handlers/trace_next_block.rs | 4 ++-- evm_loader/cli/src/context.rs | 11 +++++++---- evm_loader/lib/src/context.rs | 11 +++++++---- evm_loader/lib/src/errors.rs | 12 +++++++++--- evm_loader/lib/src/rpc/db_call_client.rs | 16 +++++++++++++--- evm_loader/lib/src/types/tracer_ch_db.rs | 18 +++++++++++++++++- 11 files changed, 61 insertions(+), 21 deletions(-) diff --git a/evm_loader/api/src/api_server/handlers/emulate.rs b/evm_loader/api/src/api_server/handlers/emulate.rs index 962cdaa20..84d5d89f5 100644 --- a/evm_loader/api/src/api_server/handlers/emulate.rs +++ b/evm_loader/api/src/api_server/handlers/emulate.rs @@ -15,7 +15,7 @@ pub async fn emulate( ) -> (StatusCode, Json) { let tx = emulate_request.tx_params.into(); - let rpc_client = match context::build_rpc_client(&state.config, emulate_request.slot) { + let rpc_client = match context::build_rpc_client(&state.config, emulate_request.slot).await { Ok(rpc_client) => rpc_client, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; diff --git a/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs b/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs index 2ab577298..d26a02c73 100644 --- a/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs +++ b/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs @@ -14,7 +14,7 @@ pub async fn get_ether_account_data( Query(req_params): Query, State(state): State, ) -> (StatusCode, Json) { - let rpc_client = match context::build_rpc_client(&state.config, req_params.slot) { + let rpc_client = match context::build_rpc_client(&state.config, req_params.slot).await { Ok(rpc_client) => rpc_client, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; diff --git a/evm_loader/api/src/api_server/handlers/get_storage_at.rs b/evm_loader/api/src/api_server/handlers/get_storage_at.rs index 57559cc4f..2ebb11e33 100644 --- a/evm_loader/api/src/api_server/handlers/get_storage_at.rs +++ b/evm_loader/api/src/api_server/handlers/get_storage_at.rs @@ -15,7 +15,7 @@ pub async fn get_storage_at( Query(req_params): Query, State(state): State, ) -> (StatusCode, Json) { - let rpc_client = match context::build_rpc_client(&state.config, req_params.slot) { + let rpc_client = match context::build_rpc_client(&state.config, req_params.slot).await { Ok(rpc_client) => rpc_client, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; diff --git a/evm_loader/api/src/api_server/handlers/mod.rs b/evm_loader/api/src/api_server/handlers/mod.rs index 6ba074f6c..9887388d7 100644 --- a/evm_loader/api/src/api_server/handlers/mod.rs +++ b/evm_loader/api/src/api_server/handlers/mod.rs @@ -14,6 +14,7 @@ use crate::{Config, Context, NeonApiResult}; use crate::types::request_models::EmulationParamsRequestModel; use std::net::AddrParseError; use std::str::FromStr; +use tracing::error; pub mod emulate; pub mod emulate_hash; @@ -133,6 +134,7 @@ fn process_result( } fn process_error(status_code: StatusCode, e: &NeonError) -> (StatusCode, Json) { + error!("NeonError: {e}"); ( status_code, Json(json!({ diff --git a/evm_loader/api/src/api_server/handlers/trace.rs b/evm_loader/api/src/api_server/handlers/trace.rs index 06cb4974e..1c792f775 100644 --- a/evm_loader/api/src/api_server/handlers/trace.rs +++ b/evm_loader/api/src/api_server/handlers/trace.rs @@ -14,7 +14,7 @@ pub async fn trace( let tx = trace_request.emulate_request.tx_params.into(); let rpc_client = - match context::build_rpc_client(&state.config, trace_request.emulate_request.slot) { + match context::build_rpc_client(&state.config, trace_request.emulate_request.slot).await { Ok(rpc_client) => rpc_client, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; diff --git a/evm_loader/api/src/api_server/handlers/trace_next_block.rs b/evm_loader/api/src/api_server/handlers/trace_next_block.rs index 67d483ec4..454d867ee 100644 --- a/evm_loader/api/src/api_server/handlers/trace_next_block.rs +++ b/evm_loader/api/src/api_server/handlers/trace_next_block.rs @@ -17,7 +17,7 @@ pub async fn trace_next_block( Json(trace_next_block_request): Json, ) -> (StatusCode, Json) { let rpc_client = - match context::build_call_db_client(&state.config, trace_next_block_request.slot) { + match context::build_call_db_client(&state.config, trace_next_block_request.slot).await { Ok(rpc_client) => rpc_client, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; @@ -49,7 +49,7 @@ pub async fn trace_next_block( Err(e) => { return process_error( StatusCode::INTERNAL_SERVER_ERROR, - &errors::NeonError::PostgreError(e), + &errors::NeonError::PostgresError(e), ) } }; diff --git a/evm_loader/cli/src/context.rs b/evm_loader/cli/src/context.rs index 2933f5ca8..eb7cecc59 100644 --- a/evm_loader/cli/src/context.rs +++ b/evm_loader/cli/src/context.rs @@ -34,10 +34,13 @@ pub async fn create_from_config_and_options<'a>( } _ => { if let Some(slot) = slot { - Arc::new(CallDbClient::new( - config.db_config.as_ref().expect("db-config not found"), - *slot, - )) + Arc::new( + CallDbClient::new( + config.db_config.as_ref().expect("db-config not found"), + *slot, + ) + .await?, + ) } else { Arc::new(RpcClient::new_with_commitment( config.json_rpc_url.clone(), diff --git a/evm_loader/lib/src/context.rs b/evm_loader/lib/src/context.rs index d9ff8f729..2eb38090c 100644 --- a/evm_loader/lib/src/context.rs +++ b/evm_loader/lib/src/context.rs @@ -69,12 +69,12 @@ pub fn build_signer(config: &Config) -> Result, NeonError> { } /// # Errors -pub fn build_rpc_client( +pub async fn build_rpc_client( config: &Config, slot: Option, ) -> Result, NeonError> { if let Some(slot) = slot { - return build_call_db_client(config, slot); + return build_call_db_client(config, slot).await; } Ok(Arc::new(RpcClient::new_with_commitment( @@ -84,10 +84,13 @@ pub fn build_rpc_client( } /// # Errors -pub fn build_call_db_client(config: &Config, slot: u64) -> Result, NeonError> { +pub async fn build_call_db_client( + config: &Config, + slot: u64, +) -> Result, NeonError> { let config = config .db_config .clone() .ok_or(NeonError::InvalidChDbConfig)?; - Ok(Arc::new(CallDbClient::new(&config, slot))) + Ok(Arc::new(CallDbClient::new(&config, slot).await?)) } diff --git a/evm_loader/lib/src/errors.rs b/evm_loader/lib/src/errors.rs index 0ba461db0..207624186 100644 --- a/evm_loader/lib/src/errors.rs +++ b/evm_loader/lib/src/errors.rs @@ -13,7 +13,7 @@ use solana_sdk::signer::SignerError as SolanaSignerError; use thiserror::Error; use crate::commands::init_environment::EnvironmentError; -use crate::types::PgError; +use crate::types::{ChError, PgError}; /// Errors that may be returned by the neon-cli program. #[derive(Debug, Error)] @@ -94,9 +94,13 @@ pub enum NeonError { #[error("Hex Error. {0}")] FromHexError(#[from] hex::FromHexError), #[error("PostgreSQL Error: {0}")] - PostgreError(#[from] PgError), + PostgresError(#[from] PgError), #[error("Panic: {0}")] Panic(String), + #[error("ClickHouse: {0}")] + ClickHouse(ChError), + #[error("Slot {0} is less than earliest_rooted_slot={1}")] + EarlySlot(u64, u64), } impl NeonError { @@ -131,7 +135,9 @@ impl NeonError { NeonError::IncorrectAddress(_) => 248, NeonError::IncorrectIndex(_) => 249, NeonError::TxParametersParsingError(_) => 250, - NeonError::PostgreError(_) => 251, + NeonError::PostgresError(_) => 251, + NeonError::ClickHouse(_) => 252, + NeonError::EarlySlot(_, _) => 253, } } } diff --git a/evm_loader/lib/src/rpc/db_call_client.rs b/evm_loader/lib/src/rpc/db_call_client.rs index 2dc75e27d..7f54f5d19 100644 --- a/evm_loader/lib/src/rpc/db_call_client.rs +++ b/evm_loader/lib/src/rpc/db_call_client.rs @@ -1,5 +1,6 @@ use super::{e, Rpc}; use crate::types::{ChDbConfig, TracerDb, TxParams}; +use crate::NeonError; use async_trait::async_trait; use solana_client::{ client_error::Result as ClientResult, @@ -27,12 +28,21 @@ pub struct CallDbClient { } impl CallDbClient { - pub fn new(config: &ChDbConfig, slot: u64) -> Self { + pub async fn new(config: &ChDbConfig, slot: u64) -> Result { let db = TracerDb::new(config); - Self { + + let earliest_rooted_slot = db + .get_earliest_rooted_slot() + .await + .map_err(NeonError::ClickHouse)?; + if slot < earliest_rooted_slot { + return Err(NeonError::EarlySlot(slot, earliest_rooted_slot)); + } + + Ok(Self { slot, tracer_db: db, - } + }) } } diff --git a/evm_loader/lib/src/types/tracer_ch_db.rs b/evm_loader/lib/src/types/tracer_ch_db.rs index fce66629e..2b653c4f9 100644 --- a/evm_loader/lib/src/types/tracer_ch_db.rs +++ b/evm_loader/lib/src/types/tracer_ch_db.rs @@ -129,7 +129,6 @@ impl TryInto for AccountRow { } } -#[allow(dead_code)] impl ClickHouseDb { pub fn new(config: &ChDbConfig) -> Self { let url_id = rand::thread_rng().gen_range(0..config.clickhouse_url.len()); @@ -169,6 +168,23 @@ impl ClickHouseDb { result } + pub async fn get_earliest_rooted_slot(&self) -> ChResult { + let time_start = Instant::now(); + let query = "SELECT min(slot) FROM events.rooted_slots"; + let result = self + .client + .query(query) + .fetch_one::() + .await + .map_err(std::convert::Into::into); + let execution_time = Instant::now().duration_since(time_start); + info!( + "get_earliest_rooted_slot sql returned {result:?}, time: {} sec", + execution_time.as_secs_f64() + ); + result + } + pub async fn get_latest_block(&self) -> ChResult { let time_start = Instant::now(); let query = "SELECT max(slot) FROM events.update_slot"; From a30ebeccaef03c78a5b6343f9a1567fd27ad5005 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Fri, 15 Sep 2023 17:46:39 +0300 Subject: [PATCH 025/318] NDEV-2204: Use global RPC clients (#194) --- .github/workflows/deploy.py | 3 ++ .github/workflows/pipeline.yml | 1 + evm_loader/Cargo.lock | 2 + evm_loader/api/Cargo.toml | 2 + evm_loader/api/src/api_context.rs | 35 ++++++++++++++ .../api/src/api_server/handlers/emulate.rs | 9 ++-- .../src/api_server/handlers/emulate_hash.rs | 6 +-- .../handlers/get_ether_account_data.rs | 7 +-- .../src/api_server/handlers/get_storage_at.rs | 7 +-- .../api/src/api_server/handlers/trace.rs | 7 +-- .../api/src/api_server/handlers/trace_hash.rs | 6 +-- .../api_server/handlers/trace_next_block.rs | 21 ++------ evm_loader/api/src/api_server/routes.rs | 5 +- evm_loader/api/src/api_server/state.rs | 14 +++++- evm_loader/api/src/main.rs | 9 ++-- evm_loader/cli/src/context.rs | 7 ++- evm_loader/docker-compose-ci.yml | 2 +- evm_loader/lib/src/context.rs | 48 +------------------ evm_loader/lib/src/rpc/db_call_client.rs | 15 ++---- evm_loader/lib/src/rpc/db_trx_client.rs | 6 +-- evm_loader/lib/src/types/mod.rs | 12 +++-- 21 files changed, 113 insertions(+), 111 deletions(-) create mode 100644 evm_loader/api/src/api_context.rs diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index 08fdbd02d..ef369b528 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -126,6 +126,9 @@ def run_tests(github_sha): print("Part of tests are skipped") exec_status = docker_client.exec_inspect(exec_id['Id'])["ExitCode"] + + run_subprocess(f"docker-compose -p {project_name} -f ./evm_loader/docker-compose-ci.yml logs dk-neon-api") + stop_containers(project_name) if tests_are_failed or exec_status == 1: diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index ed3814394..be9045650 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -14,6 +14,7 @@ env: DHUBU: ${{secrets.DHUBU}} DHUBP: ${{secrets.DHUBP}} BUILD_URL: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + INDEXER_DB_PASSWORD: ${{secrets.INDEXER_DB_PASSWORD}} concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 59dc491d6..463995ff4 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -2202,11 +2202,13 @@ dependencies = [ "clap 2.34.0", "ethnum", "evm-loader", + "hex", "http", "hyper", "neon-lib", "serde", "serde_json", + "solana-client", "solana-sdk", "tokio", "tower", diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 84980e74c..18dca2e18 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -9,6 +9,7 @@ edition = "2021" clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } solana-sdk = "=1.14.20" +solana-client = "=1.14.20" serde = "1.0.186" serde_json = "1.0.85" ethnum = { version = "1.4", default-features = false, features = ["serde"] } @@ -23,3 +24,4 @@ tower-request-id = "0.2.1" http = "0.2.9" hyper = "0.14.27" tower-http = { version = "0.4.4", features = ["trace"] } +hex = "0.4.2" diff --git a/evm_loader/api/src/api_context.rs b/evm_loader/api/src/api_context.rs new file mode 100644 index 000000000..4cb3b81fc --- /dev/null +++ b/evm_loader/api/src/api_context.rs @@ -0,0 +1,35 @@ +use crate::NeonApiState; +use hex::FromHex; +use neon_lib::rpc::{CallDbClient, TrxDbClient}; +use neon_lib::{context, rpc, NeonError}; +use std::sync::Arc; + +pub async fn build_rpc_client( + state: &NeonApiState, + slot: Option, +) -> Result, NeonError> { + if let Some(slot) = slot { + return build_call_db_client(state, slot).await; + } + + Ok(state.rpc_client.clone()) +} + +pub async fn build_call_db_client( + state: &NeonApiState, + slot: u64, +) -> Result, NeonError> { + Ok(Arc::new( + CallDbClient::new(state.tracer_db.clone(), slot).await?, + )) +} + +pub async fn build_hash_rpc_client( + state: &NeonApiState, + hash: &str, +) -> Result, NeonError> { + let hash = <[u8; 32]>::from_hex(context::truncate_0x(hash))?; + Ok(Arc::new( + TrxDbClient::new(state.tracer_db.clone(), state.indexer_db.clone(), hash).await, + )) +} diff --git a/evm_loader/api/src/api_server/handlers/emulate.rs b/evm_loader/api/src/api_server/handlers/emulate.rs index 84d5d89f5..f47b6c9dd 100644 --- a/evm_loader/api/src/api_server/handlers/emulate.rs +++ b/evm_loader/api/src/api_server/handlers/emulate.rs @@ -1,12 +1,13 @@ use axum::{http::StatusCode, Json}; use std::convert::Into; +use crate::api_server::handlers::process_error; use crate::{ - commands::emulate as EmulateCommand, context, types::request_models::EmulateRequestModel, - NeonApiState, + api_context, commands::emulate as EmulateCommand, context, + types::request_models::EmulateRequestModel, NeonApiState, }; -use super::{parse_emulation_params, process_error, process_result}; +use super::{parse_emulation_params, process_result}; #[tracing::instrument(skip(state))] pub async fn emulate( @@ -15,7 +16,7 @@ pub async fn emulate( ) -> (StatusCode, Json) { let tx = emulate_request.tx_params.into(); - let rpc_client = match context::build_rpc_client(&state.config, emulate_request.slot).await { + let rpc_client = match api_context::build_rpc_client(&state, emulate_request.slot).await { Ok(rpc_client) => rpc_client, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; diff --git a/evm_loader/api/src/api_server/handlers/emulate_hash.rs b/evm_loader/api/src/api_server/handlers/emulate_hash.rs index b97538d6e..64a60b173 100644 --- a/evm_loader/api/src/api_server/handlers/emulate_hash.rs +++ b/evm_loader/api/src/api_server/handlers/emulate_hash.rs @@ -2,8 +2,8 @@ use axum::{http::StatusCode, Json}; use std::convert::Into; use crate::{ - commands::emulate as EmulateCommand, context, types::request_models::EmulateHashRequestModel, - NeonApiState, + api_context, commands::emulate as EmulateCommand, context, + types::request_models::EmulateHashRequestModel, NeonApiState, }; use super::{parse_emulation_params, process_error, process_result}; @@ -14,7 +14,7 @@ pub async fn emulate_hash( Json(emulate_hash_request): Json, ) -> (StatusCode, Json) { let rpc_client = - match context::build_hash_rpc_client(&state.config, &emulate_hash_request.hash).await { + match api_context::build_hash_rpc_client(&state, &emulate_hash_request.hash).await { Ok(rpc_client) => rpc_client, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; diff --git a/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs b/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs index d26a02c73..a1517dc70 100644 --- a/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs +++ b/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs @@ -1,5 +1,6 @@ +use crate::api_server::handlers::process_error; use crate::commands::get_ether_account_data as GetEtherAccountDataCommand; -use crate::{context, types::request_models::GetEtherRequest, NeonApiState}; +use crate::{api_context, context, types::request_models::GetEtherRequest, NeonApiState}; use axum::{ extract::{Query, State}, http::StatusCode, @@ -7,14 +8,14 @@ use axum::{ }; use std::convert::Into; -use super::{process_error, process_result}; +use super::process_result; #[tracing::instrument(skip(state))] pub async fn get_ether_account_data( Query(req_params): Query, State(state): State, ) -> (StatusCode, Json) { - let rpc_client = match context::build_rpc_client(&state.config, req_params.slot).await { + let rpc_client = match api_context::build_rpc_client(&state, req_params.slot).await { Ok(rpc_client) => rpc_client, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; diff --git a/evm_loader/api/src/api_server/handlers/get_storage_at.rs b/evm_loader/api/src/api_server/handlers/get_storage_at.rs index 2ebb11e33..c9a5d7775 100644 --- a/evm_loader/api/src/api_server/handlers/get_storage_at.rs +++ b/evm_loader/api/src/api_server/handlers/get_storage_at.rs @@ -1,4 +1,5 @@ -use crate::{context, types::request_models::GetStorageAtRequest, NeonApiState}; +use crate::api_server::handlers::process_error; +use crate::{api_context, context, types::request_models::GetStorageAtRequest, NeonApiState}; use axum::{ extract::{Query, State}, http::StatusCode, @@ -8,14 +9,14 @@ use std::convert::Into; use crate::commands::get_storage_at as GetStorageAtCommand; -use super::{process_error, process_result}; +use super::process_result; #[tracing::instrument(skip(state))] pub async fn get_storage_at( Query(req_params): Query, State(state): State, ) -> (StatusCode, Json) { - let rpc_client = match context::build_rpc_client(&state.config, req_params.slot).await { + let rpc_client = match api_context::build_rpc_client(&state, req_params.slot).await { Ok(rpc_client) => rpc_client, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; diff --git a/evm_loader/api/src/api_server/handlers/trace.rs b/evm_loader/api/src/api_server/handlers/trace.rs index 1c792f775..ba5803962 100644 --- a/evm_loader/api/src/api_server/handlers/trace.rs +++ b/evm_loader/api/src/api_server/handlers/trace.rs @@ -1,10 +1,11 @@ use axum::{http::StatusCode, Json}; use std::convert::Into; +use crate::api_server::handlers::process_error; use crate::commands::trace::trace_transaction; -use crate::{context, types::request_models::TraceRequestModel, NeonApiState}; +use crate::{api_context, context, types::request_models::TraceRequestModel, NeonApiState}; -use super::{parse_emulation_params, process_error, process_result}; +use super::{parse_emulation_params, process_result}; #[tracing::instrument(skip(state))] pub async fn trace( @@ -14,7 +15,7 @@ pub async fn trace( let tx = trace_request.emulate_request.tx_params.into(); let rpc_client = - match context::build_rpc_client(&state.config, trace_request.emulate_request.slot).await { + match api_context::build_rpc_client(&state, trace_request.emulate_request.slot).await { Ok(rpc_client) => rpc_client, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; diff --git a/evm_loader/api/src/api_server/handlers/trace_hash.rs b/evm_loader/api/src/api_server/handlers/trace_hash.rs index 7501ac865..ccf89b1c6 100644 --- a/evm_loader/api/src/api_server/handlers/trace_hash.rs +++ b/evm_loader/api/src/api_server/handlers/trace_hash.rs @@ -1,6 +1,6 @@ use std::convert::Into; -use crate::{context, types::request_models::TraceHashRequestModel, NeonApiState}; +use crate::{api_context, context, types::request_models::TraceHashRequestModel, NeonApiState}; use axum::{http::StatusCode, Json}; use neon_lib::commands::trace::trace_transaction; @@ -11,8 +11,8 @@ pub async fn trace_hash( axum::extract::State(state): axum::extract::State, Json(trace_hash_request): Json, ) -> (StatusCode, Json) { - let rpc_client = match context::build_hash_rpc_client( - &state.config, + let rpc_client = match api_context::build_hash_rpc_client( + &state, &trace_hash_request.emulate_hash_request.hash, ) .await diff --git a/evm_loader/api/src/api_server/handlers/trace_next_block.rs b/evm_loader/api/src/api_server/handlers/trace_next_block.rs index 454d867ee..1a82e7e34 100644 --- a/evm_loader/api/src/api_server/handlers/trace_next_block.rs +++ b/evm_loader/api/src/api_server/handlers/trace_next_block.rs @@ -1,9 +1,6 @@ use crate::{ - api_server::handlers::process_error, - commands::trace::trace_block, - context, errors, - types::{request_models::TraceNextBlockRequestModel, IndexerDb}, - NeonApiState, + api_context, api_server::handlers::process_error, commands::trace::trace_block, context, + errors, types::request_models::TraceNextBlockRequestModel, NeonApiState, }; use axum::http::StatusCode; use axum::Json; @@ -17,7 +14,7 @@ pub async fn trace_next_block( Json(trace_next_block_request): Json, ) -> (StatusCode, Json) { let rpc_client = - match context::build_call_db_client(&state.config, trace_next_block_request.slot).await { + match api_context::build_call_db_client(&state, trace_next_block_request.slot).await { Ok(rpc_client) => rpc_client, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; @@ -31,17 +28,9 @@ pub async fn trace_next_block( ) .await; - let indexer_db = IndexerDb::new( - state - .config - .db_config - .as_ref() - .expect("db-config is required"), - ) - .await; - // TODO: Query next block (which parent = slot) instead of getting slot + 1: - let transactions = match indexer_db + let transactions = match state + .indexer_db .get_block_transactions(trace_next_block_request.slot + 1) .await { diff --git a/evm_loader/api/src/api_server/routes.rs b/evm_loader/api/src/api_server/routes.rs index 154a701fb..e82fdeec5 100644 --- a/evm_loader/api/src/api_server/routes.rs +++ b/evm_loader/api/src/api_server/routes.rs @@ -14,7 +14,7 @@ use crate::{ NeonApiState, }; -pub fn register(s: NeonApiState) -> Router { +pub fn register() -> Router { ServiceBuilder::new().service::>( Router::new() .route("/emulate", post(emulate)) @@ -25,7 +25,6 @@ pub fn register(s: NeonApiState) -> Router { .route("/trace", post(trace)) .route("/trace-hash", post(trace_hash)) .route("/trace_hash", post(trace_hash)) // Obsolete - .route("/trace-next-block", post(trace_next_block)) - .with_state(s), + .route("/trace-next-block", post(trace_next_block)), ) } diff --git a/evm_loader/api/src/api_server/state.rs b/evm_loader/api/src/api_server/state.rs index 039cc6c32..f4a96ef67 100644 --- a/evm_loader/api/src/api_server/state.rs +++ b/evm_loader/api/src/api_server/state.rs @@ -1,14 +1,26 @@ use crate::Config; +use neon_lib::types::{IndexerDb, TracerDb}; +use solana_client::nonblocking::rpc_client::RpcClient; use std::sync::Arc; #[derive(Clone)] pub struct State { + pub tracer_db: TracerDb, + pub indexer_db: IndexerDb, + pub rpc_client: Arc, pub config: Arc, } impl State { - pub fn new(config: Config) -> Self { + pub async fn new(config: Config) -> Self { + let db_config = config.db_config.as_ref().expect("db-config not found"); Self { + tracer_db: TracerDb::new(db_config), + indexer_db: IndexerDb::new(db_config).await, + rpc_client: Arc::new(RpcClient::new_with_commitment( + config.json_rpc_url.clone(), + config.commitment, + )), config: Arc::new(config), } } diff --git a/evm_loader/api/src/main.rs b/evm_loader/api/src/main.rs index 8a97b5096..4b84e81bd 100644 --- a/evm_loader/api/src/main.rs +++ b/evm_loader/api/src/main.rs @@ -1,6 +1,7 @@ #![allow(dead_code)] #![deny(warnings)] #![deny(clippy::all, clippy::pedantic)] +mod api_context; mod api_options; mod api_server; @@ -49,11 +50,11 @@ async fn main() -> NeonApiResult<()> { let config = config::create_from_api_config(&api_config)?; - let state: NeonApiState = Arc::new(api_server::state::State::new(config)); + let state: NeonApiState = Arc::new(api_server::state::State::new(config).await); let app = Router::new() - .nest("/api", api_server::routes::register(state.clone())) - .with_state(state.clone()) + .nest("/api", api_server::routes::register()) + .with_state(state) .layer( // Let's create a tracing span for each request TraceLayer::new_for_http().make_span_with(|request: &Request| { @@ -82,7 +83,7 @@ async fn main() -> NeonApiResult<()> { ); let addr = SocketAddr::from_str(listener_addr.as_str())?; - tracing::debug!("listening on {}", addr); + tracing::info!("listening on {}", addr); axum::Server::bind(&addr) .serve(app.into_make_service()) .with_graceful_shutdown(shutdown_signal()) diff --git a/evm_loader/cli/src/context.rs b/evm_loader/cli/src/context.rs index eb7cecc59..ed48d4c4a 100644 --- a/evm_loader/cli/src/context.rs +++ b/evm_loader/cli/src/context.rs @@ -7,6 +7,7 @@ pub use neon_lib::context::*; use neon_lib::rpc; use neon_lib::rpc::CallDbClient; use neon_lib::rpc::TrxDbClient; +use neon_lib::types::{IndexerDb, TracerDb}; use neon_lib::Config; use neon_lib::NeonError; use solana_client::nonblocking::rpc_client::RpcClient; @@ -24,9 +25,11 @@ pub async fn create_from_config_and_options<'a>( let hash = params.value_of("hash").expect("hash not found"); let hash = <[u8; 32]>::from_hex(truncate_0x(hash)).expect("hash cast error"); + let db_config = config.db_config.as_ref().expect("db-config not found"); Arc::new( TrxDbClient::new( - config.db_config.as_ref().expect("db-config not found"), + TracerDb::new(db_config), + IndexerDb::new(db_config).await, hash, ) .await, @@ -36,7 +39,7 @@ pub async fn create_from_config_and_options<'a>( if let Some(slot) = slot { Arc::new( CallDbClient::new( - config.db_config.as_ref().expect("db-config not found"), + TracerDb::new(config.db_config.as_ref().expect("db-config not found")), *slot, ) .await?, diff --git a/evm_loader/docker-compose-ci.yml b/evm_loader/docker-compose-ci.yml index 68c06de89..2580a89e9 100644 --- a/evm_loader/docker-compose-ci.yml +++ b/evm_loader/docker-compose-ci.yml @@ -34,7 +34,7 @@ services: NEON_DB_INDEXER_PORT: 5432 NEON_DB_INDEXER_DATABASE: indexer NEON_DB_INDEXER_USER: postgres - NEON_DB_INDEXER_PASSWORD: "" + NEON_DB_INDEXER_PASSWORD: $INDEXER_DB_PASSWORD KEYPAIR: /opt/operator-keypairs/id.json FEEPAIR: /opt/operator-keypairs/id.json image: ${EVM_LOADER_IMAGE} diff --git a/evm_loader/lib/src/context.rs b/evm_loader/lib/src/context.rs index 2eb38090c..e05fe4ea9 100644 --- a/evm_loader/lib/src/context.rs +++ b/evm_loader/lib/src/context.rs @@ -1,31 +1,12 @@ use std::sync::Arc; use crate::{ - rpc::CallDbClient, - rpc::{self, TrxDbClient}, + rpc::{self}, Config, NeonError, }; -use hex::FromHex; use solana_clap_utils::keypair::signer_from_path; -use solana_client::nonblocking::rpc_client::RpcClient; use solana_sdk::signature::Signer; -/// # Errors -pub async fn build_hash_rpc_client( - config: &Config, - hash: &str, -) -> Result, NeonError> { - let hash = <[u8; 32]>::from_hex(truncate_0x(hash))?; - - Ok(Arc::new( - TrxDbClient::new( - config.db_config.as_ref().expect("db-config not found"), - hash, - ) - .await, - )) -} - pub fn truncate_0x(in_str: &str) -> &str { if &in_str[..2] == "0x" { &in_str[2..] @@ -67,30 +48,3 @@ pub fn build_signer(config: &Config) -> Result, NeonError> { Ok(signer) } - -/// # Errors -pub async fn build_rpc_client( - config: &Config, - slot: Option, -) -> Result, NeonError> { - if let Some(slot) = slot { - return build_call_db_client(config, slot).await; - } - - Ok(Arc::new(RpcClient::new_with_commitment( - config.json_rpc_url.clone(), - config.commitment, - ))) -} - -/// # Errors -pub async fn build_call_db_client( - config: &Config, - slot: u64, -) -> Result, NeonError> { - let config = config - .db_config - .clone() - .ok_or(NeonError::InvalidChDbConfig)?; - Ok(Arc::new(CallDbClient::new(&config, slot).await?)) -} diff --git a/evm_loader/lib/src/rpc/db_call_client.rs b/evm_loader/lib/src/rpc/db_call_client.rs index 7f54f5d19..24e97e614 100644 --- a/evm_loader/lib/src/rpc/db_call_client.rs +++ b/evm_loader/lib/src/rpc/db_call_client.rs @@ -1,5 +1,5 @@ use super::{e, Rpc}; -use crate::types::{ChDbConfig, TracerDb, TxParams}; +use crate::types::{TracerDb, TxParams}; use crate::NeonError; use async_trait::async_trait; use solana_client::{ @@ -23,15 +23,13 @@ use solana_transaction_status::{ use std::any::Any; pub struct CallDbClient { - pub slot: u64, tracer_db: TracerDb, + pub slot: u64, } impl CallDbClient { - pub async fn new(config: &ChDbConfig, slot: u64) -> Result { - let db = TracerDb::new(config); - - let earliest_rooted_slot = db + pub async fn new(tracer_db: TracerDb, slot: u64) -> Result { + let earliest_rooted_slot = tracer_db .get_earliest_rooted_slot() .await .map_err(NeonError::ClickHouse)?; @@ -39,10 +37,7 @@ impl CallDbClient { return Err(NeonError::EarlySlot(slot, earliest_rooted_slot)); } - Ok(Self { - slot, - tracer_db: db, - }) + Ok(Self { tracer_db, slot }) } } diff --git a/evm_loader/lib/src/rpc/db_trx_client.rs b/evm_loader/lib/src/rpc/db_trx_client.rs index 65f0a08f1..bf6da857a 100644 --- a/evm_loader/lib/src/rpc/db_trx_client.rs +++ b/evm_loader/lib/src/rpc/db_trx_client.rs @@ -1,5 +1,5 @@ use super::{e, Rpc}; -use crate::types::{ChDbConfig, IndexerDb, TracerDb, TxParams}; +use crate::types::{IndexerDb, TracerDb, TxParams}; use async_trait::async_trait; use solana_client::{ client_error::Result as ClientResult, @@ -29,9 +29,7 @@ pub struct TrxDbClient { } impl TrxDbClient { - pub async fn new(config: &ChDbConfig, hash: [u8; 32]) -> Self { - let tracer_db = TracerDb::new(config); - let indexer_db = IndexerDb::new(config).await; + pub async fn new(tracer_db: TracerDb, indexer_db: IndexerDb, hash: [u8; 32]) -> Self { let sol_sig = indexer_db .get_sol_sig(&hash) .await diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index 6a70b09fa..633b2e785 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -10,6 +10,7 @@ use std::str::FromStr; use tokio::runtime::Runtime; use tokio::task::block_in_place; pub use tracer_ch_db::{ChError, ChResult, ClickHouseDb as TracerDb}; +use tracing::error; use evm_loader::evm::tracing::{TraceCallConfig, TraceConfig}; use evm_loader::types::hexbytes::HexBytes; @@ -79,10 +80,13 @@ pub async fn do_connect( let mut result = None; while attempt < 3 { - result = connect(&authority, NoTls).await.ok(); - if result.is_some() { - break; - } + match connect(&authority, NoTls).await { + Ok(res) => { + result = Some(res); + break; + } + Err(e) => error!("Error connecting to database {authority}: {e}"), + }; attempt += 1; } From be8eb1e030acf0683564c1f12a4947da8862270f Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Mon, 18 Sep 2023 12:37:38 +0100 Subject: [PATCH 026/318] Remove emulate-hash, trace-hash and trace-next-block (#196) Remove emulate-hash, trace-hash and trace-next-block. Delete everything related to accessing indexer database. --- .github/workflows/pipeline.yml | 1 - evm_loader/Cargo.lock | 151 +----------- evm_loader/api/src/api_context.rs | 15 +- .../api/src/api_server/handlers/emulate.rs | 4 +- .../src/api_server/handlers/emulate_hash.rs | 58 ----- .../handlers/get_ether_account_data.rs | 5 +- .../src/api_server/handlers/get_storage_at.rs | 6 +- evm_loader/api/src/api_server/handlers/mod.rs | 3 - .../api/src/api_server/handlers/trace.rs | 6 +- .../api/src/api_server/handlers/trace_hash.rs | 59 ----- .../api_server/handlers/trace_next_block.rs | 62 ----- evm_loader/api/src/api_server/routes.rs | 14 +- evm_loader/api/src/api_server/state.rs | 6 +- evm_loader/api/src/main.rs | 2 +- evm_loader/cli/src/context.rs | 57 ----- evm_loader/cli/src/main.rs | 106 +-------- evm_loader/cli/src/program_options.rs | 55 +---- evm_loader/docker-compose-ci.yml | 5 - evm_loader/lib/Cargo.toml | 2 - evm_loader/lib/src/config.rs | 20 -- evm_loader/lib/src/context.rs | 39 +++- evm_loader/lib/src/errors.rs | 5 +- evm_loader/lib/src/rpc/db_call_client.rs | 8 +- evm_loader/lib/src/rpc/db_trx_client.rs | 217 ------------------ evm_loader/lib/src/rpc/mod.rs | 5 +- evm_loader/lib/src/rpc/validator_client.rs | 10 +- evm_loader/lib/src/types/indexer_db.rs | 176 -------------- evm_loader/lib/src/types/mod.rs | 66 +----- evm_loader/lib/src/types/request_models.rs | 24 +- 29 files changed, 71 insertions(+), 1116 deletions(-) delete mode 100644 evm_loader/api/src/api_server/handlers/emulate_hash.rs delete mode 100644 evm_loader/api/src/api_server/handlers/trace_hash.rs delete mode 100644 evm_loader/api/src/api_server/handlers/trace_next_block.rs delete mode 100644 evm_loader/cli/src/context.rs delete mode 100644 evm_loader/lib/src/rpc/db_trx_client.rs delete mode 100644 evm_loader/lib/src/types/indexer_db.rs diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index be9045650..ed3814394 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -14,7 +14,6 @@ env: DHUBU: ${{secrets.DHUBU}} DHUBP: ${{secrets.DHUBP}} BUILD_URL: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" - INDEXER_DB_PASSWORD: ${{secrets.INDEXER_DB_PASSWORD}} concurrency: group: ${{ github.workflow }}-${{ github.ref }} diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 463995ff4..f89df6da7 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -113,12 +113,6 @@ version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" -[[package]] -name = "array-init" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc" - [[package]] name = "arrayref" version = "0.3.7" @@ -1241,12 +1235,6 @@ dependencies = [ "toml", ] -[[package]] -name = "fallible-iterator" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" - [[package]] name = "fastrand" version = "1.9.0" @@ -1680,7 +1668,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.4.9", + "socket2", "tokio", "tower-service", "tracing", @@ -2028,15 +2016,6 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" -[[package]] -name = "md-5" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" -dependencies = [ - "digest 0.10.6", -] - [[package]] name = "memchr" version = "2.5.0" @@ -2255,7 +2234,6 @@ dependencies = [ "hex", "lazy_static", "log", - "postgres", "rand 0.8.5", "scroll", "serde", @@ -2270,7 +2248,6 @@ dependencies = [ "spl-token", "thiserror", "tokio", - "tokio-postgres", "tracing", ] @@ -2602,24 +2579,6 @@ dependencies = [ "num", ] -[[package]] -name = "phf" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" -dependencies = [ - "phf_shared", -] - -[[package]] -name = "phf_shared" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" -dependencies = [ - "siphasher", -] - [[package]] name = "pin-project" version = "1.1.0" @@ -2687,52 +2646,6 @@ dependencies = [ "universal-hash", ] -[[package]] -name = "postgres" -version = "0.19.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bed5017bc2ff49649c0075d0d7a9d676933c1292480c1d137776fb205b5cd18" -dependencies = [ - "bytes", - "fallible-iterator", - "futures-util", - "log", - "tokio", - "tokio-postgres", -] - -[[package]] -name = "postgres-protocol" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b7fa9f396f51dffd61546fd8573ee20592287996568e6175ceb0f8699ad75d" -dependencies = [ - "base64 0.21.0", - "byteorder", - "bytes", - "fallible-iterator", - "hmac 0.12.1", - "md-5", - "memchr", - "rand 0.8.5", - "sha2 0.10.6", - "stringprep", -] - -[[package]] -name = "postgres-types" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f028f05971fe20f512bcc679e2c10227e57809a3af86a7606304435bc8896cd6" -dependencies = [ - "array-init", - "bytes", - "chrono", - "fallible-iterator", - "postgres-protocol", - "uuid", -] - [[package]] name = "ppv-lite86" version = "0.2.17" @@ -2839,7 +2752,7 @@ dependencies = [ "futures-util", "libc", "quinn-proto", - "socket2 0.4.9", + "socket2", "tokio", "tracing", ] @@ -3578,12 +3491,6 @@ version = "1.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" -[[package]] -name = "siphasher" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" - [[package]] name = "sized-chunks" version = "0.6.5" @@ -3619,16 +3526,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "socket2" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d283f86695ae989d1e18440a943880967156325ba025f05049946bff47bcc2b" -dependencies = [ - "libc", - "windows-sys 0.48.0", -] - [[package]] name = "solana-account-decoder" version = "1.14.20" @@ -3987,7 +3884,7 @@ dependencies = [ "rand 0.7.3", "serde", "serde_derive", - "socket2 0.4.9", + "socket2", "solana-logger", "solana-sdk", "solana-version", @@ -4416,16 +4313,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "stringprep" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "strsim" version = "0.8.0" @@ -4654,7 +4541,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.4.9", + "socket2", "tokio-macros", "windows-sys 0.45.0", ] @@ -4680,30 +4567,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-postgres" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e89f6234aa8fd43779746012fcf53603cdb91fdd8399aa0de868c2d56b6dde1" -dependencies = [ - "async-trait", - "byteorder", - "bytes", - "fallible-iterator", - "futures-channel", - "futures-util", - "log", - "parking_lot", - "percent-encoding", - "phf", - "pin-project-lite", - "postgres-protocol", - "postgres-types", - "socket2 0.5.2", - "tokio", - "tokio-util", -] - [[package]] name = "tokio-rustls" version = "0.23.4" @@ -5055,12 +4918,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" -[[package]] -name = "uuid" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" - [[package]] name = "valuable" version = "0.1.0" diff --git a/evm_loader/api/src/api_context.rs b/evm_loader/api/src/api_context.rs index 4cb3b81fc..409638aff 100644 --- a/evm_loader/api/src/api_context.rs +++ b/evm_loader/api/src/api_context.rs @@ -1,7 +1,6 @@ use crate::NeonApiState; -use hex::FromHex; -use neon_lib::rpc::{CallDbClient, TrxDbClient}; -use neon_lib::{context, rpc, NeonError}; +use neon_lib::rpc::CallDbClient; +use neon_lib::{rpc, NeonError}; use std::sync::Arc; pub async fn build_rpc_client( @@ -23,13 +22,3 @@ pub async fn build_call_db_client( CallDbClient::new(state.tracer_db.clone(), slot).await?, )) } - -pub async fn build_hash_rpc_client( - state: &NeonApiState, - hash: &str, -) -> Result, NeonError> { - let hash = <[u8; 32]>::from_hex(context::truncate_0x(hash))?; - Ok(Arc::new( - TrxDbClient::new(state.tracer_db.clone(), state.indexer_db.clone(), hash).await, - )) -} diff --git a/evm_loader/api/src/api_server/handlers/emulate.rs b/evm_loader/api/src/api_server/handlers/emulate.rs index f47b6c9dd..6403c940f 100644 --- a/evm_loader/api/src/api_server/handlers/emulate.rs +++ b/evm_loader/api/src/api_server/handlers/emulate.rs @@ -3,7 +3,7 @@ use std::convert::Into; use crate::api_server::handlers::process_error; use crate::{ - api_context, commands::emulate as EmulateCommand, context, + api_context, commands::emulate as EmulateCommand, context::Context, types::request_models::EmulateRequestModel, NeonApiState, }; @@ -21,7 +21,7 @@ pub async fn emulate( Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; - let context = context::create(rpc_client, state.config.clone()); + let context = Context::new(rpc_client, state.config.clone()); let (token, chain, steps, accounts, solana_accounts) = parse_emulation_params(&state.config, &context, &emulate_request.emulation_params).await; diff --git a/evm_loader/api/src/api_server/handlers/emulate_hash.rs b/evm_loader/api/src/api_server/handlers/emulate_hash.rs deleted file mode 100644 index 64a60b173..000000000 --- a/evm_loader/api/src/api_server/handlers/emulate_hash.rs +++ /dev/null @@ -1,58 +0,0 @@ -use axum::{http::StatusCode, Json}; -use std::convert::Into; - -use crate::{ - api_context, commands::emulate as EmulateCommand, context, - types::request_models::EmulateHashRequestModel, NeonApiState, -}; - -use super::{parse_emulation_params, process_error, process_result}; - -#[tracing::instrument(skip(state))] -pub async fn emulate_hash( - axum::extract::State(state): axum::extract::State, - Json(emulate_hash_request): Json, -) -> (StatusCode, Json) { - let rpc_client = - match api_context::build_hash_rpc_client(&state, &emulate_hash_request.hash).await { - Ok(rpc_client) => rpc_client, - Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), - }; - - let tx = match rpc_client.get_transaction_data().await { - Ok(tx) => tx, - Err(e) => { - return process_error( - StatusCode::BAD_REQUEST, - &crate::errors::NeonError::SolanaClientError(e), - ) - } - }; - - let context = context::create(rpc_client, state.config.clone()); - - let (token, chain, steps, accounts, solana_accounts) = parse_emulation_params( - &state.config, - &context, - &emulate_hash_request.emulation_params, - ) - .await; - - process_result( - &EmulateCommand::execute( - context.rpc_client.as_ref(), - state.config.evm_loader, - tx, - token, - chain, - steps, - state.config.commitment, - &accounts, - &solana_accounts, - &None, - None, - ) - .await - .map_err(Into::into), - ) -} diff --git a/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs b/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs index a1517dc70..b16854bc7 100644 --- a/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs +++ b/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs @@ -1,6 +1,6 @@ use crate::api_server::handlers::process_error; use crate::commands::get_ether_account_data as GetEtherAccountDataCommand; -use crate::{api_context, context, types::request_models::GetEtherRequest, NeonApiState}; +use crate::{api_context, context::Context, types::request_models::GetEtherRequest, NeonApiState}; use axum::{ extract::{Query, State}, http::StatusCode, @@ -19,8 +19,7 @@ pub async fn get_ether_account_data( Ok(rpc_client) => rpc_client, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; - - let context = context::create(rpc_client, state.config.clone()); + let context = Context::new(rpc_client, state.config.clone()); process_result( &GetEtherAccountDataCommand::execute( diff --git a/evm_loader/api/src/api_server/handlers/get_storage_at.rs b/evm_loader/api/src/api_server/handlers/get_storage_at.rs index c9a5d7775..f32ebd5d0 100644 --- a/evm_loader/api/src/api_server/handlers/get_storage_at.rs +++ b/evm_loader/api/src/api_server/handlers/get_storage_at.rs @@ -1,5 +1,7 @@ use crate::api_server::handlers::process_error; -use crate::{api_context, context, types::request_models::GetStorageAtRequest, NeonApiState}; +use crate::{ + api_context, context::Context, types::request_models::GetStorageAtRequest, NeonApiState, +}; use axum::{ extract::{Query, State}, http::StatusCode, @@ -21,7 +23,7 @@ pub async fn get_storage_at( Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; - let context = context::create(rpc_client, state.config.clone()); + let context = Context::new(rpc_client, state.config.clone()); process_result( &GetStorageAtCommand::execute( diff --git a/evm_loader/api/src/api_server/handlers/mod.rs b/evm_loader/api/src/api_server/handlers/mod.rs index 9887388d7..3eb743233 100644 --- a/evm_loader/api/src/api_server/handlers/mod.rs +++ b/evm_loader/api/src/api_server/handlers/mod.rs @@ -17,12 +17,9 @@ use std::str::FromStr; use tracing::error; pub mod emulate; -pub mod emulate_hash; pub mod get_ether_account_data; pub mod get_storage_at; pub mod trace; -pub mod trace_hash; -pub mod trace_next_block; #[derive(Debug)] pub struct NeonApiError(pub NeonError); diff --git a/evm_loader/api/src/api_server/handlers/trace.rs b/evm_loader/api/src/api_server/handlers/trace.rs index ba5803962..43cbf8403 100644 --- a/evm_loader/api/src/api_server/handlers/trace.rs +++ b/evm_loader/api/src/api_server/handlers/trace.rs @@ -3,7 +3,9 @@ use std::convert::Into; use crate::api_server::handlers::process_error; use crate::commands::trace::trace_transaction; -use crate::{api_context, context, types::request_models::TraceRequestModel, NeonApiState}; +use crate::{ + api_context, context::Context, types::request_models::TraceRequestModel, NeonApiState, +}; use super::{parse_emulation_params, process_result}; @@ -20,7 +22,7 @@ pub async fn trace( Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; - let context = context::create(rpc_client, state.config.clone()); + let context = Context::new(rpc_client, state.config.clone()); let (token, chain, steps, accounts, solana_accounts) = parse_emulation_params( &state.config, diff --git a/evm_loader/api/src/api_server/handlers/trace_hash.rs b/evm_loader/api/src/api_server/handlers/trace_hash.rs deleted file mode 100644 index ccf89b1c6..000000000 --- a/evm_loader/api/src/api_server/handlers/trace_hash.rs +++ /dev/null @@ -1,59 +0,0 @@ -use std::convert::Into; - -use crate::{api_context, context, types::request_models::TraceHashRequestModel, NeonApiState}; -use axum::{http::StatusCode, Json}; -use neon_lib::commands::trace::trace_transaction; - -use super::{parse_emulation_params, process_error, process_result}; - -#[tracing::instrument(skip(state))] -pub async fn trace_hash( - axum::extract::State(state): axum::extract::State, - Json(trace_hash_request): Json, -) -> (StatusCode, Json) { - let rpc_client = match api_context::build_hash_rpc_client( - &state, - &trace_hash_request.emulate_hash_request.hash, - ) - .await - { - Ok(rpc_client) => rpc_client, - Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), - }; - - let tx = match rpc_client.get_transaction_data().await { - Ok(tx) => tx, - Err(e) => { - return process_error( - StatusCode::BAD_REQUEST, - &crate::errors::NeonError::SolanaClientError(e), - ) - } - }; - - let context = context::create(rpc_client, state.config.clone()); - - let (token, chain, steps, accounts, solana_accounts) = parse_emulation_params( - &state.config, - &context, - &trace_hash_request.emulate_hash_request.emulation_params, - ) - .await; - - process_result( - &trace_transaction( - context.rpc_client.as_ref(), - state.config.evm_loader, - tx, - token, - chain, - steps, - state.config.commitment, - &accounts, - &solana_accounts, - trace_hash_request.trace_config.unwrap_or_default().into(), - ) - .await - .map_err(Into::into), - ) -} diff --git a/evm_loader/api/src/api_server/handlers/trace_next_block.rs b/evm_loader/api/src/api_server/handlers/trace_next_block.rs deleted file mode 100644 index 1a82e7e34..000000000 --- a/evm_loader/api/src/api_server/handlers/trace_next_block.rs +++ /dev/null @@ -1,62 +0,0 @@ -use crate::{ - api_context, api_server::handlers::process_error, commands::trace::trace_block, context, - errors, types::request_models::TraceNextBlockRequestModel, NeonApiState, -}; -use axum::http::StatusCode; -use axum::Json; -use std::sync::Arc; - -use super::{parse_emulation_params, process_result}; - -#[tracing::instrument(skip(state))] -pub async fn trace_next_block( - axum::extract::State(state): axum::extract::State, - Json(trace_next_block_request): Json, -) -> (StatusCode, Json) { - let rpc_client = - match api_context::build_call_db_client(&state, trace_next_block_request.slot).await { - Ok(rpc_client) => rpc_client, - Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), - }; - - let context = context::create(rpc_client, Arc::clone(&state.config)); - - let (token, chain, steps, accounts, solana_accounts) = parse_emulation_params( - &state.config, - &context, - &trace_next_block_request.emulation_params, - ) - .await; - - // TODO: Query next block (which parent = slot) instead of getting slot + 1: - let transactions = match state - .indexer_db - .get_block_transactions(trace_next_block_request.slot + 1) - .await - { - Ok(transactions) => transactions, - Err(e) => { - return process_error( - StatusCode::INTERNAL_SERVER_ERROR, - &errors::NeonError::PostgresError(e), - ) - } - }; - - process_result( - &trace_block( - context.rpc_client.as_ref(), - state.config.evm_loader, - transactions, - token, - chain, - steps, - state.config.commitment, - &accounts, - &solana_accounts, - &trace_next_block_request.trace_config.unwrap_or_default(), - ) - .await - .map_err(Into::into), - ) -} diff --git a/evm_loader/api/src/api_server/routes.rs b/evm_loader/api/src/api_server/routes.rs index e82fdeec5..85a0d9a5b 100644 --- a/evm_loader/api/src/api_server/routes.rs +++ b/evm_loader/api/src/api_server/routes.rs @@ -7,9 +7,8 @@ use tower::ServiceBuilder; // use evm_loader::types::Address; use crate::{ api_server::handlers::{ - emulate::emulate, emulate_hash::emulate_hash, - get_ether_account_data::get_ether_account_data, get_storage_at::get_storage_at, - trace::trace, trace_hash::trace_hash, trace_next_block::trace_next_block, + emulate::emulate, get_ether_account_data::get_ether_account_data, + get_storage_at::get_storage_at, trace::trace, }, NeonApiState, }; @@ -17,14 +16,9 @@ use crate::{ pub fn register() -> Router { ServiceBuilder::new().service::>( Router::new() - .route("/emulate", post(emulate)) - .route("/emulate-hash", post(emulate_hash)) - .route("/emulate_hash", post(emulate_hash)) // Obsolete + .route("/emulate", post(emulate)) // Obsolete .route("/get-storage-at", get(get_storage_at)) .route("/get-ether-account-data", get(get_ether_account_data)) - .route("/trace", post(trace)) - .route("/trace-hash", post(trace_hash)) - .route("/trace_hash", post(trace_hash)) // Obsolete - .route("/trace-next-block", post(trace_next_block)), + .route("/trace", post(trace)), ) } diff --git a/evm_loader/api/src/api_server/state.rs b/evm_loader/api/src/api_server/state.rs index f4a96ef67..1b49fe103 100644 --- a/evm_loader/api/src/api_server/state.rs +++ b/evm_loader/api/src/api_server/state.rs @@ -1,22 +1,20 @@ use crate::Config; -use neon_lib::types::{IndexerDb, TracerDb}; +use neon_lib::types::TracerDb; use solana_client::nonblocking::rpc_client::RpcClient; use std::sync::Arc; #[derive(Clone)] pub struct State { pub tracer_db: TracerDb, - pub indexer_db: IndexerDb, pub rpc_client: Arc, pub config: Arc, } impl State { - pub async fn new(config: Config) -> Self { + pub fn new(config: Config) -> Self { let db_config = config.db_config.as_ref().expect("db-config not found"); Self { tracer_db: TracerDb::new(db_config), - indexer_db: IndexerDb::new(db_config).await, rpc_client: Arc::new(RpcClient::new_with_commitment( config.json_rpc_url.clone(), config.commitment, diff --git a/evm_loader/api/src/main.rs b/evm_loader/api/src/main.rs index 4b84e81bd..206c952de 100644 --- a/evm_loader/api/src/main.rs +++ b/evm_loader/api/src/main.rs @@ -50,7 +50,7 @@ async fn main() -> NeonApiResult<()> { let config = config::create_from_api_config(&api_config)?; - let state: NeonApiState = Arc::new(api_server::state::State::new(config).await); + let state: NeonApiState = Arc::new(api_server::state::State::new(config)); let app = Router::new() .nest("/api", api_server::routes::register()) diff --git a/evm_loader/cli/src/context.rs b/evm_loader/cli/src/context.rs deleted file mode 100644 index ed48d4c4a..000000000 --- a/evm_loader/cli/src/context.rs +++ /dev/null @@ -1,57 +0,0 @@ -use std::sync::Arc; - -use clap::ArgMatches; -use hex::FromHex; -use neon_lib::context::truncate_0x; -pub use neon_lib::context::*; -use neon_lib::rpc; -use neon_lib::rpc::CallDbClient; -use neon_lib::rpc::TrxDbClient; -use neon_lib::types::{IndexerDb, TracerDb}; -use neon_lib::Config; -use neon_lib::NeonError; -use solana_client::nonblocking::rpc_client::RpcClient; - -/// # Errors -pub async fn create_from_config_and_options<'a>( - options: &'a ArgMatches<'a>, - config: Arc, - slot: &'a Option, -) -> Result { - let (cmd, params) = options.subcommand(); - - let rpc_client: Arc = match (cmd, params) { - ("emulate-hash" | "trace-hash" | "emulate_hash" | "trace_hash", Some(params)) => { - let hash = params.value_of("hash").expect("hash not found"); - let hash = <[u8; 32]>::from_hex(truncate_0x(hash)).expect("hash cast error"); - - let db_config = config.db_config.as_ref().expect("db-config not found"); - Arc::new( - TrxDbClient::new( - TracerDb::new(db_config), - IndexerDb::new(db_config).await, - hash, - ) - .await, - ) - } - _ => { - if let Some(slot) = slot { - Arc::new( - CallDbClient::new( - TracerDb::new(config.db_config.as_ref().expect("db-config not found")), - *slot, - ) - .await?, - ) - } else { - Arc::new(RpcClient::new_with_commitment( - config.json_rpc_url.clone(), - config.commitment, - )) - } - } - }; - - Ok(neon_lib::context::create(rpc_client, config.clone())) -} diff --git a/evm_loader/cli/src/main.rs b/evm_loader/cli/src/main.rs index 25a57962c..b4cbd76ed 100644 --- a/evm_loader/cli/src/main.rs +++ b/evm_loader/cli/src/main.rs @@ -2,7 +2,6 @@ #![deny(clippy::all, clippy::pedantic)] mod config; -mod context; mod logs; mod program_options; @@ -12,20 +11,19 @@ use neon_lib::{ get_ether_account_data, get_neon_elf, get_neon_elf::CachedElfParams, get_storage_at, init_environment, trace, }, - errors, rpc, + errors, types::{self, AccessListItem}, + Context, }; use clap::ArgMatches; pub use config::Config; -pub use context::Context; use std::io::Read; use ethnum::U256; -use evm_loader::evm::tracing::{TraceCallConfig, TraceConfig}; +use evm_loader::evm::tracing::TraceCallConfig; use serde_json::json; use solana_clap_utils::input_parsers::{pubkey_of, value_of, values_of}; -use solana_client::client_error::{ClientError, ClientErrorKind}; use solana_client::nonblocking::rpc_client::RpcClient; use solana_sdk::pubkey::Pubkey; use std::str::FromStr; @@ -34,8 +32,7 @@ use tokio::time::Instant; use crate::{ errors::NeonError, - rpc::Rpc, - types::{IndexerDb, TraceNextBlockParams, TransactionHashParams, TransactionParams, TxParams}, + types::{TransactionParams, TxParams}, }; use evm_loader::types::Address; @@ -47,10 +44,9 @@ async fn run<'a>(options: &'a ArgMatches<'a>) -> NeonCliResult { .map(|slot_str| slot_str.parse().expect("slot parse error")); let (cmd, params) = options.subcommand(); let config = Arc::new(config::create(options)?); - let context: Context = - context::create_from_config_and_options(options, config.clone(), &slot).await?; + let context = Context::new_from_config(config.clone(), slot).await?; - execute(cmd, params, &config, &context, slot).await + execute(cmd, params, &config, &context).await } fn print_result(result: &NeonCliResult) { @@ -103,7 +99,6 @@ async fn execute<'a>( params: Option<&'a ArgMatches<'a>>, config: &'a Config, context: &'a Context, - slot: Option, ) -> NeonCliResult { match (cmd, params) { ("emulate", Some(params)) => { @@ -126,26 +121,6 @@ async fn execute<'a>( .await .map(|result| json!(result)) } - ("emulate-hash", Some(params)) => { - let tx = context.rpc_client.get_transaction_data().await?; - let (token, chain, steps, accounts, solana_accounts) = - parse_tx_params(config, context, params).await; - emulate::execute( - context.rpc_client.as_ref(), - config.evm_loader, - tx, - token, - chain, - steps, - config.commitment, - &accounts, - &solana_accounts, - &None, - None, - ) - .await - .map(|result| json!(result)) - } ("trace", Some(params)) => { let (tx, trace_call_config) = parse_tx(params); let (token, chain, steps, accounts, solana_accounts) = @@ -165,61 +140,6 @@ async fn execute<'a>( .await .map(|trace| json!(trace)) } - ("trace-hash", Some(params)) => { - let (tx, trace_config) = parse_tx_hash(context.rpc_client.as_ref()).await; - let (token, chain, steps, accounts, solana_accounts) = - parse_tx_params(config, context, params).await; - trace::trace_transaction( - context.rpc_client.as_ref(), - config.evm_loader, - tx, - token, - chain, - steps, - config.commitment, - &accounts, - &solana_accounts, - trace_config.into(), - ) - .await - .map(|trace| json!(trace)) - } - ("trace-next-block", Some(params)) => { - let slot = slot.expect("SLOT argument is not provided"); - let trace_block_params: Option = read_from_stdin() - .unwrap_or_else(|err| { - panic!("Unable to parse `TraceBlockBySlotParams` from STDIN, error: {err:?}") - }); - let trace_config = trace_block_params - .map(|params| params.trace_config.unwrap_or_default()) - .unwrap_or_default(); - let (token, chain, steps, accounts, solana_accounts) = - parse_tx_params(config, context, params).await; - let indexer_db = - IndexerDb::new(config.db_config.as_ref().expect("db-config is required")).await; - let transactions = indexer_db - .get_block_transactions(slot + 1) - .await - .map_err(|e| { - ClientError::from(ClientErrorKind::Custom(format!( - "get_block_transactions error: {e}" - ))) - })?; - trace::trace_block( - context.rpc_client.as_ref(), - config.evm_loader, - transactions, - token, - chain, - steps, - config.commitment, - &accounts, - &solana_accounts, - &trace_config, - ) - .await - .map(|traces| json!(traces)) - } ("create-ether-account", Some(params)) => { let ether = address_of(params, "ether").expect("ether parse error"); let rpc_client = context @@ -340,20 +260,6 @@ fn parse_tx(params: &ArgMatches) -> (TxParams, TraceCallConfig) { (tx_params, trace_config) } -async fn parse_tx_hash(rpc_client: &dyn Rpc) -> (TxParams, TraceConfig) { - let tx = rpc_client.get_transaction_data().await.unwrap(); - let transaction_params: Option = - read_from_stdin().unwrap_or_else(|err| { - panic!("Unable to parse `TransactionHashParams` from STDIN, error: {err:?}") - }); - - let trace_config = transaction_params - .map(|params| params.trace_config.unwrap_or_default()) - .unwrap_or_default(); - - (tx, trace_config) -} - pub async fn parse_tx_params<'a>( config: &Config, context: &Context, diff --git a/evm_loader/cli/src/program_options.rs b/evm_loader/cli/src/program_options.rs index f8bea1704..ce0e2b39f 100644 --- a/evm_loader/cli/src/program_options.rs +++ b/evm_loader/cli/src/program_options.rs @@ -1,8 +1,6 @@ use clap::{crate_description, crate_name, App, AppSettings, Arg, ArgMatches, SubCommand}; use ethnum::U256; use evm_loader::types::Address; -use hex::FromHex; -use neon_lib::context::truncate_0x; use solana_clap_utils::input_validators::{is_url_or_moniker, is_valid_pubkey}; use std::fmt::Display; @@ -44,16 +42,6 @@ where .map_err(|e| e.to_string()) } -fn is_valid_h256(string: T) -> Result<(), String> -where - T: AsRef, -{ - let str = truncate_0x(string.as_ref()); - <[u8; 32]>::from_hex(str) - .map(|_| ()) - .map_err(|e| e.to_string()) -} - fn is_amount(amount: U) -> Result<(), String> where T: std::str::FromStr, @@ -181,24 +169,6 @@ fn trx_params<'a, 'b>(cmd: &'static str, desc: &'static str) -> App<'a, 'b> { ) } -fn trx_hash<'a, 'b>(cmd: &'static str, alias: &'static str, desc: &'static str) -> App<'a, 'b> { - SubCommand::with_name(cmd) - .alias(alias) - .about(desc) - .arg( - Arg::with_name("hash") - .index(1) - .value_name("hash") - .takes_value(true) - .required(true) - .validator(is_valid_h256) - .help("Neon transaction hash"), - ) - .arg(token_mint_arg()) - .arg(chain_id_arg()) - .arg(max_steps_arg()) -} - #[allow(clippy::too_many_lines)] pub fn parse<'a>() -> ArgMatches<'a> { App::new(crate_name!()) @@ -226,7 +196,7 @@ pub fn parse<'a>() -> ArgMatches<'a> { .long("db_config") .takes_value(true) .global(true) - .help("Configuration file to use Postgress DB") + .help("Configuration file to use Tracer DB") ) .arg( Arg::with_name("slot") @@ -321,29 +291,6 @@ pub fn parse<'a>() -> ArgMatches<'a> { "Emulation transaction to collecting traces. Additional `TransactionParams` can be provided via STDIN as a JSON object.", ) ) - .subcommand( - trx_hash( - "emulate-hash", - "emulate_hash", - "Emulation transaction by hash. Additional `TransactionHashParams` can be provided via STDIN as a JSON object.", - ) - ) - .subcommand( - trx_hash( - "trace-hash", - "trace_hash", - "Emulation transaction by hash to collecting traces. Additional `TransactionHashParams` can be provided via STDIN as a JSON object.", - ) - ) - .subcommand( - SubCommand::with_name("trace-next-block") - .about("Tracing all transactions in the block next to a given block (slot) number. \ - For this command, SLOT argument is required. \ - Additional `TraceNextBlockParams` can be provided via STDIN as a JSON object.") - .arg(token_mint_arg()) - .arg(chain_id_arg()) - .arg(max_steps_arg()) - ) .subcommand( SubCommand::with_name("create-ether-account") .about("Create ethereum account") diff --git a/evm_loader/docker-compose-ci.yml b/evm_loader/docker-compose-ci.yml index 2580a89e9..a8f0e39c5 100644 --- a/evm_loader/docker-compose-ci.yml +++ b/evm_loader/docker-compose-ci.yml @@ -30,11 +30,6 @@ services: NEON_CHAIN_ID: 111 COMMITMENT: confirmed NEON_DB_CLICKHOUSE_URLS: "http://45.250.253.36:8123;http://45.250.253.38:8123" - NEON_DB_INDEXER_HOST: 45.250.253.32 - NEON_DB_INDEXER_PORT: 5432 - NEON_DB_INDEXER_DATABASE: indexer - NEON_DB_INDEXER_USER: postgres - NEON_DB_INDEXER_PASSWORD: $INDEXER_DB_PASSWORD KEYPAIR: /opt/operator-keypairs/id.json FEEPAIR: /opt/operator-keypairs/id.json image: ${EVM_LOADER_IMAGE} diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 0123bd96a..9c0cf5ab2 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -28,8 +28,6 @@ ethnum = { version = "1.4", default-features = false, features = ["serde"] } goblin = { version = "0.6.0" } scroll = "0.11.0" tokio = { version = "1", features = ["full"] } -postgres = { version = "0.19", features = ["with-chrono-0_4", "array-impls"] } -tokio-postgres = { version = "0.7", features = ["with-uuid-0_8"] } lazy_static = "1.4" clickhouse = "0.11.5" tracing = "0.1" diff --git a/evm_loader/lib/src/config.rs b/evm_loader/lib/src/config.rs index be4f0dd33..f1293ff08 100644 --- a/evm_loader/lib/src/config.rs +++ b/evm_loader/lib/src/config.rs @@ -129,29 +129,9 @@ fn load_db_config_from_enviroment() -> ChDbConfig { .map(Some) .unwrap_or(None); - let indexer_host = - env::var("NEON_DB_INDEXER_HOST").expect("neon db indexer host valiable must be set"); - - let indexer_port = - env::var("NEON_DB_INDEXER_PORT").expect("neon db indexer port valiable must be set"); - - let indexer_database = env::var("NEON_DB_INDEXER_DATABASE") - .expect("neon db indexer database valiable must be set"); - - let indexer_user = - env::var("NEON_DB_INDEXER_USER").expect("neon db indexer user valiable must be set"); - - let indexer_password = env::var("NEON_DB_INDEXER_PASSWORD") - .expect("neon db indexer password valiable must be set"); - ChDbConfig { clickhouse_url, clickhouse_user, clickhouse_password, - indexer_host, - indexer_port, - indexer_database, - indexer_user, - indexer_password, } } diff --git a/evm_loader/lib/src/context.rs b/evm_loader/lib/src/context.rs index e05fe4ea9..0d2b8c4b4 100644 --- a/evm_loader/lib/src/context.rs +++ b/evm_loader/lib/src/context.rs @@ -5,6 +5,7 @@ use crate::{ Config, NeonError, }; use solana_clap_utils::keypair::signer_from_path; +use solana_client::nonblocking::rpc_client::RpcClient; use solana_sdk::signature::Signer; pub fn truncate_0x(in_str: &str) -> &str { @@ -24,13 +25,39 @@ impl Context { pub fn signer(&self) -> Result, NeonError> { build_signer(&self.signer_config) } -} -#[must_use] -pub fn create(rpc_client: Arc, signer_config: Arc) -> Context { - Context { - rpc_client, - signer_config, + pub async fn new_from_config( + config: Arc, + slot: Option, + ) -> Result { + let rpc_client: Arc = if let Some(slot) = slot { + Arc::new( + rpc::CallDbClient::new( + crate::types::TracerDb::new( + config.db_config.as_ref().expect("db-config not found"), + ), + slot, + ) + .await?, + ) + } else { + Arc::new(RpcClient::new_with_commitment( + config.json_rpc_url.clone(), + config.commitment, + )) + }; + + Ok(Self { + rpc_client, + signer_config: config.clone(), + }) + } + + pub fn new(rpc_client: Arc, signer_config: Arc) -> Self { + Self { + rpc_client, + signer_config, + } } } diff --git a/evm_loader/lib/src/errors.rs b/evm_loader/lib/src/errors.rs index 207624186..abe19885c 100644 --- a/evm_loader/lib/src/errors.rs +++ b/evm_loader/lib/src/errors.rs @@ -13,7 +13,7 @@ use solana_sdk::signer::SignerError as SolanaSignerError; use thiserror::Error; use crate::commands::init_environment::EnvironmentError; -use crate::types::{ChError, PgError}; +use crate::types::ChError; /// Errors that may be returned by the neon-cli program. #[derive(Debug, Error)] @@ -93,8 +93,6 @@ pub enum NeonError { WrongEnvironment, #[error("Hex Error. {0}")] FromHexError(#[from] hex::FromHexError), - #[error("PostgreSQL Error: {0}")] - PostgresError(#[from] PgError), #[error("Panic: {0}")] Panic(String), #[error("ClickHouse: {0}")] @@ -135,7 +133,6 @@ impl NeonError { NeonError::IncorrectAddress(_) => 248, NeonError::IncorrectIndex(_) => 249, NeonError::TxParametersParsingError(_) => 250, - NeonError::PostgresError(_) => 251, NeonError::ClickHouse(_) => 252, NeonError::EarlySlot(_, _) => 253, } diff --git a/evm_loader/lib/src/rpc/db_call_client.rs b/evm_loader/lib/src/rpc/db_call_client.rs index 24e97e614..a84aa7dce 100644 --- a/evm_loader/lib/src/rpc/db_call_client.rs +++ b/evm_loader/lib/src/rpc/db_call_client.rs @@ -1,5 +1,5 @@ use super::{e, Rpc}; -use crate::types::{TracerDb, TxParams}; +use crate::types::TracerDb; use crate::NeonError; use async_trait::async_trait; use solana_client::{ @@ -192,12 +192,6 @@ impl Rpc for CallDbClient { )) } - async fn get_transaction_data(&self) -> ClientResult { - Err(e!( - "get_transaction_data() not implemented for db_call_client" - )) - } - fn as_any(&self) -> &dyn Any { self } diff --git a/evm_loader/lib/src/rpc/db_trx_client.rs b/evm_loader/lib/src/rpc/db_trx_client.rs deleted file mode 100644 index bf6da857a..000000000 --- a/evm_loader/lib/src/rpc/db_trx_client.rs +++ /dev/null @@ -1,217 +0,0 @@ -use super::{e, Rpc}; -use crate::types::{IndexerDb, TracerDb, TxParams}; -use async_trait::async_trait; -use solana_client::{ - client_error::Result as ClientResult, - client_error::{ClientError, ClientErrorKind}, - rpc_config::{RpcSendTransactionConfig, RpcTransactionConfig}, - rpc_response::{Response, RpcResponseContext, RpcResult}, -}; -use solana_sdk::{ - account::Account, - clock::{Slot, UnixTimestamp}, - commitment_config::CommitmentConfig, - hash::Hash, - pubkey::Pubkey, - signature::Signature, - transaction::Transaction, -}; -use solana_transaction_status::{ - EncodedConfirmedBlock, EncodedConfirmedTransactionWithStatusMeta, TransactionStatus, -}; -use std::any::Any; - -pub struct TrxDbClient { - pub hash: [u8; 32], - sol_sig: [u8; 64], - tracer_db: TracerDb, - indexer_db: IndexerDb, -} - -impl TrxDbClient { - pub async fn new(tracer_db: TracerDb, indexer_db: IndexerDb, hash: [u8; 32]) -> Self { - let sol_sig = indexer_db - .get_sol_sig(&hash) - .await - .unwrap_or_else(|_| panic!("get_sol_sig error, hash: 0x{}", hex::encode(hash))); - - Self { - hash, - sol_sig, - tracer_db, - indexer_db, - } - } -} - -#[async_trait] -impl Rpc for TrxDbClient { - fn commitment(&self) -> CommitmentConfig { - CommitmentConfig::default() - } - - async fn confirm_transaction_with_spinner( - &self, - _signature: &Signature, - _recent_blockhash: &Hash, - _commitment_config: CommitmentConfig, - ) -> ClientResult<()> { - Err(e!( - "confirm_transaction_with_spinner() not implemented for trx rpc client" - )) - } - - async fn get_account(&self, key: &Pubkey) -> ClientResult { - self.tracer_db - .get_account_by_sol_sig(key, &self.sol_sig) - .await - .map_err(|e| e!("load account error", key, e))? - .ok_or_else(|| e!("account not found", key)) - } - - async fn get_account_with_commitment( - &self, - key: &Pubkey, - _commitment: CommitmentConfig, - ) -> RpcResult> { - let account = self - .tracer_db - .get_account_by_sol_sig(key, &self.sol_sig) - .await - .map_err(|e| e!("load account error", key, e))?; - - let slot = self - .indexer_db - .get_slot(&self.hash) - .await - .map_err(|e| e!("get_slot error", e))?; - - let context = RpcResponseContext { - slot, - api_version: None, - }; - Ok(Response { - context, - value: account, - }) - } - - async fn get_multiple_accounts( - &self, - pubkeys: &[Pubkey], - ) -> ClientResult>> { - let mut result = Vec::new(); - for key in pubkeys { - let account = self - .tracer_db - .get_account_by_sol_sig(key, &self.sol_sig) - .await - .map_err(|e| e!("load account error", key, e))?; - result.push(account); - } - Ok(result) - } - - async fn get_account_data(&self, key: &Pubkey) -> ClientResult> { - Ok(self.get_account(key).await?.data) - } - - async fn get_block(&self, _slot: Slot) -> ClientResult { - Err(e!("get_block() not implemented for db_trx_client")) - } - - async fn get_block_time(&self, slot: Slot) -> ClientResult { - self.tracer_db - .get_block_time(slot) - .await - .map_err(|e| e!("get_block_time error", slot, e)) - } - - async fn get_latest_blockhash(&self) -> ClientResult { - Err(e!( - "get_latest_blockhash() not implemented for db_trx_client" - )) - } - - async fn get_minimum_balance_for_rent_exemption(&self, _data_len: usize) -> ClientResult { - Err(e!( - "get_minimum_balance_for_rent_exemption() not implemented for db_trx_client" - )) - } - - async fn get_slot(&self) -> ClientResult { - self.indexer_db - .get_slot(&self.hash) - .await - .map_err(|e| e!("get_slot error", e)) - } - - async fn get_signature_statuses( - &self, - _signatures: &[Signature], - ) -> RpcResult>> { - Err(e!( - "get_signature_statuses() not implemented for db_trx_client" - )) - } - - async fn get_transaction_with_config( - &self, - _signature: &Signature, - _config: RpcTransactionConfig, - ) -> ClientResult { - Err(e!( - "get_transaction_with_config() not implemented for db_trx_client" - )) - } - - async fn send_transaction(&self, _transaction: &Transaction) -> ClientResult { - Err(e!("send_transaction() not implemented for db_trx_client")) - } - - async fn send_and_confirm_transaction_with_spinner( - &self, - _transaction: &Transaction, - ) -> ClientResult { - Err(e!( - "send_and_confirm_transaction_with_spinner() not implemented for db_trx_client" - )) - } - - async fn send_and_confirm_transaction_with_spinner_and_commitment( - &self, - _transaction: &Transaction, - _commitment: CommitmentConfig, - ) -> ClientResult { - Err(e!("send_and_confirm_transaction_with_spinner_and_commitment() not implemented for db_trx_client")) - } - - async fn send_and_confirm_transaction_with_spinner_and_config( - &self, - _transaction: &Transaction, - _commitment: CommitmentConfig, - _config: RpcSendTransactionConfig, - ) -> ClientResult { - Err(e!("send_and_confirm_transaction_with_spinner_and_config() not implemented for db_trx_client")) - } - - async fn get_latest_blockhash_with_commitment( - &self, - _commitment: CommitmentConfig, - ) -> ClientResult<(Hash, u64)> { - Err(e!( - "get_latest_blockhash_with_commitment() not implemented for db_trx_client" - )) - } - - async fn get_transaction_data(&self) -> ClientResult { - self.indexer_db - .get_transaction_data(&self.hash) - .await - .map_err(|e| e!("load transaction error", self.hash, e)) - } - - fn as_any(&self) -> &dyn Any { - self - } -} diff --git a/evm_loader/lib/src/rpc/mod.rs b/evm_loader/lib/src/rpc/mod.rs index 05bbe2404..d6fcc1f7c 100644 --- a/evm_loader/lib/src/rpc/mod.rs +++ b/evm_loader/lib/src/rpc/mod.rs @@ -1,11 +1,8 @@ mod db_call_client; -mod db_trx_client; mod validator_client; pub use db_call_client::CallDbClient; -pub use db_trx_client::TrxDbClient; -use crate::types::TxParams; use crate::{NeonError, NeonResult}; use async_trait::async_trait; use solana_cli::cli::CliError; @@ -83,7 +80,7 @@ pub trait Rpc: Send + Sync { &self, commitment: CommitmentConfig, ) -> ClientResult<(Hash, u64)>; - async fn get_transaction_data(&self) -> ClientResult; + fn as_any(&self) -> &dyn Any; } diff --git a/evm_loader/lib/src/rpc/validator_client.rs b/evm_loader/lib/src/rpc/validator_client.rs index 73ded9193..ab4cbab12 100644 --- a/evm_loader/lib/src/rpc/validator_client.rs +++ b/evm_loader/lib/src/rpc/validator_client.rs @@ -1,9 +1,7 @@ -use super::{e, Rpc}; -use crate::types::TxParams; +use super::Rpc; use async_trait::async_trait; use solana_client::{ client_error::Result as ClientResult, - client_error::{ClientError, ClientErrorKind}, nonblocking::rpc_client::RpcClient, rpc_config::{RpcSendTransactionConfig, RpcTransactionConfig}, rpc_response::RpcResult, @@ -134,12 +132,6 @@ impl Rpc for RpcClient { self.get_latest_blockhash_with_commitment(commitment).await } - async fn get_transaction_data(&self) -> ClientResult { - Err(e!( - "get_transaction_data() not implemented for validator_client" - )) - } - fn as_any(&self) -> &dyn Any { self } diff --git a/evm_loader/lib/src/types/indexer_db.rs b/evm_loader/lib/src/types/indexer_db.rs deleted file mode 100644 index 9a716cee5..000000000 --- a/evm_loader/lib/src/types/indexer_db.rs +++ /dev/null @@ -1,176 +0,0 @@ -use { - super::{do_connect, ChDbConfig, PgError, PgResult, TxParams}, - ethnum::U256, - evm_loader::types::Address, - solana_sdk::clock::Slot, - std::{ - convert::{TryFrom, TryInto}, - sync::Arc, - }, - tokio_postgres::Client, -}; - -#[derive(Debug, Clone)] -pub struct IndexerDb { - pub client: Arc, -} - -const TXPARAMS_FIELDS: &str = - "from_addr, COALESCE(to_addr, contract), calldata, value, gas_limit, nonce"; - -impl IndexerDb { - pub async fn new(config: &ChDbConfig) -> Self { - let client = do_connect( - &config.indexer_host, - &config.indexer_port, - &config.indexer_database, - &config.indexer_user, - &config.indexer_password, - ) - .await; - Self { - client: Arc::new(client), - } - } - - pub async fn get_sol_sig(&self, hash: &[u8; 32]) -> PgResult<[u8; 64]> { - let hex = format!("0x{}", hex::encode(hash)); - let row = self - .client - .query_one( - "SELECT S.sol_sig from solana_neon_transactions S, solana_blocks B \ - where S.block_slot = B.block_slot \ - and B.is_active = true \ - and S.neon_sig = $1", - &[&hex], - ) - .await?; - let sol_sig_b58: &str = row.try_get(0)?; - let sol_sig_b58 = sol_sig_b58.to_string(); - let sol_sig = bs58::decode(sol_sig_b58) - .into_vec() - .map_err(|e| PgError::Custom(format!("sol_sig_b58 cast error: {e}")))?; - sol_sig - .as_slice() - .try_into() - .map_err(|e| PgError::Custom(format!("sol_sig cast error: {e}"))) - } - - pub async fn get_slot(&self, hash: &[u8; 32]) -> PgResult { - let hex = format!("0x{}", hex::encode(hash)); - let row = self - .client - .query_one( - "SELECT min(S.block_slot) from solana_neon_transactions S, solana_blocks B \ - where S.block_slot = B.block_slot \ - and B.is_active = true \ - and S.neon_sig = $1", - &[&hex], - ) - .await?; - let slot: i64 = row.try_get(0)?; - u64::try_from(slot).map_err(|e| PgError::Custom(format!("slot cast error: {e}"))) - } - - #[allow(unused)] - pub async fn get_slot_by_block_hash(&self, block_hash: &[u8; 32]) -> PgResult { - let hex = format!("0x{}", hex::encode(block_hash)); - let row = self - .client - .query_one( - "SELECT block_slot FROM solana_blocks WHERE block_hash = $1 AND is_active = TRUE", - &[&hex], - ) - .await?; - - let slot: i64 = row - .try_get(0) - .map_err(std::convert::Into::::into)?; - - slot.try_into() - .map_err(|e| PgError::Custom(format!("slot cast error: {e}"))) - } - - pub async fn get_transaction_data(&self, hash: &[u8; 32]) -> PgResult { - let hex = format!("0x{}", hex::encode(hash)); - - let row = self - .client - .query_one( - &format!( - "select distinct {TXPARAMS_FIELDS} \ - from neon_transactions as t, solana_blocks as b \ - where t.block_slot = b.block_slot \ - and b.is_active = TRUE \ - and t.neon_sig = $1" - ), - &[&hex], - ) - .await?; - - Self::extract_transaction(&row) - } - - pub async fn get_block_transactions(&self, slot: u64) -> PgResult> { - let slot: i64 = slot - .try_into() - .map_err(|e| PgError::Custom(format!("slot cast error: {e}")))?; - - let rows = self - .client - .query( - &format!( - "\ - SELECT {TXPARAMS_FIELDS} \ - FROM neon_transactions t \ - INNER JOIN solana_blocks b ON t.block_slot = b.block_slot \ - WHERE b.is_active = TRUE AND t.block_slot = $1 \ - ORDER BY tx_idx\ - " - ), - &[&slot], - ) - .await?; - - let mut transactions = vec![]; - for row in rows { - transactions.push(Self::extract_transaction(&row)?); - } - - Ok(transactions) - } - - fn extract_transaction(row: &tokio_postgres::Row) -> PgResult { - let from: String = row.try_get(0)?; - let to: String = row.try_get(1)?; - let data: String = row.try_get(2)?; - let value: String = row.try_get(3)?; - let gas_limit: String = row.try_get(4)?; - let nonce: String = row.try_get(5)?; - - let from = Address::from_hex(&from.as_str()[2..]) - .map_err(|e| PgError::Custom(format!("from_address cast error: {e}")))?; - let to = Address::from_hex(&to.as_str()[2..]) - .map_err(|e| PgError::Custom(format!("to_address cast error: {e}")))?; - let data = hex::decode(&data.as_str()[2..]) - .map_err(|e| PgError::Custom(format!("data cast error: {e}")))?; - let value: U256 = U256::from_str_hex(&value) - .map_err(|e| PgError::Custom(format!("value cast error: {e}")))?; - let gas_limit: U256 = U256::from_str_hex(&gas_limit) - .map_err(|e| PgError::Custom(format!("gas_limit cast error: {e}")))?; - let nonce: u64 = U256::from_str_hex(&nonce) - .map_err(|e| PgError::Custom(format!("nonce cast error: {e}")))? - .try_into() - .map_err(|e| PgError::Custom(format!("nonce cast error: {e}")))?; - - Ok(TxParams { - nonce: Some(nonce), - from, - to: Some(to), - data: Some(data), - value: Some(value), - gas_limit: Some(gas_limit), - access_list: None, - }) - } -} diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index 633b2e785..a3f014d7b 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -1,25 +1,19 @@ -mod indexer_db; pub mod request_models; mod tracer_ch_db; pub use evm_loader::types::Address; -pub use indexer_db::IndexerDb; use lazy_static::lazy_static; use solana_sdk::pubkey::Pubkey; use std::str::FromStr; use tokio::runtime::Runtime; use tokio::task::block_in_place; pub use tracer_ch_db::{ChError, ChResult, ClickHouseDb as TracerDb}; -use tracing::error; -use evm_loader::evm::tracing::{TraceCallConfig, TraceConfig}; +use evm_loader::evm::tracing::TraceCallConfig; use evm_loader::types::hexbytes::HexBytes; use { ethnum::U256, - postgres::NoTls, serde::{Deserialize, Deserializer, Serialize, Serializer}, - thiserror::Error, - tokio_postgres::{connect, Client}, }; #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Eq, Clone, Default)] @@ -27,11 +21,6 @@ pub struct ChDbConfig { pub clickhouse_url: Vec, pub clickhouse_user: Option, pub clickhouse_password: Option, - pub indexer_host: String, - pub indexer_port: String, - pub indexer_database: String, - pub indexer_user: String, - pub indexer_password: String, } #[derive(Clone, Serialize, Deserialize, Debug)] @@ -57,49 +46,6 @@ pub struct TransactionParams { pub trace_config: Option, } -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct TransactionHashParams { - pub trace_config: Option, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct TraceNextBlockParams { - pub trace_config: Option, -} - -pub async fn do_connect( - host: &String, - port: &String, - db: &String, - user: &String, - pass: &String, -) -> Client { - let authority = format!("host={host} port={port} dbname={db} user={user} password={pass}"); - - let mut attempt = 0; - let mut result = None; - - while attempt < 3 { - match connect(&authority, NoTls).await { - Ok(res) => { - result = Some(res); - break; - } - Err(e) => error!("Error connecting to database {authority}: {e}"), - }; - attempt += 1; - } - - let (client, connection) = result.expect("error to set DB connection"); - - tokio::spawn(async move { - if let Err(e) = connection.await { - eprintln!("connection error: {e}"); - } - }); - client -} - lazy_static! { pub static ref RT: Runtime = Runtime::new().unwrap(); } @@ -114,16 +60,6 @@ where } } -#[derive(Error, Debug)] -pub enum PgError { - #[error("postgres: {}", .0)] - Db(#[from] tokio_postgres::Error), - #[error("Custom: {0}")] - Custom(String), -} - -pub type PgResult = std::result::Result; - #[derive(Debug, Default, Clone, Copy)] pub struct PubkeyBase58(pub Pubkey); diff --git a/evm_loader/lib/src/types/request_models.rs b/evm_loader/lib/src/types/request_models.rs index d1b76da52..a1f3b180e 100644 --- a/evm_loader/lib/src/types/request_models.rs +++ b/evm_loader/lib/src/types/request_models.rs @@ -1,6 +1,6 @@ use crate::types::{PubkeyBase58, TxParams}; use ethnum::U256; -use evm_loader::evm::tracing::{TraceCallConfig, TraceConfig}; +use evm_loader::evm::tracing::TraceCallConfig; use evm_loader::types::Address; use serde::{Deserialize, Serialize}; use solana_sdk::debug_account_data::debug_account_data; @@ -104,31 +104,9 @@ pub struct EmulateRequestModel { pub slot: Option, } -#[derive(Deserialize, Serialize, Debug, Default)] -pub struct EmulateHashRequestModel { - #[serde(flatten)] - pub emulation_params: EmulationParamsRequestModel, - pub hash: String, -} - #[derive(Deserialize, Serialize, Debug, Default)] pub struct TraceRequestModel { #[serde(flatten)] pub emulate_request: EmulateRequestModel, pub trace_call_config: Option, } - -#[derive(Deserialize, Serialize, Debug, Default)] -pub struct TraceHashRequestModel { - #[serde(flatten)] - pub emulate_hash_request: EmulateHashRequestModel, - pub trace_config: Option, -} - -#[derive(Deserialize, Serialize, Debug, Default)] -pub struct TraceNextBlockRequestModel { - #[serde(flatten)] - pub emulation_params: EmulationParamsRequestModel, - pub slot: u64, - pub trace_config: Option, -} From e79ec26962d8f34c1c785047756f7c448ddeb41c Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 19 Sep 2023 10:27:00 +0300 Subject: [PATCH 027/318] NDEV-2183: Implement get_sync_status for eth_syncing (#193) * NDEV-2183: Implement get_sync_status for eth_syncing --- evm_loader/lib/src/errors.rs | 2 +- evm_loader/lib/src/types/mod.rs | 3 +- evm_loader/lib/src/types/tracer_ch_common.rs | 131 +++++++++++++ evm_loader/lib/src/types/tracer_ch_db.rs | 183 ++++++++----------- 4 files changed, 209 insertions(+), 110 deletions(-) create mode 100644 evm_loader/lib/src/types/tracer_ch_common.rs diff --git a/evm_loader/lib/src/errors.rs b/evm_loader/lib/src/errors.rs index abe19885c..132e6e5b2 100644 --- a/evm_loader/lib/src/errors.rs +++ b/evm_loader/lib/src/errors.rs @@ -13,7 +13,7 @@ use solana_sdk::signer::SignerError as SolanaSignerError; use thiserror::Error; use crate::commands::init_environment::EnvironmentError; -use crate::types::ChError; +use crate::types::tracer_ch_common::ChError; /// Errors that may be returned by the neon-cli program. #[derive(Debug, Error)] diff --git a/evm_loader/lib/src/types/mod.rs b/evm_loader/lib/src/types/mod.rs index a3f014d7b..69e8099ff 100644 --- a/evm_loader/lib/src/types/mod.rs +++ b/evm_loader/lib/src/types/mod.rs @@ -1,4 +1,5 @@ pub mod request_models; +pub mod tracer_ch_common; mod tracer_ch_db; pub use evm_loader::types::Address; @@ -7,7 +8,7 @@ use solana_sdk::pubkey::Pubkey; use std::str::FromStr; use tokio::runtime::Runtime; use tokio::task::block_in_place; -pub use tracer_ch_db::{ChError, ChResult, ClickHouseDb as TracerDb}; +pub use tracer_ch_db::ClickHouseDb as TracerDb; use evm_loader::evm::tracing::TraceCallConfig; use evm_loader::types::hexbytes::HexBytes; diff --git a/evm_loader/lib/src/types/tracer_ch_common.rs b/evm_loader/lib/src/types/tracer_ch_common.rs new file mode 100644 index 000000000..c7c0e54f4 --- /dev/null +++ b/evm_loader/lib/src/types/tracer_ch_common.rs @@ -0,0 +1,131 @@ +use std::fmt; + +use clickhouse::Row; +use serde::{Deserialize, Serialize}; +use solana_sdk::{account::Account, pubkey::Pubkey}; +use thiserror::Error; + +pub const ROOT_BLOCK_DELAY: u8 = 100; + +#[derive(Error, Debug)] +pub enum ChError { + #[error("clickhouse: {}", .0)] + Db(#[from] clickhouse::error::Error), +} + +pub type ChResult = std::result::Result; + +pub enum SlotStatus { + #[allow(unused)] + Confirmed = 1, + #[allow(unused)] + Processed = 2, + Rooted = 3, +} + +#[derive(Debug, Row, serde::Deserialize, Clone)] +pub struct SlotParent { + pub slot: u64, + pub parent: Option, + pub status: u8, +} + +#[derive(Debug, Row, serde::Deserialize, Clone)] +pub struct SlotParentRooted { + pub slot: u64, + pub parent: Option, +} + +impl From for SlotParent { + fn from(slot_parent_rooted: SlotParentRooted) -> Self { + SlotParent { + slot: slot_parent_rooted.slot, + parent: slot_parent_rooted.parent, + status: SlotStatus::Rooted as u8, + } + } +} + +impl SlotParent { + pub fn is_rooted(&self) -> bool { + self.status == SlotStatus::Rooted as u8 + } +} + +#[derive(Row, serde::Deserialize, Clone)] +pub struct AccountRow { + pub owner: Vec, + pub lamports: u64, + pub executable: bool, + pub rent_epoch: u64, + pub data: Vec, + pub txn_signature: Vec>, +} + +impl fmt::Display for AccountRow { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "AccountRow {{\n owner: {},\n lamports: {},\n executable: {},\n rent_epoch: {},\n}}", + bs58::encode(&self.owner).into_string(), + self.lamports, + self.executable, + self.rent_epoch, + ) + } +} + +impl fmt::Debug for AccountRow { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Account") + .field("owner", &bs58::encode(&self.owner).into_string()) + .field("lamports", &self.lamports) + .field("executable", &self.executable) + .field("rent_epoch", &self.rent_epoch) + .finish() + } +} + +impl TryInto for AccountRow { + type Error = String; + + fn try_into(self) -> Result { + let owner = Pubkey::try_from(self.owner).map_err(|src| { + format!( + "Incorrect slice length ({}) while converting owner from: {src:?}", + src.len(), + ) + })?; + + Ok(Account { + lamports: self.lamports, + data: self.data, + owner, + rent_epoch: self.rent_epoch, + executable: self.executable, + }) + } +} + +pub enum EthSyncStatus { + Syncing(EthSyncing), + Synced, +} + +impl EthSyncStatus { + pub fn new(syncing_status: Option) -> Self { + if let Some(syncing_status) = syncing_status { + Self::Syncing(syncing_status) + } else { + Self::Synced + } + } +} + +#[derive(Row, Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct EthSyncing { + pub starting_block: u64, + pub current_block: u64, + pub highest_block: u64, +} diff --git a/evm_loader/lib/src/types/tracer_ch_db.rs b/evm_loader/lib/src/types/tracer_ch_db.rs index 2b653c4f9..2cf0a1b9d 100644 --- a/evm_loader/lib/src/types/tracer_ch_db.rs +++ b/evm_loader/lib/src/types/tracer_ch_db.rs @@ -1,7 +1,14 @@ -use crate::commands::get_neon_elf::get_elf_parameter; +use crate::{ + commands::get_neon_elf::get_elf_parameter, + types::tracer_ch_common::{AccountRow, ChError, SlotParent, ROOT_BLOCK_DELAY}, +}; + +use super::{ + tracer_ch_common::{ChResult, EthSyncStatus, EthSyncing, SlotParentRooted}, + ChDbConfig, +}; -use super::ChDbConfig; -use clickhouse::{Client, Row}; +use clickhouse::Client; use log::{debug, info}; use rand::Rng; use solana_sdk::{ @@ -14,22 +21,9 @@ use std::{ Ord, Ordering::{Equal, Greater, Less}, }, - convert::TryFrom, - fmt, sync::Arc, time::Instant, }; -use thiserror::Error; - -const ROOT_BLOCK_DELAY: u8 = 100; - -#[derive(Error, Debug)] -pub enum ChError { - #[error("clickhouse: {}", .0)] - Db(#[from] clickhouse::error::Error), -} - -pub type ChResult = std::result::Result; #[allow(dead_code)] #[derive(Clone)] @@ -37,98 +31,6 @@ pub struct ClickHouseDb { pub client: Arc, } -pub enum SlotStatus { - #[allow(unused)] - Confirmed = 1, - #[allow(unused)] - Processed = 2, - Rooted = 3, -} - -#[derive(Debug, Row, serde::Deserialize, Clone)] -pub struct SlotParent { - pub slot: u64, - pub parent: Option, - pub status: u8, -} - -#[derive(Debug, Row, serde::Deserialize, Clone)] -pub struct SlotParentRooted { - pub slot: u64, - pub parent: Option, -} - -impl From for SlotParent { - fn from(slot_parent_rooted: SlotParentRooted) -> Self { - SlotParent { - slot: slot_parent_rooted.slot, - parent: slot_parent_rooted.parent, - status: SlotStatus::Rooted as u8, - } - } -} - -impl SlotParent { - fn is_rooted(&self) -> bool { - self.status == SlotStatus::Rooted as u8 - } -} - -#[derive(Row, serde::Deserialize, Clone)] -pub struct AccountRow { - pub owner: Vec, - pub lamports: u64, - pub executable: bool, - pub rent_epoch: u64, - pub data: Vec, - pub txn_signature: Vec>, -} - -impl fmt::Display for AccountRow { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "AccountRow {{\n owner: {},\n lamports: {},\n executable: {},\n rent_epoch: {},\n}}", - bs58::encode(&self.owner).into_string(), - self.lamports, - self.executable, - self.rent_epoch, - ) - } -} - -impl fmt::Debug for AccountRow { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Account") - .field("owner", &bs58::encode(&self.owner).into_string()) - .field("lamports", &self.lamports) - .field("executable", &self.executable) - .field("rent_epoch", &self.rent_epoch) - .finish() - } -} - -impl TryInto for AccountRow { - type Error = String; - - fn try_into(self) -> Result { - let owner = Pubkey::try_from(self.owner).map_err(|src| { - format!( - "Incorrect slice length ({}) while converting owner from: {src:?}", - src.len(), - ) - })?; - - Ok(Account { - lamports: self.lamports, - data: self.data, - owner, - rent_epoch: self.rent_epoch, - executable: self.executable, - }) - } -} - impl ClickHouseDb { pub fn new(config: &ChDbConfig) -> Self { let url_id = rand::thread_rng().gen_range(0..config.clickhouse_url.len()); @@ -620,6 +522,71 @@ impl ClickHouseDb { } } + pub async fn get_slot_by_blockhash(&self, blockhash: &str) -> ChResult { + let query = r#"SELECT slot + FROM events.notify_block_distributed + WHERE hash = ? + LIMIT 1 + "#; + + let slot = Self::row_opt( + self.client + .query(query) + .bind(blockhash) + .fetch_one::() + .await, + )?; + + match slot { + Some(slot) => Ok(slot), + None => Err(ChError::Db(clickhouse::error::Error::Custom( + "get_slot_by_blockhash: no data available".to_string(), + ))), + } + } + + pub async fn get_sync_status(&self) -> ChResult { + let query_is_startup = r#"SELECT is_startup + FROM events.update_account_distributed + WHERE slot = ( + SELECT MAX(slot) + FROM events.update_account_distributed + ) + LIMIT 1; + "#; + + let is_startup = Self::row_opt( + self.client + .query(query_is_startup) + .fetch_one::() + .await, + )?; + + if let Some(true) = is_startup { + let query = r#"SELECT slot + FROM ( + (SELECT MIN(slot) as slot FROM events.notify_block_distributed) + UNION ALL + (SELECT MAX(slot) as slot FROM events.notify_block_distributed) + UNION ALL + (SELECT MAX(slot) as slot FROM events.notify_block_distributed) + ) + ORDER BY slot ASC + "#; + + let data = Self::row_opt(self.client.query(query).fetch_one::().await)?; + + return match data { + Some(data) => Ok(EthSyncStatus::new(Some(data))), + None => Err(ChError::Db(clickhouse::error::Error::Custom( + "get_sync_status: no data available".to_string(), + ))), + }; + } + + Ok(EthSyncStatus::new(None)) + } + fn row_opt(result: clickhouse::error::Result) -> clickhouse::error::Result> { match result { Ok(row) => Ok(Some(row)), From c54de10ec432471fe429c3d4538e88c8943f6013 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Tue, 19 Sep 2023 10:57:53 +0000 Subject: [PATCH 028/318] NDEV-2081: Upgrade Solana to v1.16.13 (#179) --- .github/workflows/deploy.py | 4 +- Dockerfile | 18 +- evm_loader/Cargo.lock | 1166 ++++++++++++----- evm_loader/api/Cargo.toml | 4 +- evm_loader/cli/Cargo.toml | 8 +- evm_loader/cli/src/config.rs | 6 +- evm_loader/docker-compose-ci.yml | 8 +- evm_loader/lib/Cargo.toml | 12 +- evm_loader/lib/src/commands/get_storage_at.rs | 2 +- evm_loader/lib/src/types/tracer_ch_db.rs | 2 +- evm_loader/program/Cargo.toml | 4 +- .../program/src/evm/precompile/ecrecover.rs | 5 +- .../program/src/external_programs/metaplex.rs | 15 +- evm_loader/solana-run-neon.sh | 2 + rust-toolchain.toml | 2 +- 15 files changed, 881 insertions(+), 377 deletions(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index ef369b528..8c80381a9 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -30,8 +30,8 @@ DOCKER_USER = os.environ.get("DHUBU") DOCKER_PASSWORD = os.environ.get("DHUBP") IMAGE_NAME = 'neonlabsorg/evm_loader' -SOLANA_NODE_VERSION = 'v1.14.20' -SOLANA_BPF_VERSION = 'v1.14.20' +SOLANA_NODE_VERSION = 'v1.16.13' +SOLANA_BPF_VERSION = 'v1.16.13' VERSION_BRANCH_TEMPLATE = r"[vt]{1}\d{1,2}\.\d{1,2}\.x.*" docker_client = docker.APIClient() diff --git a/Dockerfile b/Dockerfile index 84c753576..df963690d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,11 @@ ARG SOLANA_IMAGE # Install BPF SDK -FROM solanalabs/rust:1.64.0 AS builder +FROM solanalabs/rust:1.69.0 AS builder RUN cargo install rustfilt WORKDIR /opt ARG SOLANA_BPF_VERSION RUN sh -c "$(curl -sSfL https://release.solana.com/"${SOLANA_BPF_VERSION}"/install)" && \ - /root/.local/share/solana/install/active_release/bin/sdk/bpf/scripts/install.sh + /root/.local/share/solana/install/active_release/bin/sdk/sbf/scripts/install.sh ENV PATH=/root/.local/share/solana/install/active_release/bin:/usr/local/cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin @@ -18,13 +18,13 @@ ENV NEON_REVISION=${REVISION} RUN cargo fmt --check && \ cargo clippy --release && \ cargo build --release && \ - cargo build-sbf --arch bpf --features devnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-devnet.so && \ - cargo build-sbf --arch bpf --features testnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-testnet.so && \ - cargo build-sbf --arch bpf --features govertest && cp target/deploy/evm_loader.so target/deploy/evm_loader-govertest.so && \ - cargo build-sbf --arch bpf --features govertest,emergency && cp target/deploy/evm_loader.so target/deploy/evm_loader-govertest-emergency.so && \ - cargo build-sbf --arch bpf --features mainnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-mainnet.so && \ - cargo build-sbf --arch bpf --features mainnet,emergency && cp target/deploy/evm_loader.so target/deploy/evm_loader-mainnet-emergency.so && \ - cargo build-sbf --arch bpf --features ci --dump + cargo build-bpf --features devnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-devnet.so && \ + cargo build-bpf --features testnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-testnet.so && \ + cargo build-bpf --features govertest && cp target/deploy/evm_loader.so target/deploy/evm_loader-govertest.so && \ + cargo build-bpf --features govertest,emergency && cp target/deploy/evm_loader.so target/deploy/evm_loader-govertest-emergency.so && \ + cargo build-bpf --features mainnet && cp target/deploy/evm_loader.so target/deploy/evm_loader-mainnet.so && \ + cargo build-bpf --features mainnet,emergency && cp target/deploy/evm_loader.so target/deploy/evm_loader-mainnet-emergency.so && \ + cargo build-bpf --features ci --dump # Build Solidity contracts FROM ethereum/solc:0.8.0 AS solc diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index f89df6da7..405d595c7 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -34,7 +34,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" dependencies = [ "cfg-if", - "cipher 0.3.0", + "cipher", "cpufeatures", "opaque-debug", ] @@ -47,7 +47,7 @@ checksum = "589c637f0e68c877bbd59a4599bbe849cac8e5f3e4b5a3ebae8f528cd218dcdc" dependencies = [ "aead", "aes", - "cipher 0.3.0", + "cipher", "ctr", "polyval", "subtle", @@ -65,6 +65,18 @@ dependencies = [ "version_check", ] +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "getrandom 0.2.9", + "once_cell", + "version_check", +] + [[package]] name = "aho-corasick" version = "0.7.20" @@ -113,6 +125,129 @@ version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" +[[package]] +name = "ark-bn254" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", + "itertools", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest 0.10.7", + "itertools", + "num-bigint 0.4.3", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote 1.0.32", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint 0.4.3", + "num-traits", + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 1.0.109", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest 0.10.7", + "num-bigint 0.4.3", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 1.0.109", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "array-bytes" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ad284aeb45c13f2fb4f084de4a420ebf447423bdf9386c0540ce33cb3ef4b8c" + [[package]] name = "arrayref" version = "0.3.7" @@ -176,11 +311,22 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + [[package]] name = "async-compression" -version = "0.3.15" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942c7cd7ae39e91bde4820d74132e9862e62c2f386c3aa90ccf55949f5bad63a" +checksum = "d495b6dc0184693324491a5ac05f559acc97bf937ab31d7a1c33dd0016be6d2b" dependencies = [ "brotli", "flate2", @@ -290,9 +436,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.0" +version = "0.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" +checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" [[package]] name = "base64ct" @@ -332,16 +478,16 @@ dependencies = [ [[package]] name = "blake3" -version = "1.3.1" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08e53fc5a564bb15bfe6fae56bd71522205f1f91893f9c0116edad6496c183f" +checksum = "199c42ab6972d92c9f8995f086273d25c42fc0f7b2a1fcefba465c1352d25ba5" dependencies = [ "arrayref", "arrayvec", "cc", "cfg-if", "constant_time_eq", - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -375,18 +521,41 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" dependencies = [ - "borsh-derive", + "borsh-derive 0.9.3", "hashbrown 0.11.2", ] +[[package]] +name = "borsh" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" +dependencies = [ + "borsh-derive 0.10.3", + "hashbrown 0.12.3", +] + [[package]] name = "borsh-derive" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" dependencies = [ - "borsh-derive-internal", - "borsh-schema-derive-internal", + "borsh-derive-internal 0.9.3", + "borsh-schema-derive-internal 0.9.3", + "proc-macro-crate 0.1.5", + "proc-macro2 1.0.66", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7" +dependencies = [ + "borsh-derive-internal 0.10.3", + "borsh-schema-derive-internal 0.10.3", "proc-macro-crate 0.1.5", "proc-macro2 1.0.66", "syn 1.0.109", @@ -403,6 +572,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "borsh-derive-internal" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb" +dependencies = [ + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 1.0.109", +] + [[package]] name = "borsh-schema-derive-internal" version = "0.9.3" @@ -414,6 +594,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "borsh-schema-derive-internal" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd" +dependencies = [ + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 1.0.109", +] + [[package]] name = "brotli" version = "3.3.4" @@ -557,16 +748,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", -] - [[package]] name = "clap" version = "2.34.0" @@ -591,7 +772,7 @@ dependencies = [ "atty", "bitflags 1.3.2", "clap_lex", - "indexmap", + "indexmap 1.9.3", "once_cell", "strsim 0.10.0", "termcolor", @@ -673,17 +854,26 @@ dependencies = [ "unreachable", ] +[[package]] +name = "concurrent-queue" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "console" -version = "0.15.5" +version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d79fbe8970a77e3e34151cc13d3b3e248aa0faaecb9f6091fa07ebefe5ad60" +checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" dependencies = [ "encode_unicode", "lazy_static", "libc", "unicode-width", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -734,9 +924,9 @@ dependencies = [ [[package]] name = "constant_time_eq" -version = "0.1.5" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" [[package]] name = "core-foundation" @@ -860,17 +1050,17 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" dependencies = [ - "cipher 0.3.0", + "cipher", ] [[package]] name = "ctrlc" -version = "3.2.5" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbcf33c2a618cbe41ee43ae6e9f2e48368cd9f9db2896f10167d8d762679f639" +checksum = "82e95fbd621905b854affdc67943b043a0fbb6ed7385fd5a25650d19a8a6cfdf" dependencies = [ - "nix 0.26.2", - "windows-sys 0.45.0", + "nix 0.27.1", + "windows-sys 0.48.0", ] [[package]] @@ -931,6 +1121,41 @@ dependencies = [ "syn 2.0.28", ] +[[package]] +name = "darling" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2 1.0.66", + "quote 1.0.32", + "strsim 0.10.0", + "syn 2.0.28", +] + +[[package]] +name = "darling_macro" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +dependencies = [ + "darling_core", + "quote 1.0.32", + "syn 2.0.28", +] + [[package]] name = "data-encoding" version = "2.3.3" @@ -966,6 +1191,17 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e5c37193a1db1d8ed868c03ec7b152175f26160a5b740e5e484143877e0adf0" +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 1.0.109", +] + [[package]] name = "dialoguer" version = "0.10.4" @@ -989,9 +1225,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", "crypto-common", @@ -1117,34 +1353,22 @@ dependencies = [ [[package]] name = "enum-iterator" -version = "0.8.1" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2953d1df47ac0eb70086ccabf0275aa8da8591a28bd358ee2b52bd9f9e3ff9e9" +checksum = "7add3873b5dd076766ee79c8e406ad1a472c385476b9e38849f8eec24f1be689" dependencies = [ "enum-iterator-derive", ] [[package]] name = "enum-iterator-derive" -version = "0.8.1" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8958699f9359f0b04e691a13850d48b7de329138023876d07cbd024c2c820598" +checksum = "eecf8589574ce9b895052fa12d69af7a233f99e6107f5cb8dd1044f2a17bfdcb" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", - "syn 1.0.109", -] - -[[package]] -name = "enum_dispatch" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11f36e95862220b211a6e2aa5eca09b4fa391b13cd52ceb8035a24bf65a79de2" -dependencies = [ - "once_cell", - "proc-macro2 1.0.66", - "quote 1.0.32", - "syn 1.0.109", + "syn 2.0.28", ] [[package]] @@ -1160,6 +1384,12 @@ dependencies = [ "termcolor", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "errno" version = "0.3.1" @@ -1202,7 +1432,7 @@ version = "1.5.0-dev" dependencies = [ "arrayref", "bincode", - "borsh", + "borsh 0.9.3", "cfg-if", "const_format", "ethnum", @@ -1394,15 +1624,6 @@ dependencies = [ "slab", ] -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - [[package]] name = "generic-array" version = "0.14.7" @@ -1484,7 +1705,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 1.9.3", "slab", "tokio", "tokio-util", @@ -1506,7 +1727,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" dependencies = [ - "ahash", + "ahash 0.7.6", ] [[package]] @@ -1515,9 +1736,24 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash", + "ahash 0.7.6", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash 0.8.3", ] +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + [[package]] name = "heck" version = "0.3.3" @@ -1559,9 +1795,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hidapi" -version = "1.5.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "798154e4b6570af74899d71155fb0072d5b17e6aa12f39c8ef22c60fb8ec99e7" +checksum = "723777263b0dcc5730aec947496bd8c3940ba63c15f5633b288cc615f4f6af79" dependencies = [ "cc", "libc", @@ -1591,7 +1827,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -1677,15 +1913,16 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.23.2" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" +checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" dependencies = [ + "futures-util", "http", "hyper", - "rustls", + "rustls 0.21.7", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", ] [[package]] @@ -1725,6 +1962,12 @@ dependencies = [ "cxx-build", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "0.3.0" @@ -1762,24 +2005,26 @@ dependencies = [ ] [[package]] -name = "indicatif" -version = "0.16.2" +name = "indexmap" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d207dc617c7a380ab07ff572a6e52fa202a2a8f355860ac9c38e23f8196be1b" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" dependencies = [ - "console", - "lazy_static", - "number_prefix", - "regex", + "equivalent", + "hashbrown 0.14.0", ] [[package]] -name = "inout" -version = "0.1.3" +name = "indicatif" +version = "0.17.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +checksum = "0b297dc40733f23a0e52728a58fa9489a5b7638a324932de16b41adc3ef80730" dependencies = [ - "generic-array", + "console", + "instant", + "number_prefix", + "portable-atomic", + "unicode-width", ] [[package]] @@ -1834,9 +2079,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.61" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" dependencies = [ "wasm-bindgen", ] @@ -1873,19 +2118,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.142" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" - -[[package]] -name = "libloading" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" -dependencies = [ - "cfg-if", - "winapi", -] +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libsecp256k1" @@ -1944,12 +2179,6 @@ dependencies = [ "cc", ] -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - [[package]] name = "linked_list_allocator" version = "0.10.5" @@ -2033,9 +2262,9 @@ dependencies = [ [[package]] name = "memoffset" -version = "0.6.5" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" dependencies = [ "autocfg", ] @@ -2049,6 +2278,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + [[package]] name = "merlin" version = "3.0.0" @@ -2096,13 +2334,13 @@ dependencies = [ [[package]] name = "mpl-token-auth-rules" -version = "1.4.1" +version = "1.4.3-beta.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c376f2cc7dae80e2949cd6ca8a2420b3c61c1ecb7a275c6433d9a4d2d24f994d" +checksum = "81a34d740606a10a9dac7507d0c9025d72e0ce311c68ae85b6634982cf69a9c6" dependencies = [ - "borsh", + "borsh 0.9.3", "bytemuck", - "mpl-token-metadata-context-derive", + "mpl-token-metadata-context-derive 0.2.1", "num-derive", "num-traits", "rmp-serde", @@ -2115,14 +2353,14 @@ dependencies = [ [[package]] name = "mpl-token-metadata" -version = "1.12.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f661ff8c1d64c48cf207c0d259783d411a4249058c1b861fabd8bb6ce30ae4d8" +checksum = "654976568c99887549e1291e7b7e55ae31a70732e56ebb25cb1cdfc08c018333" dependencies = [ "arrayref", - "borsh", + "borsh 0.9.3", "mpl-token-auth-rules", - "mpl-token-metadata-context-derive", + "mpl-token-metadata-context-derive 0.3.0", "mpl-utils", "num-derive", "num-traits", @@ -2143,16 +2381,25 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "mpl-token-metadata-context-derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a739019e11d93661a64ef5fe108ab17c79b35961e944442ff6efdd460ad01a" +dependencies = [ + "quote 1.0.32", + "syn 1.0.109", +] + [[package]] name = "mpl-utils" -version = "0.2.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "822133b6cba8f9a43e5e0e189813be63dd795858f54155c729833be472ffdb51" +checksum = "3f2e4f92aec317d5853c0cc4c03c55f5178511c45bb3dbb441aea63117bf3dc9" dependencies = [ "arrayref", - "borsh", "solana-program", - "spl-token", + "spl-token-2022", ] [[package]] @@ -2253,26 +2500,27 @@ dependencies = [ [[package]] name = "nix" -version = "0.24.3" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" +checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" dependencies = [ "bitflags 1.3.2", "cfg-if", "libc", - "memoffset 0.6.5", + "memoffset 0.7.1", + "pin-utils", + "static_assertions", ] [[package]] name = "nix" -version = "0.26.2" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.0", "cfg-if", "libc", - "static_assertions", ] [[package]] @@ -2410,7 +2658,16 @@ version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" dependencies = [ - "num_enum_derive", + "num_enum_derive 0.5.11", +] + +[[package]] +name = "num_enum" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" +dependencies = [ + "num_enum_derive 0.6.1", ] [[package]] @@ -2425,6 +2682,18 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "num_enum_derive" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 2.0.28", +] + [[package]] name = "number_prefix" version = "0.4.0" @@ -2552,7 +2821,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -2646,6 +2915,12 @@ dependencies = [ "universal-hash", ] +[[package]] +name = "portable-atomic" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31114a898e107c51bb1609ffaf55a0e011cf6a4d7f1170d0015a165082c0338b" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -2706,17 +2981,16 @@ dependencies = [ [[package]] name = "quinn" -version = "0.8.5" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b435e71d9bfa0d8889927231970c51fb89c58fa63bffcab117c9c7a41e5ef8f" +checksum = "2e8b432585672228923edbbf64b8b12c14e1112f62e88737655b4a083dbcd78e" dependencies = [ "bytes", - "futures-channel", - "futures-util", - "fxhash", + "pin-project-lite", "quinn-proto", "quinn-udp", - "rustls", + "rustc-hash", + "rustls 0.20.8", "thiserror", "tokio", "tracing", @@ -2725,17 +2999,16 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.8.4" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fce546b9688f767a57530652488420d419a8b1f44a478b451c3d1ab6d992a55" +checksum = "f31999cfc7927c4e212e60fd50934ab40e8e8bfd2d493d6095d2d306bc0764d9" dependencies = [ "bytes", - "fxhash", "rand 0.8.5", "ring", - "rustls", + "rustc-hash", + "rustls 0.20.8", "rustls-native-certs", - "rustls-pemfile 0.2.1", "slab", "thiserror", "tinyvec", @@ -2745,16 +3018,15 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.1.4" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b07946277141531aea269befd949ed16b2c85a780ba1043244eda0969e538e54" +checksum = "641538578b21f5e5c8ea733b736895576d0fe329bb883b937db6f4d163dbaaf4" dependencies = [ - "futures-util", "libc", "quinn-proto", "socket2", - "tokio", "tracing", + "windows-sys 0.42.0", ] [[package]] @@ -2907,9 +3179,9 @@ dependencies = [ [[package]] name = "rcgen" -version = "0.9.3" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6413f3de1edee53342e6138e75b56d32e7bc6e332b3bd62d497b1929d4cfbcdd" +checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" dependencies = [ "pem", "ring", @@ -2983,12 +3255,12 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "reqwest" -version = "0.11.16" +version = "0.11.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b71749df584b7f4cac2c426c127a7c785a5106cc98f7a8feb044115f0fa254" +checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" dependencies = [ "async-compression", - "base64 0.21.0", + "base64 0.21.4", "bytes", "encoding_rs", "futures-core", @@ -3005,20 +3277,20 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls", - "rustls-pemfile 1.0.2", + "rustls 0.21.7", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", "tokio-util", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", + "webpki-roots 0.25.2", "winreg", ] @@ -3043,7 +3315,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -3080,13 +3352,22 @@ dependencies = [ [[package]] name = "rpassword" -version = "6.0.1" +version = "7.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bf099a1888612545b683d2661a1940089f6c2e5a8e38979b2159da876bfd956" +checksum = "6678cf63ab3491898c0d021b493c94c9b221d91295294a2a5746eacbe5928322" +dependencies = [ + "libc", + "rtoolbox", + "winapi", +] + +[[package]] +name = "rtoolbox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "034e22c514f5c0cb8a10ff341b9b048b5ceb21591f31c8f44c43b960f9b3524a" dependencies = [ "libc", - "serde", - "serde_json", "winapi", ] @@ -3152,6 +3433,18 @@ dependencies = [ "webpki", ] +[[package]] +name = "rustls" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" +dependencies = [ + "log", + "ring", + "rustls-webpki", + "sct", +] + [[package]] name = "rustls-native-certs" version = "0.6.2" @@ -3159,27 +3452,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" dependencies = [ "openssl-probe", - "rustls-pemfile 1.0.2", + "rustls-pemfile", "schannel", "security-framework", ] [[package]] name = "rustls-pemfile" -version = "0.2.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9" +checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" dependencies = [ - "base64 0.13.1", + "base64 0.21.4", ] [[package]] -name = "rustls-pemfile" -version = "1.0.2" +name = "rustls-webpki" +version = "0.101.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +checksum = "7d93931baf2d282fff8d3a532bbfd7653f734643161b87e3e01e59a04439bf0d" dependencies = [ - "base64 0.21.0", + "ring", + "untrusted", ] [[package]] @@ -3358,16 +3652,39 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_with" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe" +dependencies = [ + "serde", + "serde_with_macros", +] + +[[package]] +name = "serde_with_macros" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" +dependencies = [ + "darling", + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 2.0.28", +] + [[package]] name = "serde_yaml" -version = "0.8.26" +version = "0.9.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b" +checksum = "1a49e178e4452f45cb61d0cd8cebc1b0fafd3e41929e996cef79aa3aca91f574" dependencies = [ - "indexmap", + "indexmap 2.0.0", + "itoa", "ryu", "serde", - "yaml-rust", + "unsafe-libyaml", ] [[package]] @@ -3378,7 +3695,7 @@ checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -3402,7 +3719,7 @@ checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -3423,7 +3740,7 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54c2bb1a323307527314a36bfb73f24febb08ce2b8a554bf4ffd6f51ad15198c" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", "keccak", ] @@ -3528,12 +3845,12 @@ dependencies = [ [[package]] name = "solana-account-decoder" -version = "1.14.20" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6e4e7166dc87b235d087997fd89724d82d0b83f75551fbb1d3d692a47ac237f" +checksum = "b83daa56035885dac1a47f5bd3d4e02379e3fc5915b2c3ce978a9af9eeecf07d" dependencies = [ "Inflector", - "base64 0.13.1", + "base64 0.21.4", "bincode", "bs58", "bv", @@ -3544,7 +3861,6 @@ dependencies = [ "solana-address-lookup-table-program", "solana-config-program", "solana-sdk", - "solana-vote-program", "spl-token", "spl-token-2022", "thiserror", @@ -3553,9 +3869,9 @@ dependencies = [ [[package]] name = "solana-address-lookup-table-program" -version = "1.14.20" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8669314c1bab81668baff87db9e81fcf72e15f61d9904e423f13911d8e3949cc" +checksum = "2dd3f3e85d67e559985fbdc6b5b4d5dd9c8462b78e6079c3b465496c1f3c55d6" dependencies = [ "bincode", "bytemuck", @@ -3574,16 +3890,16 @@ dependencies = [ [[package]] name = "solana-bpf-loader-program" -version = "1.14.20" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9492c78a61eb825fee7e2e632037b89ff6e09023a5d37ee6639318316fa071d2" +checksum = "3da230f2ff22007e2ca60507346488a65ec274fbb2486bdd2d10948eef2c03d8" dependencies = [ "bincode", "byteorder", "libsecp256k1", "log", + "rand 0.7.3", "solana-measure", - "solana-metrics", "solana-program-runtime", "solana-sdk", "solana-zk-token-sdk", @@ -3593,9 +3909,9 @@ dependencies = [ [[package]] name = "solana-clap-utils" -version = "1.14.20" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d294b68c3a9f67aedde39c799fed85139d779a332280094054446f5b55a2edad" +checksum = "3669a399b8ef60642471e68e1f93d3f3050248a4fa1436341596cfcb2a484e8b" dependencies = [ "chrono", "clap 2.34.0", @@ -3611,9 +3927,9 @@ dependencies = [ [[package]] name = "solana-cli" -version = "1.14.20" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e21daca34f4f0462c54931193e6e613c589bb3c312ee79f35dc0994c8fe8bd9f" +checksum = "05046d0c42224578516c307893b486156507de627c5ac006079f936a90f31dce" dependencies = [ "bincode", "bs58", @@ -3623,6 +3939,7 @@ dependencies = [ "criterion-stats", "crossbeam-channel", "ctrlc", + "hex", "humantime", "log", "num-traits", @@ -3643,8 +3960,13 @@ dependencies = [ "solana-faucet", "solana-logger", "solana-program-runtime", + "solana-pubsub-client", "solana-remote-wallet", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-rpc-client-nonce-utils", "solana-sdk", + "solana-tpu-client", "solana-transaction-status", "solana-version", "solana-vote-program", @@ -3656,9 +3978,9 @@ dependencies = [ [[package]] name = "solana-cli-config" -version = "1.14.20" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "073a01cadf661c50373549add14d21436dcfed0fbc88022817481c6a18340fc8" +checksum = "79b593a0718a12d73fff3c5d9d405981c778a1806c66d327f5bdef0bec23402f" dependencies = [ "dirs-next", "lazy_static", @@ -3672,12 +3994,12 @@ dependencies = [ [[package]] name = "solana-cli-output" -version = "1.14.20" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953484f2c794afb2643907158f3433c209becd12e3943449d281ef6c1b68c69e" +checksum = "0518efb44a2586f0aa7bf01fa6f90d3cd4e047a90ccfef799adb6e248bf79773" dependencies = [ "Inflector", - "base64 0.13.1", + "base64 0.21.4", "chrono", "clap 2.34.0", "console", @@ -3690,7 +4012,7 @@ dependencies = [ "solana-account-decoder", "solana-clap-utils", "solana-cli-config", - "solana-client", + "solana-rpc-client-api", "solana-sdk", "solana-transaction-status", "solana-vote-program", @@ -3699,63 +4021,42 @@ dependencies = [ [[package]] name = "solana-client" -version = "1.14.20" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b3c55fbbc68dbf7b2df2ba01038d6d2a65522deec3db9c7b15e9c8c1d9dc526" +checksum = "e96d8a28ca30cd385f7c2c4a7f93edc32c18bc041baa0e8b25bd56cd28c51cbb" dependencies = [ - "async-mutex", "async-trait", - "base64 0.13.1", "bincode", - "bs58", - "bytes", - "clap 2.34.0", - "crossbeam-channel", - "enum_dispatch", "futures", "futures-util", - "indexmap", + "indexmap 1.9.3", "indicatif", - "itertools", - "jsonrpc-core", - "lazy_static", "log", "quinn", - "quinn-proto", "rand 0.7.3", - "rand_chacha 0.2.2", "rayon", - "reqwest", - "rustls", - "semver", - "serde", - "serde_derive", - "serde_json", - "solana-account-decoder", - "solana-clap-utils", - "solana-faucet", + "solana-connection-cache", "solana-measure", "solana-metrics", - "solana-net-utils", + "solana-pubsub-client", + "solana-quic-client", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-rpc-client-nonce-utils", "solana-sdk", "solana-streamer", - "solana-transaction-status", - "solana-version", - "solana-vote-program", - "spl-token-2022", + "solana-thin-client", + "solana-tpu-client", + "solana-udp-client", "thiserror", "tokio", - "tokio-stream", - "tokio-tungstenite", - "tungstenite", - "url", ] [[package]] name = "solana-config-program" -version = "1.14.20" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6faa5fbf80687e39850c3139561b38d35f9d35e248adaccc4b6379ee41846638" +checksum = "0a35e4cc9f2996a2ef95aac398443fc4a110ef585521e11a7685b3591648b7cf" dependencies = [ "bincode", "chrono", @@ -3765,11 +4066,32 @@ dependencies = [ "solana-sdk", ] +[[package]] +name = "solana-connection-cache" +version = "1.16.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ecb12464ee1322a02635345522839958d78a2bacff18298991cacf298178f64" +dependencies = [ + "async-trait", + "bincode", + "futures-util", + "indexmap 1.9.3", + "log", + "rand 0.7.3", + "rayon", + "rcgen", + "solana-measure", + "solana-metrics", + "solana-sdk", + "thiserror", + "tokio", +] + [[package]] name = "solana-faucet" -version = "1.14.20" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3084d18786564211573d5043550ea2750c049eaf3c75ae35ed8e9e845a0dda" +checksum = "fa14ab9f44667719270dd174538d0c0fa869ddfb69a1b2ac1aa2d510e98da009" dependencies = [ "bincode", "byteorder", @@ -3791,13 +4113,13 @@ dependencies = [ [[package]] name = "solana-frozen-abi" -version = "1.14.20" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a100b7fa8198c20354eb7256c0d9789107d8a62280221f3efe15f7c9dc4cec" +checksum = "35b9e2169fd13394af838b13f047067c35ce69372aea0fb46e026405b5e931f9" dependencies = [ - "ahash", + "ahash 0.8.3", "blake3", - "block-buffer 0.9.0", + "block-buffer 0.10.4", "bs58", "bv", "byteorder", @@ -3805,7 +4127,6 @@ dependencies = [ "either", "generic-array", "getrandom 0.1.16", - "hashbrown 0.12.3", "im", "lazy_static", "log", @@ -3825,21 +4146,21 @@ dependencies = [ [[package]] name = "solana-frozen-abi-macro" -version = "1.14.20" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f527f44601b35dd67d11bc72f2f7512976a466f9304ef574b87dac83ced8a42" +checksum = "db08ab0af4007dc0954b900aa5febc0c0ae50d9f9f598be27263c3195d90240b" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", "rustc_version", - "syn 1.0.109", + "syn 2.0.28", ] [[package]] name = "solana-logger" -version = "1.14.20" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8632c8bc480bb5615b70a18b807ede73024aebc7761503ff86a70b7f4906ae47" +checksum = "bf8a48e734f78a44399516f7c130c114b455911e351f001abc0d96e7c5694efa" dependencies = [ "env_logger", "lazy_static", @@ -3848,9 +4169,9 @@ dependencies = [ [[package]] name = "solana-measure" -version = "1.14.20" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a3d09e890127454f43ffc37a6e23a375fe86c5159c4e5d4767d446ddb7e93a3" +checksum = "d3529d2ff63ceedd3707c51188aacb9e3c142118de3f55447c40584a78223ffd" dependencies = [ "log", "solana-sdk", @@ -3858,9 +4179,9 @@ dependencies = [ [[package]] name = "solana-metrics" -version = "1.14.20" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "185128a041b4c1eaeec7f2034673ce89f99ee364fcb4405313edb1bc26ac95dd" +checksum = "4792f29de5378a13c51be3fa9fdd526a20550b5ffabd7d1a57a4e49468e17d90" dependencies = [ "crossbeam-channel", "gethostname", @@ -3872,15 +4193,15 @@ dependencies = [ [[package]] name = "solana-net-utils" -version = "1.14.20" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16497e2cc753a0a35fb34c73846495fa21ba04a4e64cb92d818c4cb31c935fcc" +checksum = "7ed75beb465e211c79d31ae2049cb85974203e5ac21ae89396378d5a2fe71962" dependencies = [ "bincode", "clap 3.2.23", "crossbeam-channel", "log", - "nix 0.24.3", + "nix 0.26.2", "rand 0.7.3", "serde", "serde_derive", @@ -3894,11 +4215,11 @@ dependencies = [ [[package]] name = "solana-perf" -version = "1.14.20" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc65488c030174215a0176e44f889aed937c172ea1886c878f25ad7ce63f189" +checksum = "9218d9c823b22a465f91c966e8254a5f57b6817e0121ec6d4bf9a5ddc8307f18" dependencies = [ - "ahash", + "ahash 0.8.3", "bincode", "bv", "caps", @@ -3909,7 +4230,7 @@ dependencies = [ "lazy_static", "libc", "log", - "nix 0.24.3", + "nix 0.26.2", "rand 0.7.3", "rayon", "serde", @@ -3921,16 +4242,21 @@ dependencies = [ [[package]] name = "solana-program" -version = "1.14.20" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51ad5f48743ce505f6139a07e20aecdc689def12da7230fed661c2073ab97df8" +checksum = "2f17a1fbcf1e94e282db16153d323b446d6386ac99f597f78e76332265829336" dependencies = [ - "base64 0.13.1", + "ark-bn254", + "ark-ec", + "ark-ff", + "ark-serialize", + "array-bytes", + "base64 0.21.4", "bincode", "bitflags 1.3.2", "blake3", - "borsh", - "borsh-derive", + "borsh 0.10.3", + "borsh 0.9.3", "bs58", "bv", "bytemuck", @@ -3945,7 +4271,8 @@ dependencies = [ "libc", "libsecp256k1", "log", - "memoffset 0.6.5", + "memoffset 0.9.0", + "num-bigint 0.4.3", "num-derive", "num-traits", "parking_lot", @@ -3970,20 +4297,20 @@ dependencies = [ [[package]] name = "solana-program-runtime" -version = "1.14.20" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e837e539fee15e553bfc6e041bcfbc1113db6e437c21f0319536c4ea1621b884" +checksum = "2ff9f0c8043b2e7921e25a3fee88fa253b8cb5dbab1e521a4d83e78e8874c551" dependencies = [ - "base64 0.13.1", + "base64 0.21.4", "bincode", "eager", "enum-iterator", "itertools", "libc", - "libloading", "log", "num-derive", "num-traits", + "percentage", "rand 0.7.3", "rustc_version", "serde", @@ -3992,14 +4319,68 @@ dependencies = [ "solana-measure", "solana-metrics", "solana-sdk", + "solana_rbpf", + "thiserror", +] + +[[package]] +name = "solana-pubsub-client" +version = "1.16.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e0659db803f68fb440c87f43a603e2da7adb3dd11d68e119c3209ed3ca02073" +dependencies = [ + "crossbeam-channel", + "futures-util", + "log", + "reqwest", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder", + "solana-rpc-client-api", + "solana-sdk", + "thiserror", + "tokio", + "tokio-stream", + "tokio-tungstenite", + "tungstenite", + "url", +] + +[[package]] +name = "solana-quic-client" +version = "1.16.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd4e0689f7b3b2e98e73089bf3aa6b3290cb8a2cbff97fca2ee579cc3ca2717e" +dependencies = [ + "async-mutex", + "async-trait", + "futures", + "itertools", + "lazy_static", + "log", + "quinn", + "quinn-proto", + "quinn-udp", + "rcgen", + "rustls 0.20.8", + "solana-connection-cache", + "solana-measure", + "solana-metrics", + "solana-net-utils", + "solana-rpc-client-api", + "solana-sdk", + "solana-streamer", "thiserror", + "tokio", ] [[package]] name = "solana-rayon-threadlimit" -version = "1.14.20" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aa7a1bc3d3e611952e10c9447094f5c2816b5bb8122c6710a6f28395595a671" +checksum = "ab3c3996bd418c45a540ee2c2d23e9796c244d3e5c9f135a86aa8501e1afea19" dependencies = [ "lazy_static", "num_cpus", @@ -4007,9 +4388,9 @@ dependencies = [ [[package]] name = "solana-remote-wallet" -version = "1.14.20" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e4fb5902f71b3965b75a6418874f1d2bff525e4e49108e5f2ea174a5213b66" +checksum = "40927d4df440e354f618cbf9e5eb81e02cf4563ef8360782b5493f395b63f61a" dependencies = [ "console", "dialoguer", @@ -4025,23 +4406,84 @@ dependencies = [ "uriparse", ] +[[package]] +name = "solana-rpc-client" +version = "1.16.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "871cf6d60098c556755a3a7dbd1742201718220a13b988d012f0658eddaad674" +dependencies = [ + "async-trait", + "base64 0.21.4", + "bincode", + "bs58", + "indicatif", + "log", + "reqwest", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder", + "solana-rpc-client-api", + "solana-sdk", + "solana-transaction-status", + "solana-version", + "solana-vote-program", + "tokio", +] + +[[package]] +name = "solana-rpc-client-api" +version = "1.16.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3214d68e3b661ddfd960271f67eb8042298ac7d90d9bd86d330200c3a5518404" +dependencies = [ + "base64 0.21.4", + "bs58", + "jsonrpc-core", + "reqwest", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder", + "solana-sdk", + "solana-transaction-status", + "solana-version", + "spl-token-2022", + "thiserror", +] + +[[package]] +name = "solana-rpc-client-nonce-utils" +version = "1.16.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf08c480fb3d0d861abe10a0517990edea8151529ccf537c0a833233f1381d8" +dependencies = [ + "clap 2.34.0", + "solana-clap-utils", + "solana-rpc-client", + "solana-sdk", + "thiserror", +] + [[package]] name = "solana-sdk" -version = "1.14.20" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c515a5a5a5cdc115044c33959eb4d091680f5e7ca8be9eb5218fb0c21bf3568" +checksum = "74a01f25b9f4022fc222c21c589ef7943027fb0fa2b9f6ae943fc4a65c2c01a2" dependencies = [ "assert_matches", - "base64 0.13.1", + "base64 0.21.4", "bincode", "bitflags 1.3.2", - "borsh", + "borsh 0.10.3", "bs58", "bytemuck", "byteorder", "chrono", "derivation-path", - "digest 0.10.6", + "digest 0.10.7", "ed25519-dalek", "ed25519-dalek-bip32", "generic-array", @@ -4054,6 +4496,7 @@ dependencies = [ "memmap2", "num-derive", "num-traits", + "num_enum 0.6.1", "pbkdf2 0.11.0", "qstring", "rand 0.7.3", @@ -4064,6 +4507,7 @@ dependencies = [ "serde_bytes", "serde_derive", "serde_json", + "serde_with", "sha2 0.10.6", "sha3 0.10.7", "solana-frozen-abi", @@ -4078,38 +4522,42 @@ dependencies = [ [[package]] name = "solana-sdk-macro" -version = "1.14.20" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bbc3ab3070c090e1a18fd5a0a07d729d0db2bc8524414dc3e16504286d38049" +checksum = "a75b33716470fa4a65a23ddc2d4abcb8d28532c6e3ae3f04f4fe79b5e1f8c247" dependencies = [ "bs58", "proc-macro2 1.0.66", "quote 1.0.32", "rustversion", - "syn 1.0.109", + "syn 2.0.28", ] [[package]] name = "solana-streamer" -version = "1.14.20" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54279b5018a6e9a98e4b4e5dad87953e64359a6f9ce3715ffcdee0691885b88" +checksum = "705ef2b2649c4162061a74aaf12f02b244828ed847ad981581e3e51155279ca5" dependencies = [ + "async-channel", + "bytes", "crossbeam-channel", "futures-util", "histogram", - "indexmap", + "indexmap 1.9.3", "itertools", "libc", "log", - "nix 0.24.3", + "nix 0.26.2", "pem", "percentage", "pkcs8", "quinn", + "quinn-proto", + "quinn-udp", "rand 0.7.3", "rcgen", - "rustls", + "rustls 0.20.8", "solana-metrics", "solana-perf", "solana-sdk", @@ -4118,16 +4566,56 @@ dependencies = [ "x509-parser", ] +[[package]] +name = "solana-thin-client" +version = "1.16.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc8a9f9c101395d314c4e5e1b19801dd54f4cd501e40b8c2d7d8b896cd2e0980" +dependencies = [ + "bincode", + "log", + "rayon", + "solana-connection-cache", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-sdk", +] + +[[package]] +name = "solana-tpu-client" +version = "1.16.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a8a4d90f74e666cd2a5f7ac9ed230ca186d8f7351a927f061801b3ba4e8f2f" +dependencies = [ + "async-trait", + "bincode", + "futures-util", + "indexmap 1.9.3", + "indicatif", + "log", + "rand 0.7.3", + "rayon", + "solana-connection-cache", + "solana-measure", + "solana-metrics", + "solana-pubsub-client", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-sdk", + "thiserror", + "tokio", +] + [[package]] name = "solana-transaction-status" -version = "1.14.20" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6fbba26070920a1d25be8b3a2835df337ddcb5df1e65e4bbed48a019604377" +checksum = "c9266f75afa4163c9a5f29f1066f907e87482858749942380d6538af567b44c7" dependencies = [ "Inflector", - "base64 0.13.1", + "base64 0.21.4", "bincode", - "borsh", + "borsh 0.9.3", "bs58", "lazy_static", "log", @@ -4136,10 +4624,7 @@ dependencies = [ "serde_json", "solana-account-decoder", "solana-address-lookup-table-program", - "solana-measure", - "solana-metrics", "solana-sdk", - "solana-vote-program", "spl-associated-token-account", "spl-memo", "spl-token", @@ -4147,11 +4632,26 @@ dependencies = [ "thiserror", ] +[[package]] +name = "solana-udp-client" +version = "1.16.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0f475a0a0faa55f7783084258c1e88be39ed3ea5c4f945bf728b7ca8c7a3262" +dependencies = [ + "async-trait", + "solana-connection-cache", + "solana-net-utils", + "solana-sdk", + "solana-streamer", + "thiserror", + "tokio", +] + [[package]] name = "solana-version" -version = "1.14.20" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "122eccec6f9124b9234fde0ba6da263198f8e403f58e6535cd342f5fd3bd6c76" +checksum = "886a0c01be1e2b3a7ec3bed63f2112cd7f80c4b8182e95fa98b7ab7e37faf90a" dependencies = [ "log", "rustc_version", @@ -4165,9 +4665,9 @@ dependencies = [ [[package]] name = "solana-vote-program" -version = "1.14.20" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3edcb5a3ff3a8e78441badd1f21d2d6244e33497ee341b1bcafea768c6b501e6" +checksum = "01b1102b13ca7c760439545dba83588419d208b500a93eb61f6565be26bef490" dependencies = [ "bincode", "log", @@ -4179,6 +4679,7 @@ dependencies = [ "solana-frozen-abi", "solana-frozen-abi-macro", "solana-metrics", + "solana-program", "solana-program-runtime", "solana-sdk", "thiserror", @@ -4186,17 +4687,15 @@ dependencies = [ [[package]] name = "solana-zk-token-sdk" -version = "1.14.20" +version = "1.16.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d51d131cdefcb621a8034321ce487c4f788e813f81ce81e4f65eed8d4b4f2aa" +checksum = "1669c9d223d850cd96cad69d3ba1a4234bc3e2f83ac837fbdbc0ce774dac7b92" dependencies = [ "aes-gcm-siv", - "arrayref", - "base64 0.13.1", + "base64 0.21.4", "bincode", "bytemuck", "byteorder", - "cipher 0.4.4", "curve25519-dalek", "getrandom 0.1.16", "itertools", @@ -4217,9 +4716,9 @@ dependencies = [ [[package]] name = "solana_rbpf" -version = "0.2.31" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80a28c5dfe7e8af38daa39d6561c8e8b9ed7a2f900951ebe7362ad6348d36c73" +checksum = "b3082ec3a1d4ef7879eb5b84916d5acde057abd59733eec3647e0ab8885283ef" dependencies = [ "byteorder", "combine", @@ -4231,6 +4730,7 @@ dependencies = [ "rustc-demangle", "scroll", "thiserror", + "winapi", ] [[package]] @@ -4256,7 +4756,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978dba3bcbe88d0c2c58366c254d9ea41c5f73357e72fc0bdee4d6b5fc99c8f4" dependencies = [ "assert_matches", - "borsh", + "borsh 0.9.3", "num-derive", "num-traits", "solana-program", @@ -4284,7 +4784,7 @@ dependencies = [ "bytemuck", "num-derive", "num-traits", - "num_enum", + "num_enum 0.5.11", "solana-program", "thiserror", ] @@ -4299,7 +4799,7 @@ dependencies = [ "bytemuck", "num-derive", "num-traits", - "num_enum", + "num_enum 0.5.11", "solana-program", "solana-zk-token-sdk", "spl-memo", @@ -4573,11 +5073,21 @@ version = "0.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" dependencies = [ - "rustls", + "rustls 0.20.8", "tokio", "webpki", ] +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.7", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.12" @@ -4597,12 +5107,12 @@ checksum = "f714dd15bead90401d77e04243611caec13726c2408afd5b31901dfcdcb3b181" dependencies = [ "futures-util", "log", - "rustls", + "rustls 0.20.8", "tokio", - "tokio-rustls", + "tokio-rustls 0.23.4", "tungstenite", "webpki", - "webpki-roots", + "webpki-roots 0.22.6", ] [[package]] @@ -4640,7 +5150,7 @@ version = "0.19.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" dependencies = [ - "indexmap", + "indexmap 1.9.3", "toml_datetime", "winnow", ] @@ -4797,13 +5307,13 @@ dependencies = [ "httparse", "log", "rand 0.8.5", - "rustls", + "rustls 0.20.8", "sha-1", "thiserror", "url", "utf-8", "webpki", - "webpki-roots", + "webpki-roots 0.22.6", ] [[package]] @@ -4885,6 +5395,12 @@ dependencies = [ "void", ] +[[package]] +name = "unsafe-libyaml" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa" + [[package]] name = "untrusted" version = "0.7.1" @@ -4978,9 +5494,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -4988,16 +5504,16 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2 1.0.66", "quote 1.0.32", - "syn 1.0.109", + "syn 2.0.28", "wasm-bindgen-shared", ] @@ -5015,9 +5531,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote 1.0.32", "wasm-bindgen-macro-support", @@ -5025,22 +5541,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", - "syn 1.0.109", + "syn 2.0.28", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "web-sys" @@ -5071,6 +5587,12 @@ dependencies = [ "webpki", ] +[[package]] +name = "webpki-roots" +version = "0.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc" + [[package]] name = "winapi" version = "0.3.9" @@ -5269,11 +5791,12 @@ dependencies = [ [[package]] name = "winreg" -version = "0.10.1" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "winapi", + "cfg-if", + "windows-sys 0.48.0", ] [[package]] @@ -5294,15 +5817,6 @@ dependencies = [ "time 0.3.20", ] -[[package]] -name = "yaml-rust" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" -dependencies = [ - "linked-hash-map", -] - [[package]] name = "yasna" version = "0.5.2" diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 18dca2e18..416d04541 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -8,8 +8,8 @@ edition = "2021" [dependencies] clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } -solana-sdk = "=1.14.20" -solana-client = "=1.14.20" +solana-sdk = "=1.16.13" +solana-client = "=1.16.13" serde = "1.0.186" serde_json = "1.0.85" ethnum = { version = "1.4", default-features = false, features = ["serde"] } diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index 695e10fb6..c18f7574a 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -8,10 +8,10 @@ edition = "2021" [dependencies] clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } -solana-sdk = "=1.14.20" -solana-client = "=1.14.20" -solana-clap-utils = "=1.14.20" -solana-cli-config = "=1.14.20" +solana-sdk = "=1.16.13" +solana-client = "=1.16.13" +solana-clap-utils = "=1.16.13" +solana-cli-config = "=1.16.13" hex = "0.4.2" serde = "1.0.186" serde_json = "1.0.85" diff --git a/evm_loader/cli/src/config.rs b/evm_loader/cli/src/config.rs index 4e81ee87e..6d3382ce9 100644 --- a/evm_loader/cli/src/config.rs +++ b/evm_loader/cli/src/config.rs @@ -28,11 +28,7 @@ pub fn create(options: &ArgMatches) -> Result { .unwrap_or(&solana_cli_config.json_rpc_url), ); - let evm_loader = if let Some(value) = pubkey_of(options, "evm_loader") { - value - } else { - return Err(NeonError::EvmLoaderNotSpecified); - }; + let evm_loader = pubkey_of(options, "evm_loader").ok_or(NeonError::EvmLoaderNotSpecified)?; let keypair_path: String = options .value_of("keypair") diff --git a/evm_loader/docker-compose-ci.yml b/evm_loader/docker-compose-ci.yml index a8f0e39c5..c86929df7 100644 --- a/evm_loader/docker-compose-ci.yml +++ b/evm_loader/docker-compose-ci.yml @@ -8,9 +8,13 @@ services: - SOLANA_URL=http://solana:8899 hostname: solana ports: - - 8899 + - "8899" expose: - "8899" + ulimits: + nofile: + soft: 1048576 + hard: 1048576 entrypoint: /opt/solana/bin/solana-run-neon.sh networks: @@ -34,7 +38,7 @@ services: FEEPAIR: /opt/operator-keypairs/id.json image: ${EVM_LOADER_IMAGE} ports: - - 8085 + - "8085" networks: - net diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 9c0cf5ab2..24ce2e2d1 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -10,12 +10,12 @@ thiserror = "1.0" anyhow = "1.0" bincode = "1.3.1" evm-loader = { path = "../program", default-features = false, features = ["log", "tracing"] } -solana-sdk = "=1.14.20" -solana-client = "=1.14.20" -solana-clap-utils = "=1.14.20" -solana-cli-config = "=1.14.20" -solana-cli = "=1.14.20" -solana-transaction-status = "=1.14.20" +solana-sdk = "=1.16.13" +solana-client = "=1.16.13" +solana-clap-utils = "=1.16.13" +solana-cli-config = "=1.16.13" +solana-cli = "=1.16.13" +solana-transaction-status = "=1.16.13" spl-token = { version = "~3.5", default-features = false, features = ["no-entrypoint"] } spl-associated-token-account = { version = "~1.1", default-features = false, features = ["no-entrypoint"] } bs58 = "0.4.0" diff --git a/evm_loader/lib/src/commands/get_storage_at.rs b/evm_loader/lib/src/commands/get_storage_at.rs index 7a33b3117..44261324d 100644 --- a/evm_loader/lib/src/commands/get_storage_at.rs +++ b/evm_loader/lib/src/commands/get_storage_at.rs @@ -24,7 +24,7 @@ pub struct GetStorageAtReturn(pub [u8; 32]); impl Display for GetStorageAtReturn { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "0x{}", hex::encode(&self.0)) + write!(f, "0x{}", hex::encode(self.0)) } } diff --git a/evm_loader/lib/src/types/tracer_ch_db.rs b/evm_loader/lib/src/types/tracer_ch_db.rs index 2cf0a1b9d..5233b62b0 100644 --- a/evm_loader/lib/src/types/tracer_ch_db.rs +++ b/evm_loader/lib/src/types/tracer_ch_db.rs @@ -262,7 +262,7 @@ impl ClickHouseDb { self.client .query(query) .bind(pubkey_str.clone()) - .bind(&branch.as_slice()) + .bind(branch.as_slice()) .fetch_one::() .await, ) diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index bd82f4696..2ef830f66 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -39,10 +39,10 @@ tracing = ["serde_json"] [dependencies] linked_list_allocator = { version = "0.10", default-features = false } evm-loader-macro = { path = "../program-macro" } -solana-program = { version = "=1.14.20", default-features = false } +solana-program = { version = "=1.16.13", default-features = false } spl-token = { version = "~3.5", default-features = false, features = ["no-entrypoint"] } spl-associated-token-account = { version = "~1.1", default-features = false, features = ["no-entrypoint"] } -mpl-token-metadata = { version = "1.12", default-features = false, features = ["no-entrypoint"] } +mpl-token-metadata = { version = "1.13.2", default-features = false, features = ["no-entrypoint"] } thiserror = "1.0" arrayref = "0.3.6" hex = "0.4.2" diff --git a/evm_loader/program/src/evm/precompile/ecrecover.rs b/evm_loader/program/src/evm/precompile/ecrecover.rs index 6bebfd162..c45186e20 100644 --- a/evm_loader/program/src/evm/precompile/ecrecover.rs +++ b/evm_loader/program/src/evm/precompile/ecrecover.rs @@ -25,10 +25,7 @@ pub fn ecrecover(input: &[u8]) -> Vec { let recovery_id = v.as_u8() - 27; - let public_key = match secp256k1_recover(&msg[..], recovery_id, &sig[..]) { - Ok(key) => key, - Err(_) => return vec![], - }; + let Ok(public_key) = secp256k1_recover(&msg[..], recovery_id, &sig[..]) else { return vec![] }; let mut address = keccak::hash(&public_key.to_bytes()).to_bytes(); address[0..12].fill(0); diff --git a/evm_loader/program/src/external_programs/metaplex.rs b/evm_loader/program/src/external_programs/metaplex.rs index 8176d81a5..0f2c513ad 100644 --- a/evm_loader/program/src/external_programs/metaplex.rs +++ b/evm_loader/program/src/external_programs/metaplex.rs @@ -15,8 +15,8 @@ use mpl_token_metadata::instruction::{ CreateMasterEditionArgs, CreateMetadataAccountArgsV3, MetadataInstruction, }; use mpl_token_metadata::state::{ - CollectionDetails, Key, MasterEditionV2, Metadata, TokenMetadataAccount, TokenStandard, - MAX_MASTER_EDITION_LEN, MAX_METADATA_LEN, + Key, MasterEditionV2, Metadata, TokenMetadataAccount, TokenStandard, MAX_MASTER_EDITION_LEN, + MAX_METADATA_LEN, }; use solana_program::{ entrypoint::ProgramResult, program_error::ProgramError, program_pack::Pack, pubkey::Pubkey, @@ -90,16 +90,7 @@ fn create_metadata_accounts_v3( assert_collection_update_is_valid(false, &None, &args.data.collection)?; metadata.collection = args.data.collection.clone(); - - if let Some(details) = &args.collection_details { - match details { - CollectionDetails::V1 { size: _size } => { - metadata.collection_details = Some(CollectionDetails::V1 { size: 0 }); - } - } - } else { - metadata.collection_details = None; - } + metadata.collection_details = None; let token_standard = if mint.decimals == 0 { TokenStandard::FungibleAsset diff --git a/evm_loader/solana-run-neon.sh b/evm_loader/solana-run-neon.sh index e6365379a..50db9f4f9 100755 --- a/evm_loader/solana-run-neon.sh +++ b/evm_loader/solana-run-neon.sh @@ -46,6 +46,8 @@ fi NEON_VALIDATOR_ARGS=( --gossip-host $(hostname -i) --log-messages-bytes-limit 50000 + # See https://github.com/solana-labs/solana/issues/33205 for why this is required for run-neon-evm-tests + --allow-private-addr ) if [[ -n $GEYSER_PLUGIN_CONFIG ]]; then diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 10add70bb..f2415f831 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.64.0" +channel = "1.69.0" From acc47592b96472fab14b84495b749cfe4c067ba4 Mon Sep 17 00:00:00 2001 From: Denis Date: Thu, 21 Sep 2023 07:46:36 +0300 Subject: [PATCH 029/318] NDEV-2183: Remove the semicolon in query_is_startup (#199) --- evm_loader/lib/src/types/tracer_ch_db.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/evm_loader/lib/src/types/tracer_ch_db.rs b/evm_loader/lib/src/types/tracer_ch_db.rs index 5233b62b0..0cc9bfbb6 100644 --- a/evm_loader/lib/src/types/tracer_ch_db.rs +++ b/evm_loader/lib/src/types/tracer_ch_db.rs @@ -552,7 +552,7 @@ impl ClickHouseDb { SELECT MAX(slot) FROM events.update_account_distributed ) - LIMIT 1; + LIMIT 1 "#; let is_startup = Self::row_opt( From 426322a5be78053ca0e5f07dec46841c5adb95cd Mon Sep 17 00:00:00 2001 From: Kristina Nikolaeva <112946046+kristinaNikolaevaa@users.noreply.github.com> Date: Thu, 21 Sep 2023 10:53:16 +0200 Subject: [PATCH 030/318] Ndev 2093 add comment with dapps report (#198) * added pr_url as param * fix param name * Update pipeline.yml --- .github/workflows/deploy.py | 9 +++++++-- .github/workflows/github_api_client.py | 5 +++-- .github/workflows/pipeline.yml | 4 +++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index 8c80381a9..2ae5c5e61 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -158,7 +158,10 @@ def stop_containers(project_name): @click.option('--token') @click.option('--is_draft') @click.option('--labels') -def trigger_proxy_action(head_ref_branch, base_ref_branch, github_ref, github_sha, token, is_draft, labels): +@click.option('--pr_url') +@click.option('--pr_number') +def trigger_proxy_action(head_ref_branch, base_ref_branch, github_ref, github_sha, token, is_draft, labels, + pr_url, pr_number): is_develop_branch = github_ref in ['refs/heads/develop', 'refs/heads/master'] is_tag_creating = 'refs/tags/' in github_ref is_version_branch = re.match(VERSION_BRANCH_TEMPLATE, github_ref.replace("refs/heads/", "")) is not None @@ -184,9 +187,11 @@ def trigger_proxy_action(head_ref_branch, base_ref_branch, github_ref, github_sh proxy_branch = 'develop' click.echo(f"Proxy branch: {proxy_branch}") + initial_pr = f"{pr_url}/{pr_number}/comments" if pr_number else "" + runs_before = github.get_proxy_runs_list(proxy_branch) runs_count_before = github.get_proxy_runs_count(proxy_branch) - github.run_proxy_dispatches(proxy_branch, github_ref, github_sha, full_test_suite) + github.run_proxy_dispatches(proxy_branch, github_ref, github_sha, full_test_suite, initial_pr) wait_condition(lambda: github.get_proxy_runs_count(proxy_branch) > runs_count_before) runs_after = github.get_proxy_runs_list(proxy_branch) diff --git a/.github/workflows/github_api_client.py b/.github/workflows/github_api_client.py index af0039747..c66726b59 100644 --- a/.github/workflows/github_api_client.py +++ b/.github/workflows/github_api_client.py @@ -22,11 +22,12 @@ def get_proxy_runs_count(self, proxy_branch): f"{self.PROXY_ENDPOINT}/actions/workflows/pipeline.yml/runs?branch={proxy_branch}", headers=self.headers) return int(response.json()["total_count"]) - def run_proxy_dispatches(self, proxy_branch, github_ref, github_sha, full_test_suite): + def run_proxy_dispatches(self, proxy_branch, github_ref, github_sha, full_test_suite, initial_pr): data = {"ref": proxy_branch, "inputs": {"full_test_suite": full_test_suite, "neon_evm_commit": github_sha, - "neon_evm_branch": github_ref} + "neon_evm_branch": github_ref, + "initial_pr": initial_pr} } response = requests.post( f"{self.PROXY_ENDPOINT}/actions/workflows/pipeline.yml/dispatches", json=data, headers=self.headers) diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index ed3814394..3ee1e4ae4 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -64,7 +64,9 @@ jobs: --github_ref=${{ github.ref }} \ --token=${{secrets.GHTOKEN }} \ --is_draft=${{github.event.pull_request.draft}} \ - --labels='${{ toJson(github.event.pull_request.labels.*.name) }}' + --labels='${{ toJson(github.event.pull_request.labels.*.name) }}' \ + --pr_url="${{ github.api_url }}/repos/${{ github.repository }}/issues" \ + --pr_number="${{ github.event.pull_request.number }}" finalize-image: runs-on: neon-evm-1 needs: From 2dac917e5683b4066a79fed78accb4d32ee772e6 Mon Sep 17 00:00:00 2001 From: Kristina Nikolaeva <112946046+kristinaNikolaevaa@users.noreply.github.com> Date: Mon, 25 Sep 2023 09:47:04 +0200 Subject: [PATCH 031/318] added new label for tests (#202) --- .github/workflows/deploy.py | 11 +++++++---- .github/workflows/github_api_client.py | 4 ++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index 2ae5c5e61..995dfc550 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -166,11 +166,14 @@ def trigger_proxy_action(head_ref_branch, base_ref_branch, github_ref, github_sh is_tag_creating = 'refs/tags/' in github_ref is_version_branch = re.match(VERSION_BRANCH_TEMPLATE, github_ref.replace("refs/heads/", "")) is not None is_FTS_labeled_not_draft = 'FullTestSuit' in labels and is_draft != "true" + is_extended_FTS_labeled_not_draft = 'ExtendedFullTestSuit' in labels and is_draft != "true" - if is_develop_branch or is_tag_creating or is_version_branch or is_FTS_labeled_not_draft: - full_test_suite = "true" + if is_extended_FTS_labeled_not_draft: + test_set = "extendedFullTestSuite" + elif is_develop_branch or is_tag_creating or is_version_branch or is_FTS_labeled_not_draft: + test_set = "fullTestSuite" else: - full_test_suite = "false" + test_set = "basic" github = GithubClient(token) @@ -191,7 +194,7 @@ def trigger_proxy_action(head_ref_branch, base_ref_branch, github_ref, github_sh runs_before = github.get_proxy_runs_list(proxy_branch) runs_count_before = github.get_proxy_runs_count(proxy_branch) - github.run_proxy_dispatches(proxy_branch, github_ref, github_sha, full_test_suite, initial_pr) + github.run_proxy_dispatches(proxy_branch, github_ref, github_sha, test_set, initial_pr) wait_condition(lambda: github.get_proxy_runs_count(proxy_branch) > runs_count_before) runs_after = github.get_proxy_runs_list(proxy_branch) diff --git a/.github/workflows/github_api_client.py b/.github/workflows/github_api_client.py index c66726b59..dc5e519b7 100644 --- a/.github/workflows/github_api_client.py +++ b/.github/workflows/github_api_client.py @@ -22,9 +22,9 @@ def get_proxy_runs_count(self, proxy_branch): f"{self.PROXY_ENDPOINT}/actions/workflows/pipeline.yml/runs?branch={proxy_branch}", headers=self.headers) return int(response.json()["total_count"]) - def run_proxy_dispatches(self, proxy_branch, github_ref, github_sha, full_test_suite, initial_pr): + def run_proxy_dispatches(self, proxy_branch, github_ref, github_sha, test_set, initial_pr): data = {"ref": proxy_branch, - "inputs": {"full_test_suite": full_test_suite, + "inputs": {"test_set": test_set, "neon_evm_commit": github_sha, "neon_evm_branch": github_ref, "initial_pr": initial_pr} From 2505b19b13fe3e01baa1171c416cf48fa07dd181 Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Mon, 25 Sep 2023 08:35:35 +0000 Subject: [PATCH 032/318] NDEV-2249: Upgrade Solana to v1.16.14 (#203) --- .github/workflows/deploy.py | 4 +- evm_loader/Cargo.lock | 161 +++++++++++++++++----------------- evm_loader/api/Cargo.toml | 4 +- evm_loader/cli/Cargo.toml | 8 +- evm_loader/lib/Cargo.toml | 12 +-- evm_loader/program/Cargo.toml | 2 +- 6 files changed, 94 insertions(+), 97 deletions(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index 995dfc550..8afd3fd8f 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -30,8 +30,8 @@ DOCKER_USER = os.environ.get("DHUBU") DOCKER_PASSWORD = os.environ.get("DHUBP") IMAGE_NAME = 'neonlabsorg/evm_loader' -SOLANA_NODE_VERSION = 'v1.16.13' -SOLANA_BPF_VERSION = 'v1.16.13' +SOLANA_NODE_VERSION = 'v1.16.14' +SOLANA_BPF_VERSION = 'v1.16.14' VERSION_BRANCH_TEMPLATE = r"[vt]{1}\d{1,2}\.\d{1,2}\.x.*" docker_client = docker.APIClient() diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 405d595c7..04aba9077 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -532,7 +532,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" dependencies = [ "borsh-derive 0.10.3", - "hashbrown 0.12.3", + "hashbrown 0.13.2", ] [[package]] @@ -1735,9 +1735,6 @@ name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash 0.7.6", -] [[package]] name = "hashbrown" @@ -2999,9 +2996,9 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31999cfc7927c4e212e60fd50934ab40e8e8bfd2d493d6095d2d306bc0764d9" +checksum = "c956be1b23f4261676aed05a0046e204e8a6836e50203902683a718af0797989" dependencies = [ "bytes", "rand 0.8.5", @@ -3845,9 +3842,9 @@ dependencies = [ [[package]] name = "solana-account-decoder" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b83daa56035885dac1a47f5bd3d4e02379e3fc5915b2c3ce978a9af9eeecf07d" +checksum = "f0ada16ccd5ca6884ae28b716211c4f09d22225a9ebde14eccd4f605cc321e42" dependencies = [ "Inflector", "base64 0.21.4", @@ -3869,9 +3866,9 @@ dependencies = [ [[package]] name = "solana-address-lookup-table-program" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dd3f3e85d67e559985fbdc6b5b4d5dd9c8462b78e6079c3b465496c1f3c55d6" +checksum = "248b435722d18100b70bb8f09fd38b8a8c46031a0de86f6b31768f64cf4092c5" dependencies = [ "bincode", "bytemuck", @@ -3890,9 +3887,9 @@ dependencies = [ [[package]] name = "solana-bpf-loader-program" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da230f2ff22007e2ca60507346488a65ec274fbb2486bdd2d10948eef2c03d8" +checksum = "70b84a554f12f89c72f3c2dea973a5105740814aeebfb04998cc0afd9e2e6a2e" dependencies = [ "bincode", "byteorder", @@ -3909,9 +3906,9 @@ dependencies = [ [[package]] name = "solana-clap-utils" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3669a399b8ef60642471e68e1f93d3f3050248a4fa1436341596cfcb2a484e8b" +checksum = "2782dc1178498135d438ea51998e5a28be05f2ed5b9ff97e224d8ca1f6b16fe5" dependencies = [ "chrono", "clap 2.34.0", @@ -3927,9 +3924,9 @@ dependencies = [ [[package]] name = "solana-cli" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05046d0c42224578516c307893b486156507de627c5ac006079f936a90f31dce" +checksum = "cf1feeff64c3c26c609e4824ed8154d3da2086dc712009a3e762e96c6490f164" dependencies = [ "bincode", "bs58", @@ -3978,9 +3975,9 @@ dependencies = [ [[package]] name = "solana-cli-config" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79b593a0718a12d73fff3c5d9d405981c778a1806c66d327f5bdef0bec23402f" +checksum = "538e8c1de6e6a948930a11f7debdbb21ff5492d09b67fb0d37a03c5208c233c7" dependencies = [ "dirs-next", "lazy_static", @@ -3994,9 +3991,9 @@ dependencies = [ [[package]] name = "solana-cli-output" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0518efb44a2586f0aa7bf01fa6f90d3cd4e047a90ccfef799adb6e248bf79773" +checksum = "eb41ef997e186c81a42d8b359eff0d8f0f3c61a02ad4a66111f189664a4f9d0d" dependencies = [ "Inflector", "base64 0.21.4", @@ -4021,9 +4018,9 @@ dependencies = [ [[package]] name = "solana-client" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96d8a28ca30cd385f7c2c4a7f93edc32c18bc041baa0e8b25bd56cd28c51cbb" +checksum = "969294bec354ba003bb4dc2e95e94beee4202d3244d6011434c282337601cc1f" dependencies = [ "async-trait", "bincode", @@ -4054,9 +4051,9 @@ dependencies = [ [[package]] name = "solana-config-program" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a35e4cc9f2996a2ef95aac398443fc4a110ef585521e11a7685b3591648b7cf" +checksum = "e0622d8798d060c84883572483f214b0d5c1640450e4322483cfe2e72823a6d7" dependencies = [ "bincode", "chrono", @@ -4068,9 +4065,9 @@ dependencies = [ [[package]] name = "solana-connection-cache" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ecb12464ee1322a02635345522839958d78a2bacff18298991cacf298178f64" +checksum = "d1439d38886d31690d8e2573e656e6767d3ae790229050dfe71ade309d5664cb" dependencies = [ "async-trait", "bincode", @@ -4089,9 +4086,9 @@ dependencies = [ [[package]] name = "solana-faucet" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa14ab9f44667719270dd174538d0c0fa869ddfb69a1b2ac1aa2d510e98da009" +checksum = "7ec77384c3c93e9f755ef0352c0c90ec98017e9db9908a9e7878dad60ea3244b" dependencies = [ "bincode", "byteorder", @@ -4113,9 +4110,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35b9e2169fd13394af838b13f047067c35ce69372aea0fb46e026405b5e931f9" +checksum = "0e74d294241df12a73a229e38a819e810d54234da494c3d43f8a1a828631047d" dependencies = [ "ahash 0.8.3", "blake3", @@ -4146,9 +4143,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi-macro" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db08ab0af4007dc0954b900aa5febc0c0ae50d9f9f598be27263c3195d90240b" +checksum = "4dabde7fbd88a68eb083ae9d6d5f6855b7ba1bfc45d200c786b1b448ac49da5f" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", @@ -4158,9 +4155,9 @@ dependencies = [ [[package]] name = "solana-logger" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf8a48e734f78a44399516f7c130c114b455911e351f001abc0d96e7c5694efa" +checksum = "24dc0037a389d782c8de3c6f509b74efa1d60523ef9e5561cefe41f1a354fee0" dependencies = [ "env_logger", "lazy_static", @@ -4169,9 +4166,9 @@ dependencies = [ [[package]] name = "solana-measure" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3529d2ff63ceedd3707c51188aacb9e3c142118de3f55447c40584a78223ffd" +checksum = "19563c27f12801e0e65b42d0f216db1d910dfeaad88d8f1335dd6369697eda60" dependencies = [ "log", "solana-sdk", @@ -4179,9 +4176,9 @@ dependencies = [ [[package]] name = "solana-metrics" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4792f29de5378a13c51be3fa9fdd526a20550b5ffabd7d1a57a4e49468e17d90" +checksum = "7f74c557e821c7ff48c9b4ef4ab3a296918d7fb745e3f2e820ebdb38e8e3555b" dependencies = [ "crossbeam-channel", "gethostname", @@ -4193,9 +4190,9 @@ dependencies = [ [[package]] name = "solana-net-utils" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ed75beb465e211c79d31ae2049cb85974203e5ac21ae89396378d5a2fe71962" +checksum = "b7d5599760f8a287c59d96a5c52752028c1c72c815fe74e0d7990bb90684cbfc" dependencies = [ "bincode", "clap 3.2.23", @@ -4215,9 +4212,9 @@ dependencies = [ [[package]] name = "solana-perf" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9218d9c823b22a465f91c966e8254a5f57b6817e0121ec6d4bf9a5ddc8307f18" +checksum = "76b2adb00aa09d92cd3b4f614ddd4f81366524a0d8ae9dd63b64418f696171c6" dependencies = [ "ahash 0.8.3", "bincode", @@ -4242,9 +4239,9 @@ dependencies = [ [[package]] name = "solana-program" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f17a1fbcf1e94e282db16153d323b446d6386ac99f597f78e76332265829336" +checksum = "3a2faeb9c89b354b547a229e3b39fa8fd6d11c78362ba8580f0c4721739725b6" dependencies = [ "ark-bn254", "ark-ec", @@ -4297,9 +4294,9 @@ dependencies = [ [[package]] name = "solana-program-runtime" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ff9f0c8043b2e7921e25a3fee88fa253b8cb5dbab1e521a4d83e78e8874c551" +checksum = "9f65907a405764cda63be89335ffd2138ade18f065e5cae09d20adab7fb09502" dependencies = [ "base64 0.21.4", "bincode", @@ -4325,9 +4322,9 @@ dependencies = [ [[package]] name = "solana-pubsub-client" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0659db803f68fb440c87f43a603e2da7adb3dd11d68e119c3209ed3ca02073" +checksum = "367e70572ebc81de7d8ca742342f7cf19b6b47d182dd9aa8932c7cfa71bb6dc4" dependencies = [ "crossbeam-channel", "futures-util", @@ -4350,9 +4347,9 @@ dependencies = [ [[package]] name = "solana-quic-client" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd4e0689f7b3b2e98e73089bf3aa6b3290cb8a2cbff97fca2ee579cc3ca2717e" +checksum = "87daa01ce0ecd6667425c7f19f10388cbce63a62f8f69767ea37b69293e814cf" dependencies = [ "async-mutex", "async-trait", @@ -4378,9 +4375,9 @@ dependencies = [ [[package]] name = "solana-rayon-threadlimit" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3c3996bd418c45a540ee2c2d23e9796c244d3e5c9f135a86aa8501e1afea19" +checksum = "fb6593da84631b9b523dac91b04f4e2a366205f61112d677e8cbe2bfda57a176" dependencies = [ "lazy_static", "num_cpus", @@ -4388,9 +4385,9 @@ dependencies = [ [[package]] name = "solana-remote-wallet" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40927d4df440e354f618cbf9e5eb81e02cf4563ef8360782b5493f395b63f61a" +checksum = "a431bdda7679de1381722f6eef63dfc301f07cbd51a930a28e61ee42167448a5" dependencies = [ "console", "dialoguer", @@ -4408,9 +4405,9 @@ dependencies = [ [[package]] name = "solana-rpc-client" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "871cf6d60098c556755a3a7dbd1742201718220a13b988d012f0658eddaad674" +checksum = "2771ac12cdbde1aa6b55a129947f1428bb44d14314059c1e69674e1d58aaf9e1" dependencies = [ "async-trait", "base64 0.21.4", @@ -4434,9 +4431,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-api" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3214d68e3b661ddfd960271f67eb8042298ac7d90d9bd86d330200c3a5518404" +checksum = "f401e2ae586fd60c1c8c0f406be521bfe4889c6c2854fbb76bd20e8bc2d57284" dependencies = [ "base64 0.21.4", "bs58", @@ -4456,9 +4453,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-nonce-utils" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf08c480fb3d0d861abe10a0517990edea8151529ccf537c0a833233f1381d8" +checksum = "46df2d20521eab49fadb9afe93808e9764767e193bd701c7d380a56d0dc7f8ad" dependencies = [ "clap 2.34.0", "solana-clap-utils", @@ -4469,9 +4466,9 @@ dependencies = [ [[package]] name = "solana-sdk" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74a01f25b9f4022fc222c21c589ef7943027fb0fa2b9f6ae943fc4a65c2c01a2" +checksum = "57f4046d0d487e3d79be809ff29c63c1484793956e6ccbc5d3307b0aafbf989d" dependencies = [ "assert_matches", "base64 0.21.4", @@ -4522,9 +4519,9 @@ dependencies = [ [[package]] name = "solana-sdk-macro" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75b33716470fa4a65a23ddc2d4abcb8d28532c6e3ae3f04f4fe79b5e1f8c247" +checksum = "760fdfd4b7edb02fd9173a6dcec899ffae06ac21b66b65f8c7c5f3d17b12fa64" dependencies = [ "bs58", "proc-macro2 1.0.66", @@ -4535,9 +4532,9 @@ dependencies = [ [[package]] name = "solana-streamer" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "705ef2b2649c4162061a74aaf12f02b244828ed847ad981581e3e51155279ca5" +checksum = "0125d00ca7e8e67d12f7f192a18d1dff2801a9c3e3239033af40b3e72ad92d76" dependencies = [ "async-channel", "bytes", @@ -4568,9 +4565,9 @@ dependencies = [ [[package]] name = "solana-thin-client" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc8a9f9c101395d314c4e5e1b19801dd54f4cd501e40b8c2d7d8b896cd2e0980" +checksum = "61b6137bb86d37323482474d841dd5baba41d5e3cb8827e4f0f5e37e9ff09153" dependencies = [ "bincode", "log", @@ -4583,9 +4580,9 @@ dependencies = [ [[package]] name = "solana-tpu-client" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a8a4d90f74e666cd2a5f7ac9ed230ca186d8f7351a927f061801b3ba4e8f2f" +checksum = "7fe350f0f2e6a098c118e9a5820280bb3c512f27560ad848f793825f2cd76fa5" dependencies = [ "async-trait", "bincode", @@ -4608,9 +4605,9 @@ dependencies = [ [[package]] name = "solana-transaction-status" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9266f75afa4163c9a5f29f1066f907e87482858749942380d6538af567b44c7" +checksum = "8bdf7379a72c051d7879f1c36cfdab5fed0653a2a613718bc5d343e44e603401" dependencies = [ "Inflector", "base64 0.21.4", @@ -4634,9 +4631,9 @@ dependencies = [ [[package]] name = "solana-udp-client" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0f475a0a0faa55f7783084258c1e88be39ed3ea5c4f945bf728b7ca8c7a3262" +checksum = "22c5d62db9c69e8eced8eb8fdb1f8317dbcb3ad37cb5cc0d495aec85b5a46f7f" dependencies = [ "async-trait", "solana-connection-cache", @@ -4649,9 +4646,9 @@ dependencies = [ [[package]] name = "solana-version" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "886a0c01be1e2b3a7ec3bed63f2112cd7f80c4b8182e95fa98b7ab7e37faf90a" +checksum = "7d62712e119d6c616d1dea0fa5c1464f7316abe446e0b1eb4796cc9c77324c69" dependencies = [ "log", "rustc_version", @@ -4665,9 +4662,9 @@ dependencies = [ [[package]] name = "solana-vote-program" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01b1102b13ca7c760439545dba83588419d208b500a93eb61f6565be26bef490" +checksum = "dfde11af84827c25b484baf1743b5d0db068af32cf2e4f533148a2d2a31c2263" dependencies = [ "bincode", "log", @@ -4687,9 +4684,9 @@ dependencies = [ [[package]] name = "solana-zk-token-sdk" -version = "1.16.13" +version = "1.16.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1669c9d223d850cd96cad69d3ba1a4234bc3e2f83ac837fbdbc0ce774dac7b92" +checksum = "3bdec366a15133a70a8dfc4f027b5d0f508bd7cb46af11971076c9ebaf9ede2d" dependencies = [ "aes-gcm-siv", "base64 0.21.4", @@ -4716,9 +4713,9 @@ dependencies = [ [[package]] name = "solana_rbpf" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3082ec3a1d4ef7879eb5b84916d5acde057abd59733eec3647e0ab8885283ef" +checksum = "17d4ba1e58947346e360fabde0697029d36ba83c42f669199b16a8931313cf29" dependencies = [ "byteorder", "combine", diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 416d04541..b5a0e1890 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -8,8 +8,8 @@ edition = "2021" [dependencies] clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } -solana-sdk = "=1.16.13" -solana-client = "=1.16.13" +solana-sdk = "=1.16.14" +solana-client = "=1.16.14" serde = "1.0.186" serde_json = "1.0.85" ethnum = { version = "1.4", default-features = false, features = ["serde"] } diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index c18f7574a..540949f05 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -8,10 +8,10 @@ edition = "2021" [dependencies] clap = "2.33.3" evm-loader = { path = "../program", default-features = false, features = ["log"] } -solana-sdk = "=1.16.13" -solana-client = "=1.16.13" -solana-clap-utils = "=1.16.13" -solana-cli-config = "=1.16.13" +solana-sdk = "=1.16.14" +solana-client = "=1.16.14" +solana-clap-utils = "=1.16.14" +solana-cli-config = "=1.16.14" hex = "0.4.2" serde = "1.0.186" serde_json = "1.0.85" diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 24ce2e2d1..68e6f7816 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -10,12 +10,12 @@ thiserror = "1.0" anyhow = "1.0" bincode = "1.3.1" evm-loader = { path = "../program", default-features = false, features = ["log", "tracing"] } -solana-sdk = "=1.16.13" -solana-client = "=1.16.13" -solana-clap-utils = "=1.16.13" -solana-cli-config = "=1.16.13" -solana-cli = "=1.16.13" -solana-transaction-status = "=1.16.13" +solana-sdk = "=1.16.14" +solana-client = "=1.16.14" +solana-clap-utils = "=1.16.14" +solana-cli-config = "=1.16.14" +solana-cli = "=1.16.14" +solana-transaction-status = "=1.16.14" spl-token = { version = "~3.5", default-features = false, features = ["no-entrypoint"] } spl-associated-token-account = { version = "~1.1", default-features = false, features = ["no-entrypoint"] } bs58 = "0.4.0" diff --git a/evm_loader/program/Cargo.toml b/evm_loader/program/Cargo.toml index 2ef830f66..6c8e1c10f 100644 --- a/evm_loader/program/Cargo.toml +++ b/evm_loader/program/Cargo.toml @@ -39,7 +39,7 @@ tracing = ["serde_json"] [dependencies] linked_list_allocator = { version = "0.10", default-features = false } evm-loader-macro = { path = "../program-macro" } -solana-program = { version = "=1.16.13", default-features = false } +solana-program = { version = "=1.16.14", default-features = false } spl-token = { version = "~3.5", default-features = false, features = ["no-entrypoint"] } spl-associated-token-account = { version = "~1.1", default-features = false, features = ["no-entrypoint"] } mpl-token-metadata = { version = "1.13.2", default-features = false, features = ["no-entrypoint"] } From bce7b41a13178ea6e65d9dcc2809feef61c08296 Mon Sep 17 00:00:00 2001 From: Kristina Nikolaeva <112946046+kristinaNikolaevaa@users.noreply.github.com> Date: Mon, 25 Sep 2023 14:18:04 +0200 Subject: [PATCH 033/318] fix-ci (#204) --- .github/workflows/deploy.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy.py b/.github/workflows/deploy.py index 8afd3fd8f..297cac4fd 100644 --- a/.github/workflows/deploy.py +++ b/.github/workflows/deploy.py @@ -165,8 +165,8 @@ def trigger_proxy_action(head_ref_branch, base_ref_branch, github_ref, github_sh is_develop_branch = github_ref in ['refs/heads/develop', 'refs/heads/master'] is_tag_creating = 'refs/tags/' in github_ref is_version_branch = re.match(VERSION_BRANCH_TEMPLATE, github_ref.replace("refs/heads/", "")) is not None - is_FTS_labeled_not_draft = 'FullTestSuit' in labels and is_draft != "true" - is_extended_FTS_labeled_not_draft = 'ExtendedFullTestSuit' in labels and is_draft != "true" + is_FTS_labeled_not_draft = 'fullTestSuit' in labels and is_draft != "true" + is_extended_FTS_labeled_not_draft = 'extendedFullTestSuit' in labels and is_draft != "true" if is_extended_FTS_labeled_not_draft: test_set = "extendedFullTestSuite" From 6021618ab47b9f0911f0f6492d9c70ff3359f6bf Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Tue, 26 Sep 2023 07:08:26 +0100 Subject: [PATCH 034/318] NDEV-2222: Add build-info to neon-cli and neon-api (#200) --- .dockerignore | 1 - Dockerfile | 12 +- evm_loader/Cargo.lock | 234 ++++++++++++++++++ evm_loader/api/Cargo.toml | 4 + evm_loader/api/build.rs | 3 + .../api/src/api_server/handlers/build_info.rs | 8 + evm_loader/api/src/api_server/handlers/mod.rs | 1 + evm_loader/api/src/api_server/routes.rs | 5 +- evm_loader/api/src/build_info.rs | 7 + evm_loader/api/src/main.rs | 7 +- evm_loader/cli/Cargo.toml | 4 + evm_loader/cli/build.rs | 3 + evm_loader/cli/src/build_info.rs | 7 + evm_loader/cli/src/main.rs | 6 + evm_loader/lib/Cargo.toml | 4 + evm_loader/lib/build.rs | 3 + evm_loader/lib/src/build_info.rs | 7 + evm_loader/lib/src/build_info_common.rs | 76 ++++++ .../lib/src/commands/init_environment.rs | 6 +- evm_loader/lib/src/lib.rs | 2 + 20 files changed, 388 insertions(+), 12 deletions(-) create mode 100644 evm_loader/api/build.rs create mode 100644 evm_loader/api/src/api_server/handlers/build_info.rs create mode 100644 evm_loader/api/src/build_info.rs create mode 100644 evm_loader/cli/build.rs create mode 100644 evm_loader/cli/src/build_info.rs create mode 100644 evm_loader/lib/build.rs create mode 100644 evm_loader/lib/src/build_info.rs create mode 100644 evm_loader/lib/src/build_info_common.rs diff --git a/.dockerignore b/.dockerignore index bbfe5a82c..bcd73a3cc 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,7 +2,6 @@ Dockerfile Dockerfile.* .*.swp -.git .github .gitignore .gitmodules diff --git a/Dockerfile b/Dockerfile index df963690d..5d11bd626 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,8 +11,8 @@ ENV PATH=/root/.local/share/solana/install/active_release/bin:/usr/local/cargo/b # Build evm_loader FROM builder AS evm-loader-builder -COPY ./evm_loader/ /opt/evm_loader/ -WORKDIR /opt/evm_loader +COPY . /opt/neon-evm/ +WORKDIR /opt/neon-evm/evm_loader ARG REVISION ENV NEON_REVISION=${REVISION} RUN cargo fmt --check && \ @@ -73,10 +73,10 @@ RUN /opt/solana/bin/solana program dump metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518 COPY evm_loader/solana-run-neon.sh \ /opt/solana/bin/ -COPY --from=evm-loader-builder /opt/evm_loader/target/deploy/evm_loader*.so /opt/ -COPY --from=evm-loader-builder /opt/evm_loader/target/deploy/evm_loader-dump.txt /opt/ -COPY --from=evm-loader-builder /opt/evm_loader/target/release/neon-cli /opt/ -COPY --from=evm-loader-builder /opt/evm_loader/target/release/neon-api /opt/ +COPY --from=evm-loader-builder /opt/neon-evm/evm_loader/target/deploy/evm_loader*.so /opt/ +COPY --from=evm-loader-builder /opt/neon-evm/evm_loader/target/deploy/evm_loader-dump.txt /opt/ +COPY --from=evm-loader-builder /opt/neon-evm/evm_loader/target/release/neon-cli /opt/ +COPY --from=evm-loader-builder /opt/neon-evm/evm_loader/target/release/neon-api /opt/ COPY --from=solana /usr/bin/spl-token /opt/spl-token COPY --from=contracts /opt/ /opt/solidity/ COPY --from=contracts /usr/bin/solc /usr/bin/solc diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 04aba9077..7600e18b0 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -641,6 +641,71 @@ dependencies = [ "memchr", ] +[[package]] +name = "build-info" +version = "0.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b301350c1c448e35b896f32b68c49c8ecd969a71978fbafc4ebd09ec3f4eee2" +dependencies = [ + "build-info-common", + "build-info-proc", + "once_cell", +] + +[[package]] +name = "build-info-build" +version = "0.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b314717755dd6a06fc11ad3f7909ba4c0ae2ab516f5cb0404fe924c71bfc7d0" +dependencies = [ + "anyhow", + "base64 0.21.4", + "bincode", + "build-info-common", + "cargo_metadata", + "chrono", + "git2", + "glob", + "once_cell", + "pretty_assertions", + "rustc_version", + "serde_json", + "xz2", +] + +[[package]] +name = "build-info-common" +version = "0.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e040d36472d40ec9424c36a7b54be589072e605596b6f20b0c56c5230b460cc" +dependencies = [ + "chrono", + "derive_more", + "semver", + "serde", +] + +[[package]] +name = "build-info-proc" +version = "0.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffd5f241ddd417436c48d35da9869480891449ddd1ae3fd483bbcfbae741a422" +dependencies = [ + "anyhow", + "base64 0.21.4", + "bincode", + "build-info-common", + "chrono", + "num-bigint 0.4.3", + "num-traits", + "proc-macro-error", + "proc-macro2 1.0.66", + "quote 1.0.32", + "serde_json", + "syn 2.0.28", + "xz2", +] + [[package]] name = "bumpalo" version = "3.12.0" @@ -689,6 +754,15 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +[[package]] +name = "camino" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +dependencies = [ + "serde", +] + [[package]] name = "caps" version = "0.5.5" @@ -699,6 +773,29 @@ dependencies = [ "thiserror", ] +[[package]] +name = "cargo-platform" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cfa25e60aea747ec7e1124f238816749faa93759c6ff5b31f1ccdda137f4479" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "cast" version = "0.2.7" @@ -928,6 +1025,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + [[package]] name = "core-foundation" version = "0.9.3" @@ -1202,6 +1305,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2 1.0.66", + "quote 1.0.32", + "rustc_version", + "syn 1.0.109", +] + [[package]] name = "dialoguer" version = "0.10.4" @@ -1214,6 +1330,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + [[package]] name = "digest" version = "0.9.0" @@ -1671,6 +1793,25 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "git2" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b989d6a7ca95a362cf2cfc5ad688b3a467be1f87e480b8dad07fee8c79b0044" +dependencies = [ + "bitflags 1.3.2", + "libc", + "libgit2-sys", + "log", + "url", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "goblin" version = "0.5.4" @@ -2119,6 +2260,18 @@ version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +[[package]] +name = "libgit2-sys" +version = "0.15.2+1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a80df2e11fb4a61f4ba2ab42dbe7f74468da143f1a75c74e11dee7c813f694fa" +dependencies = [ + "cc", + "libc", + "libz-sys", + "pkg-config", +] + [[package]] name = "libsecp256k1" version = "0.6.0" @@ -2167,6 +2320,18 @@ dependencies = [ "libsecp256k1-core", ] +[[package]] +name = "libz-sys" +version = "1.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d97137b25e321a73eef1418d1d5d2eda4d77e12813f8e6dead84bc52c5870a7b" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "link-cplusplus" version = "1.0.8" @@ -2227,6 +2392,17 @@ dependencies = [ "libc", ] +[[package]] +name = "lzma-sys" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "matchers" version = "0.1.0" @@ -2422,6 +2598,8 @@ name = "neon-api" version = "0.1.0" dependencies = [ "axum", + "build-info", + "build-info-build", "clap 2.34.0", "ethnum", "evm-loader", @@ -2446,6 +2624,8 @@ dependencies = [ name = "neon-cli" version = "1.5.0-dev" dependencies = [ + "build-info", + "build-info-build", "clap 2.34.0", "ethnum", "evm-loader", @@ -2471,6 +2651,8 @@ dependencies = [ "axum", "bincode", "bs58", + "build-info", + "build-info-build", "clickhouse", "ethnum", "evm-loader", @@ -2930,6 +3112,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6fa0831dd7cc608c38a5e323422a0077678fa5744aa2be4ad91c4ece8eec8d5" +[[package]] +name = "pretty_assertions" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" +dependencies = [ + "diff", + "yansi", +] + [[package]] name = "proc-macro-crate" version = "0.1.5" @@ -2949,6 +3141,30 @@ dependencies = [ "toml_edit", ] +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2 1.0.66", + "quote 1.0.32", + "version_check", +] + [[package]] name = "proc-macro2" version = "0.4.30" @@ -3576,6 +3792,9 @@ name = "semver" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +dependencies = [ + "serde", +] [[package]] name = "serde" @@ -5814,6 +6033,21 @@ dependencies = [ "time 0.3.20", ] +[[package]] +name = "xz2" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2" +dependencies = [ + "lzma-sys", +] + +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + [[package]] name = "yasna" version = "0.5.2" diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index b5a0e1890..9c601bfbd 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -25,3 +25,7 @@ http = "0.2.9" hyper = "0.14.27" tower-http = { version = "0.4.4", features = ["trace"] } hex = "0.4.2" +build-info = { version = "0.0.31", features = ["serde"] } + +[build-dependencies] +build-info-build = "0.0.31" diff --git a/evm_loader/api/build.rs b/evm_loader/api/build.rs new file mode 100644 index 000000000..d36778f60 --- /dev/null +++ b/evm_loader/api/build.rs @@ -0,0 +1,3 @@ +fn main() { + build_info_build::build_script(); +} diff --git a/evm_loader/api/src/api_server/handlers/build_info.rs b/evm_loader/api/src/api_server/handlers/build_info.rs new file mode 100644 index 000000000..a46c6ceed --- /dev/null +++ b/evm_loader/api/src/api_server/handlers/build_info.rs @@ -0,0 +1,8 @@ +use crate::build_info::get_build_info; +use axum::{http::StatusCode, Json}; +use neon_lib::build_info_common::SlimBuildInfo; + +#[tracing::instrument(ret)] +pub async fn build_info() -> (StatusCode, Json) { + (StatusCode::OK, Json(get_build_info())) +} diff --git a/evm_loader/api/src/api_server/handlers/mod.rs b/evm_loader/api/src/api_server/handlers/mod.rs index 3eb743233..252a5fb89 100644 --- a/evm_loader/api/src/api_server/handlers/mod.rs +++ b/evm_loader/api/src/api_server/handlers/mod.rs @@ -16,6 +16,7 @@ use std::net::AddrParseError; use std::str::FromStr; use tracing::error; +pub mod build_info; pub mod emulate; pub mod get_ether_account_data; pub mod get_storage_at; diff --git a/evm_loader/api/src/api_server/routes.rs b/evm_loader/api/src/api_server/routes.rs index 85a0d9a5b..1b9a31457 100644 --- a/evm_loader/api/src/api_server/routes.rs +++ b/evm_loader/api/src/api_server/routes.rs @@ -7,7 +7,7 @@ use tower::ServiceBuilder; // use evm_loader::types::Address; use crate::{ api_server::handlers::{ - emulate::emulate, get_ether_account_data::get_ether_account_data, + build_info::build_info, emulate::emulate, get_ether_account_data::get_ether_account_data, get_storage_at::get_storage_at, trace::trace, }, NeonApiState, @@ -19,6 +19,7 @@ pub fn register() -> Router { .route("/emulate", post(emulate)) // Obsolete .route("/get-storage-at", get(get_storage_at)) .route("/get-ether-account-data", get(get_ether_account_data)) - .route("/trace", post(trace)), + .route("/trace", post(trace)) + .route("/build-info", get(build_info)), ) } diff --git a/evm_loader/api/src/build_info.rs b/evm_loader/api/src/build_info.rs new file mode 100644 index 000000000..85f42da0d --- /dev/null +++ b/evm_loader/api/src/build_info.rs @@ -0,0 +1,7 @@ +use neon_lib::build_info_common::SlimBuildInfo; + +build_info::build_info!(fn build_info); + +pub fn get_build_info() -> SlimBuildInfo { + build_info().into() +} diff --git a/evm_loader/api/src/main.rs b/evm_loader/api/src/main.rs index 206c952de..d9091abc8 100644 --- a/evm_loader/api/src/main.rs +++ b/evm_loader/api/src/main.rs @@ -4,6 +4,8 @@ mod api_context; mod api_options; mod api_server; +#[allow(clippy::module_name_repetitions)] +mod build_info; use api_server::handlers::NeonApiError; use axum::Router; @@ -20,6 +22,7 @@ use tracing_appender::non_blocking::NonBlockingBuilder; use std::sync::Arc; use std::{env, net::SocketAddr, str::FromStr}; +use crate::build_info::get_build_info; pub use config::Config; pub use context::Context; use http::Request; @@ -27,7 +30,7 @@ use hyper::Body; use tokio::signal::{self}; use tower_http::trace::TraceLayer; use tower_request_id::{RequestId, RequestIdLayer}; -use tracing::info_span; +use tracing::{info, info_span}; type NeonApiResult = Result; type NeonApiState = Arc; @@ -46,6 +49,8 @@ async fn main() -> NeonApiResult<()> { .with_writer(non_blocking) .init(); + info!("{}", get_build_info()); + let api_config = config::load_api_config_from_enviroment(); let config = config::create_from_api_config(&api_config)?; diff --git a/evm_loader/cli/Cargo.toml b/evm_loader/cli/Cargo.toml index 540949f05..e223224bb 100644 --- a/evm_loader/cli/Cargo.toml +++ b/evm_loader/cli/Cargo.toml @@ -20,3 +20,7 @@ fern = "0.6" ethnum = { version = "1.4", default-features = false, features = ["serde"] } tokio = { version = "1", features = ["full"] } neon-lib = { path = "../lib" } +build-info = { version = "0.0.31", features = ["serde"] } + +[build-dependencies] +build-info-build = "0.0.31" diff --git a/evm_loader/cli/build.rs b/evm_loader/cli/build.rs new file mode 100644 index 000000000..d36778f60 --- /dev/null +++ b/evm_loader/cli/build.rs @@ -0,0 +1,3 @@ +fn main() { + build_info_build::build_script(); +} diff --git a/evm_loader/cli/src/build_info.rs b/evm_loader/cli/src/build_info.rs new file mode 100644 index 000000000..85f42da0d --- /dev/null +++ b/evm_loader/cli/src/build_info.rs @@ -0,0 +1,7 @@ +use neon_lib::build_info_common::SlimBuildInfo; + +build_info::build_info!(fn build_info); + +pub fn get_build_info() -> SlimBuildInfo { + build_info().into() +} diff --git a/evm_loader/cli/src/main.rs b/evm_loader/cli/src/main.rs index b4cbd76ed..2b7d4ee5c 100644 --- a/evm_loader/cli/src/main.rs +++ b/evm_loader/cli/src/main.rs @@ -1,6 +1,8 @@ #![deny(warnings)] #![deny(clippy::all, clippy::pedantic)] +#[allow(clippy::module_name_repetitions)] +mod build_info; mod config; mod logs; mod program_options; @@ -22,6 +24,7 @@ use std::io::Read; use ethnum::U256; use evm_loader::evm::tracing::TraceCallConfig; +use log::debug; use serde_json::json; use solana_clap_utils::input_parsers::{pubkey_of, value_of, values_of}; use solana_client::nonblocking::rpc_client::RpcClient; @@ -30,6 +33,7 @@ use std::str::FromStr; use std::sync::Arc; use tokio::time::Instant; +use crate::build_info::get_build_info; use crate::{ errors::NeonError, types::{TransactionParams, TxParams}, @@ -83,6 +87,8 @@ async fn main() { print_result(&Err(NeonError::Panic(message))); })); + debug!("{}", get_build_info()); + let result = run(&options).await; let execution_time = Instant::now().duration_since(time_start); diff --git a/evm_loader/lib/Cargo.toml b/evm_loader/lib/Cargo.toml index 68e6f7816..bc9cc62d2 100644 --- a/evm_loader/lib/Cargo.toml +++ b/evm_loader/lib/Cargo.toml @@ -33,3 +33,7 @@ clickhouse = "0.11.5" tracing = "0.1" async-trait = "0.1.68" axum = "0.6" +build-info = "0.0.31" + +[build-dependencies] +build-info-build = "0.0.31" diff --git a/evm_loader/lib/build.rs b/evm_loader/lib/build.rs new file mode 100644 index 000000000..d36778f60 --- /dev/null +++ b/evm_loader/lib/build.rs @@ -0,0 +1,3 @@ +fn main() { + build_info_build::build_script(); +} diff --git a/evm_loader/lib/src/build_info.rs b/evm_loader/lib/src/build_info.rs new file mode 100644 index 000000000..f7d76fa9a --- /dev/null +++ b/evm_loader/lib/src/build_info.rs @@ -0,0 +1,7 @@ +use crate::build_info_common::SlimBuildInfo; + +build_info::build_info!(fn build_info); + +pub fn get_build_info() -> SlimBuildInfo { + build_info().into() +} diff --git a/evm_loader/lib/src/build_info_common.rs b/evm_loader/lib/src/build_info_common.rs new file mode 100644 index 000000000..94cff87e0 --- /dev/null +++ b/evm_loader/lib/src/build_info_common.rs @@ -0,0 +1,76 @@ +use build_info::chrono::{DateTime, Utc}; +use build_info::semver::Version; +use build_info::VersionControl::Git; +use build_info::{BuildInfo, OptimizationLevel}; +use serde::Serialize; +use std::fmt::{Display, Formatter}; + +#[derive(Debug, Clone, Serialize)] +pub struct SlimBuildInfo { + timestamp: DateTime, + profile: String, + optimization_level: OptimizationLevel, + crate_info: CrateInfo, + compiler: CompilerInfo, + version_control: GitInfo, +} + +#[derive(Debug, Clone, Serialize)] +struct CrateInfo { + name: String, + version: Version, +} + +#[derive(Debug, Clone, Serialize)] +struct CompilerInfo { + version: Version, +} + +#[derive(Debug, Clone, Serialize)] +struct GitInfo { + commit_id: String, + dirty: bool, + branch: Option, + tags: Vec, +} + +impl From<&BuildInfo> for SlimBuildInfo { + fn from(build_info: &BuildInfo) -> Self { + let build_info = build_info.clone(); + + let crate_info = build_info.crate_info; + + let Git(git_info) = build_info + .version_control + .expect("Project should be built inside version control"); + + SlimBuildInfo { + timestamp: build_info.timestamp, + profile: build_info.profile, + optimization_level: build_info.optimization_level, + crate_info: CrateInfo { + name: crate_info.name, + version: crate_info.version, + }, + compiler: CompilerInfo { + version: build_info.compiler.version, + }, + version_control: GitInfo { + commit_id: git_info.commit_id, + dirty: git_info.dirty, + branch: git_info.branch, + tags: git_info.tags, + }, + } + } +} + +impl Display for SlimBuildInfo { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "BuildInfo={}", + serde_json::to_string(&self).expect("Serialization should not fail") + ) + } +} diff --git a/evm_loader/lib/src/commands/init_environment.rs b/evm_loader/lib/src/commands/init_environment.rs index ee7d87f46..1c45090b9 100644 --- a/evm_loader/lib/src/commands/init_environment.rs +++ b/evm_loader/lib/src/commands/init_environment.rs @@ -139,14 +139,16 @@ pub async fn execute( let program_parameters = Parameters::new(read_elf_parameters(config, &data)); let neon_revision = program_parameters.get::("NEON_REVISION")?; - if neon_revision != env!("NEON_REVISION") { + let build_neon_revision = + build_info::format!("{}", $.version_control.unwrap().git().unwrap().commit_id); + if neon_revision != build_neon_revision { if force { warn!("NeonEVM revision doesn't match CLI revision. This check has been disabled with `--force` flag"); } else { error!("NeonEVM revision doesn't match CLI revision. Use appropriate neon-cli version or add `--force` flag"); return Err(EnvironmentError::RevisionMismatch( neon_revision, - env!("NEON_REVISION").to_string(), + build_neon_revision.to_string(), ) .into()); } diff --git a/evm_loader/lib/src/lib.rs b/evm_loader/lib/src/lib.rs index 3d84ba382..7475b056c 100644 --- a/evm_loader/lib/src/lib.rs +++ b/evm_loader/lib/src/lib.rs @@ -1,4 +1,6 @@ pub mod account_storage; +pub mod build_info; +pub mod build_info_common; pub mod commands; pub mod config; pub mod context; From 36caa1bca03e2f516e44c6938df3503e15cc4944 Mon Sep 17 00:00:00 2001 From: Anton Lisanin Date: Tue, 26 Sep 2023 17:01:18 +0100 Subject: [PATCH 035/318] NDEV-1396 Implement missing precompiled contracts (#197) --- .../program/src/evm/precompile/big_mod_exp.rs | 54 +++++++++---------- .../program/src/evm/precompile/bn256.rs | 21 +++----- 2 files changed, 31 insertions(+), 44 deletions(-) diff --git a/evm_loader/program/src/evm/precompile/big_mod_exp.rs b/evm_loader/program/src/evm/precompile/big_mod_exp.rs index dc92fd262..3331f0917 100644 --- a/evm_loader/program/src/evm/precompile/big_mod_exp.rs +++ b/evm_loader/program/src/evm/precompile/big_mod_exp.rs @@ -1,38 +1,32 @@ -// use ethnum::U256; +use ethnum::U256; #[must_use] -pub fn big_mod_exp(_input: &[u8]) -> Vec { - // Should be implemented via Solana syscall - Vec::new() +pub fn big_mod_exp(input: &[u8]) -> Vec { + if input.len() < 96 { + return vec![]; + } - // if input.len() < 96 { - // return vec![]; - // } + let (base_len, rest) = input.split_at(32); + let (exp_len, rest) = rest.split_at(32); + let (mod_len, rest) = rest.split_at(32); - // let (base_len, rest) = input.split_at(32); - // let (exp_len, rest) = rest.split_at(32); - // let (mod_len, rest) = rest.split_at(32); + let Ok(base_len) = U256::from_be_bytes(base_len.try_into().unwrap()).try_into() else { + return vec![]; + }; + let Ok(exp_len) = U256::from_be_bytes(exp_len.try_into().unwrap()).try_into() else { + return vec![]; + }; + let Ok(mod_len) = U256::from_be_bytes(mod_len.try_into().unwrap()).try_into() else { + return vec![]; + }; - // let base_len = match U256::from_be_bytes(base_len.try_into().unwrap()).try_into() { - // Ok(value) => value, - // Err(_) => return vec![] - // }; - // let exp_len = match U256::from_be_bytes(exp_len.try_into().unwrap()).try_into() { - // Ok(value) => value, - // Err(_) => return vec![] - // }; - // let mod_len = match U256::from_be_bytes(mod_len.try_into().unwrap()).try_into() { - // Ok(value) => value, - // Err(_) => return vec![] - // }; + if base_len == 0 && mod_len == 0 { + return vec![0; 32]; + } - // if base_len == 0 && mod_len == 0 { - // return vec![0; 32]; - // } + let (base_val, rest) = rest.split_at(base_len); + let (exp_val, rest) = rest.split_at(exp_len); + let (mod_val, _) = rest.split_at(mod_len); - // let (base_val, rest) = rest.split_at(base_len); - // let (exp_val, rest) = rest.split_at(exp_len); - // let (mod_val, _) = rest.split_at(mod_len); - - // solana_program::big_mod_exp::big_mod_exp(base_val, exp_val, mod_val) + solana_program::big_mod_exp::big_mod_exp(base_val, exp_val, mod_val) } diff --git a/evm_loader/program/src/evm/precompile/bn256.rs b/evm_loader/program/src/evm/precompile/bn256.rs index 02d062907..dfc2f4daa 100644 --- a/evm_loader/program/src/evm/precompile/bn256.rs +++ b/evm_loader/program/src/evm/precompile/bn256.rs @@ -1,26 +1,19 @@ -// Should be implemented via Solana syscall -// use solana_program::alt_bn128::prelude::*; +use solana_program::alt_bn128::prelude::*; /// Call inner `bn256Add` #[must_use] -pub fn bn256_add(_input: &[u8]) -> Vec { - // Should be implemented via Solana syscall - Vec::new() - //alt_bn128_addition(input).unwrap_or_else(|_| vec![]) +pub fn bn256_add(input: &[u8]) -> Vec { + alt_bn128_addition(input).unwrap_or_else(|_| vec![]) } /// Call inner `bn256ScalarMul` #[must_use] -pub fn bn256_scalar_mul(_input: &[u8]) -> Vec { - // Should be implemented via Solana syscall - Vec::new() - //alt_bn128_multiplication(input).unwrap_or_else(|_| vec![]) +pub fn bn256_scalar_mul(input: &[u8]) -> Vec { + alt_bn128_multiplication(input).unwrap_or_else(|_| vec![]) } /// Call inner `bn256Pairing` #[must_use] -pub fn bn256_pairing(_input: &[u8]) -> Vec { - // Should be implemented via Solana syscall - Vec::new() - //alt_bn128_pairing(input).unwrap_or_else(|_| vec![]) +pub fn bn256_pairing(input: &[u8]) -> Vec { + alt_bn128_pairing(input).unwrap_or_else(|_| vec![]) } From b4031f01fc2239fe42d3da2d67fbe0bb3f7fcd6f Mon Sep 17 00:00:00 2001 From: Andrei Silviu Dragnea Date: Wed, 27 Sep 2023 10:03:38 +0300 Subject: [PATCH 036/318] NDEV-2043: Improve performance of neon-api crate (#158) The main purpose of this PR is to remove usages of [`block_in_place`](https://docs.rs/tokio/latest/tokio/task/fn.block_in_place.html) and to re-use the same code in both an async (`neon-api`) and non-async (`evm-loader`) context. - Replaced `#[cfg(feature = "tracing")]` with `#[cfg(target_os = "solana")]` and extended its usage to: - code from `evm-loader` crate used only as a library (`#[cfg(not(target_os = "solana")]`); - code from `evm-loader` crate used only as part of a Solana program (`#[cfg(target_os = "solana")]`). - Replaced [`axum`](https://github.com/tokio-rs/axum) with [`actix-web`](https://github.com/actix/actix-web), because most of the `evm-loader` crate is based on non-`Send` types and [`actix-web`](https://github.com/actix/actix-web) is a web framework which does not require `Future`s to be `Send`. Inspired from #107. - Used [`maybe_async`](https://github.com/fMeow/maybe-async-rs) crate to re-write common parts of `evm-loader` crate used both as an async library and as a non-async Solana program. This also removed all usages of [`block_in_place`](https://docs.rs/tokio/latest/tokio/task/fn.block_in_place.html). - Simplified all types related to multi-threading in the context of non-`Send` `Future`s: less `Arc`s, less `RwLock`s. --- evm_loader/Cargo.lock | 452 ++++++++++++------ evm_loader/api/Cargo.toml | 7 +- .../api/src/api_server/handlers/build_info.rs | 11 +- .../api/src/api_server/handlers/emulate.rs | 15 +- .../handlers/get_ether_account_data.rs | 20 +- .../src/api_server/handlers/get_storage_at.rs | 19 +- evm_loader/api/src/api_server/handlers/mod.rs | 37 +- .../api/src/api_server/handlers/trace.rs | 15 +- evm_loader/api/src/api_server/mod.rs | 1 - evm_loader/api/src/api_server/routes.rs | 25 - evm_loader/api/src/api_server/state.rs | 5 +- evm_loader/api/src/main.rs | 104 ++-- evm_loader/cli/src/config.rs | 5 +- evm_loader/cli/src/main.rs | 54 ++- evm_loader/lib/Cargo.toml | 6 +- evm_loader/lib/src/account_storage.rs | 169 +++---- .../lib/src/commands/collect_treasury.rs | 2 +- evm_loader/lib/src/commands/emulate.rs | 33 +- evm_loader/lib/src/commands/get_neon_elf.rs | 10 +- evm_loader/lib/src/commands/get_storage_at.rs | 3 +- .../lib/src/commands/init_environment.rs | 29 +- evm_loader/lib/src/commands/trace.rs | 12 +- .../lib/src/commands/transaction_executor.rs | 51 +- evm_loader/lib/src/config.rs | 7 +- evm_loader/lib/src/context.rs | 42 +- evm_loader/lib/src/errors.rs | 3 - evm_loader/lib/src/rpc/db_call_client.rs | 2 +- evm_loader/lib/src/rpc/mod.rs | 4 +- evm_loader/lib/src/rpc/validator_client.rs | 2 +- evm_loader/lib/src/types/mod.rs | 17 - evm_loader/lib/src/types/tracer_ch_db.rs | 8 +- evm_loader/program/Cargo.toml | 8 +- evm_loader/program/src/account_storage/mod.rs | 87 ++-- evm_loader/program/src/evm/database.rs | 22 +- evm_loader/program/src/evm/memory.rs | 16 +- evm_loader/program/src/evm/mod.rs | 102 ++-- evm_loader/program/src/evm/opcode.rs | 342 ++++++++----- evm_loader/program/src/evm/opcode_table.rs | 368 +++++++------- .../program/src/evm/precompile/ecrecover.rs | 1 + evm_loader/program/src/evm/stack.rs | 14 +- evm_loader/program/src/evm/tracing/mod.rs | 5 +- .../program/src/evm/tracing/tracers/mod.rs | 5 +- .../src/evm/tracing/tracers/struct_logger.rs | 6 +- evm_loader/program/src/executor/action.rs | 1 + evm_loader/program/src/executor/cache.rs | 19 +- .../executor/precompile_extension/metaplex.rs | 66 ++- .../src/executor/precompile_extension/mod.rs | 24 +- .../precompile_extension/neon_token.rs | 15 +- .../precompile_extension/query_account.rs | 66 ++- .../precompile_extension/spl_token.rs | 54 ++- evm_loader/program/src/executor/state.rs | 93 ++-- .../src/instruction/transaction_execute.rs | 8 +- .../src/instruction/transaction_step.rs | 8 +- evm_loader/program/src/lib.rs | 5 +- evm_loader/program/src/state_account.rs | 31 +- evm_loader/program/src/types/mod.rs | 1 + evm_loader/program/src/types/transaction.rs | 1 + 57 files changed, 1401 insertions(+), 1137 deletions(-) delete mode 100644 evm_loader/api/src/api_server/routes.rs diff --git a/evm_loader/Cargo.lock b/evm_loader/Cargo.lock index 7600e18b0..8ad657fb7 100644 --- a/evm_loader/Cargo.lock +++ b/evm_loader/Cargo.lock @@ -12,6 +12,196 @@ dependencies = [ "regex", ] +[[package]] +name = "actix-codec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8" +dependencies = [ + "bitflags 1.3.2", + "bytes", + "futures-core", + "futures-sink", + "memchr", + "pin-project-lite", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "actix-http" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92ef85799cba03f76e4f7c10f533e66d87c9a7e7055f3391f09000ad8351bc9" +dependencies = [ + "actix-codec", + "actix-rt", + "actix-service", + "actix-utils", + "ahash 0.8.3", + "base64 0.21.4", + "bitflags 2.4.0", + "brotli", + "bytes", + "bytestring", + "derive_more", + "encoding_rs", + "flate2", + "futures-core", + "h2", + "http", + "httparse", + "httpdate", + "itoa", + "language-tags", + "local-channel", + "mime", + "percent-encoding", + "pin-project-lite", + "rand 0.8.5", + "sha1", + "smallvec", + "tokio", + "tokio-util", + "tracing", + "zstd 0.12.4", +] + +[[package]] +name = "actix-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" +dependencies = [ + "quote 1.0.32", + "syn 2.0.28", +] + +[[package]] +name = "actix-request-identifier" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f620de7c806297b88cf39da5ef4293a59f7dc219a9838433e83238e53a9c7057" +dependencies = [ + "actix-web", + "futures", + "uuid", +] + +[[package]] +name = "actix-router" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66ff4d247d2b160861fa2866457e85706833527840e4133f8f49aa423a38799" +dependencies = [ + "bytestring", + "http", + "regex", + "serde", + "tracing", +] + +[[package]] +name = "actix-rt" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28f32d40287d3f402ae0028a9d54bef51af15c8769492826a69d28f81893151d" +dependencies = [ + "futures-core", + "tokio", +] + +[[package]] +name = "actix-server" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb13e7eef0423ea6eab0e59f6c72e7cb46d33691ad56a726b3cd07ddec2c2d4" +dependencies = [ + "actix-rt", + "actix-service", + "actix-utils", + "futures-core", + "futures-util", + "mio", + "socket2 0.5.4", + "tokio", + "tracing", +] + +[[package]] +name = "actix-service" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" +dependencies = [ + "futures-core", + "paste", + "pin-project-lite", +] + +[[package]] +name = "actix-utils" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8" +dependencies = [ + "local-waker", + "pin-project-lite", +] + +[[package]] +name = "actix-web" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4a5b5e29603ca8c94a77c65cf874718ceb60292c5a5c3e5f4ace041af462b9" +dependencies = [ + "actix-codec", + "actix-http", + "actix-macros", + "actix-router", + "actix-rt", + "actix-server", + "actix-service", + "actix-utils", + "actix-web-codegen", + "ahash 0.8.3", + "bytes", + "bytestring", + "cfg-if", + "cookie", + "derive_more", + "encoding_rs", + "futures-core", + "futures-util", + "itoa", + "language-tags", + "log", + "mime", + "once_cell", + "pin-project-lite", + "regex", + "serde", + "serde_json", + "serde_urlencoded", + "smallvec", + "socket2 0.5.4", + "time 0.3.20", + "url", +] + +[[package]] +name = "actix-web-codegen" +version = "4.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb1f50ebbb30eca122b188319a4398b3f7bb4a8cdf50ecfb73bfc6a3c3ce54f5" +dependencies = [ + "actix-router", + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 2.0.28", +] + [[package]] name = "adler" version = "1.0.2" @@ -347,9 +537,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.68" +version = "0.1.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ "proc-macro2 1.0.66", "quote 1.0.32", @@ -373,55 +563,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" -[[package]] -name = "axum" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8175979259124331c1d7bf6586ee7e0da434155e4b2d48ec2c8386281d8df39" -dependencies = [ - "async-trait", - "axum-core", - "bitflags 1.3.2", - "bytes", - "futures-util", - "http", - "http-body", - "hyper", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "serde_json", - "serde_path_to_error", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum-core" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http", - "http-body", - "mime", - "rustversion", - "tower-layer", - "tower-service", -] - [[package]] name = "base64" version = "0.12.3" @@ -754,6 +895,15 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +[[package]] +name = "bytestring" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "238e4886760d98c4f899360c834fa93e62cf7f721ac3c2da375cbdf4b8679aae" +dependencies = [ + "bytes", +] + [[package]] name = "camino" version = "1.1.6" @@ -1031,6 +1181,17 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +[[package]] +name = "cookie" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" +dependencies = [ + "percent-encoding", + "time 0.3.20", + "version_check", +] + [[package]] name = "core-foundation" version = "0.9.3" @@ -1553,6 +1714,7 @@ name = "evm-loader" version = "1.5.0-dev" dependencies = [ "arrayref", + "async-trait", "bincode", "borsh 0.9.3", "cfg-if", @@ -1562,6 +1724,7 @@ dependencies = [ "hex", "linked_list_allocator", "log", + "maybe-async", "mpl-token-metadata", "ripemd", "rlp", @@ -2001,12 +2164,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "http-range-header" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" - [[package]] name = "httparse" version = "1.8.0" @@ -2042,7 +2199,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.4.9", "tokio", "tower-service", "tracing", @@ -2248,6 +2405,12 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "language-tags" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" + [[package]] name = "lazy_static" version = "1.4.0" @@ -2353,6 +2516,23 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b085a4f2cde5781fc4b1717f2e86c62f5cda49de7ba99a7c2eae02b61c9064c" +[[package]] +name = "local-channel" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a493488de5f18c8ffcba89eebb8532ffc562dc400490eb65b84893fae0b178" +dependencies = [ + "futures-core", + "futures-sink", + "local-waker", +] + +[[package]] +name = "local-waker" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e34f76eb3611940e0e7d53a9aaa4e6a3151f69541a282fd0dad5571420c53ff1" + [[package]] name = "lock_api" version = "0.4.9" @@ -2413,10 +2593,15 @@ dependencies = [ ] [[package]] -name = "matchit" -version = "0.7.0" +name = "maybe-async" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" +checksum = "0f1b8c13cb1f814b634a96b2c725449fe7ed464a7b8781de8688be5ffbd3f305" +dependencies = [ + "proc-macro2 1.0.66", + "quote 1.0.32", + "syn 1.0.109", +] [[package]] name = "memchr" @@ -2597,15 +2782,14 @@ dependencies = [ name = "neon-api" version = "0.1.0" dependencies = [ - "axum", + "actix-request-identifier", + "actix-web", "build-info", "build-info-build", "clap 2.34.0", "ethnum", "evm-loader", "hex", - "http", - "hyper", "neon-lib", "serde", "serde_json", @@ -2613,8 +2797,6 @@ dependencies = [ "solana-sdk", "tokio", "tower", - "tower-http", - "tower-request-id", "tracing", "tracing-appender", "tracing-subscriber", @@ -2648,7 +2830,6 @@ version = "0.1.0" dependencies = [ "anyhow", "async-trait", - "axum", "bincode", "bs58", "build-info", @@ -2658,7 +2839,6 @@ dependencies = [ "evm-loader", "goblin 0.6.1", "hex", - "lazy_static", "log", "rand 0.8.5", "scroll", @@ -3027,26 +3207,6 @@ dependencies = [ "num", ] -[[package]] -name = "pin-project" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" -dependencies = [ - "proc-macro2 1.0.66", - "quote 1.0.32", - "syn 2.0.28", -] - [[package]] name = "pin-project-lite" version = "0.2.9" @@ -3237,7 +3397,7 @@ checksum = "641538578b21f5e5c8ea733b736895576d0fe329bb883b937db6f4d163dbaaf4" dependencies = [ "libc", "quinn-proto", - "socket2", + "socket2 0.4.9", "tracing", "windows-sys 0.42.0", ] @@ -3847,15 +4007,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_path_to_error" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7f05c1d5476066defcdfacce1f52fc3cae3af1d3089727100c02ae92e5abbe0" -dependencies = [ - "serde", -] - [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -3914,6 +4065,17 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + [[package]] name = "sha2" version = "0.9.9" @@ -4059,6 +4221,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "socket2" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "solana-account-decoder" version = "1.16.14" @@ -4080,7 +4252,7 @@ dependencies = [ "spl-token", "spl-token-2022", "thiserror", - "zstd", + "zstd 0.11.2+zstd.1.5.2", ] [[package]] @@ -4421,7 +4593,7 @@ dependencies = [ "rand 0.7.3", "serde", "serde_derive", - "socket2", + "socket2 0.4.9", "solana-logger", "solana-sdk", "solana-version", @@ -5080,12 +5252,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - [[package]] name = "synstructure" version = "0.12.6" @@ -5257,7 +5423,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.4.9", "tokio-macros", "windows-sys 0.45.0", ] @@ -5377,9 +5543,7 @@ version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" dependencies = [ - "futures-core", "futures-util", - "pin-project", "pin-project-lite", "tokio", "tower-layer", @@ -5387,43 +5551,12 @@ dependencies = [ "tracing", ] -[[package]] -name = "tower-http" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" -dependencies = [ - "bitflags 2.4.0", - "bytes", - "futures-core", - "futures-util", - "http", - "http-body", - "http-range-header", - "pin-project-lite", - "tower-layer", - "tower-service", - "tracing", -] - [[package]] name = "tower-layer" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" -[[package]] -name = "tower-request-id" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a4fbab3421649e92056980671a04d83aa76e3bd4e7b755a9d9ae24eb2015b25" -dependencies = [ - "http", - "tower-layer", - "tower-service", - "ulid", -] - [[package]] name = "tower-service" version = "0.3.2" @@ -5538,15 +5671,6 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" -[[package]] -name = "ulid" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f9d3475df4ff8a8f7804c0fc3394b44fdcfc4fb635717bf05fbb7c41c83a376" -dependencies = [ - "rand 0.8.5", -] - [[package]] name = "unicode-bidi" version = "0.3.13" @@ -5650,6 +5774,15 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "uuid" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +dependencies = [ + "getrandom 0.2.9", +] + [[package]] name = "valuable" version = "0.1.0" @@ -6083,7 +6216,16 @@ version = "0.11.2+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" dependencies = [ - "zstd-safe", + "zstd-safe 5.0.2+zstd.1.5.2", +] + +[[package]] +name = "zstd" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c" +dependencies = [ + "zstd-safe 6.0.6", ] [[package]] @@ -6096,6 +6238,16 @@ dependencies = [ "zstd-sys", ] +[[package]] +name = "zstd-safe" +version = "6.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581" +dependencies = [ + "libc", + "zstd-sys", +] + [[package]] name = "zstd-sys" version = "2.0.8+zstd.1.5.5" diff --git a/evm_loader/api/Cargo.toml b/evm_loader/api/Cargo.toml index 9c601bfbd..3f7ddc40c 100644 --- a/evm_loader/api/Cargo.toml +++ b/evm_loader/api/Cargo.toml @@ -17,13 +17,10 @@ tokio = { version = "1", features = ["full"] } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } tracing-appender = "0.2.2" -axum = "0.6" tower = { version = "0.4", features = ["make"] } neon-lib = { path = "../lib" } -tower-request-id = "0.2.1" -http = "0.2.9" -hyper = "0.14.27" -tower-http = { version = "0.4.4", features = ["trace"] } +actix-web = "4.4.0" +actix-request-identifier = "4.1.0" hex = "0.4.2" build-info = { version = "0.0.31", features = ["serde"] } diff --git a/evm_loader/api/src/api_server/handlers/build_info.rs b/evm_loader/api/src/api_server/handlers/build_info.rs index a46c6ceed..e57d05a4a 100644 --- a/evm_loader/api/src/api_server/handlers/build_info.rs +++ b/evm_loader/api/src/api_server/handlers/build_info.rs @@ -1,8 +1,11 @@ use crate::build_info::get_build_info; -use axum::{http::StatusCode, Json}; -use neon_lib::build_info_common::SlimBuildInfo; +use actix_web::get; +use actix_web::http::StatusCode; +use actix_web::web::Json; +use actix_web::Responder; #[tracing::instrument(ret)] -pub async fn build_info() -> (StatusCode, Json) { - (StatusCode::OK, Json(get_build_info())) +#[get("/build-info")] +pub async fn build_info_route() -> impl Responder { + (Json(get_build_info()), StatusCode::OK) } diff --git a/evm_loader/api/src/api_server/handlers/emulate.rs b/evm_loader/api/src/api_server/handlers/emulate.rs index 6403c940f..1a3da87a7 100644 --- a/evm_loader/api/src/api_server/handlers/emulate.rs +++ b/evm_loader/api/src/api_server/handlers/emulate.rs @@ -1,4 +1,5 @@ -use axum::{http::StatusCode, Json}; +use actix_request_identifier::RequestId; +use actix_web::{http::StatusCode, post, web::Json, Responder}; use std::convert::Into; use crate::api_server::handlers::process_error; @@ -9,11 +10,13 @@ use crate::{ use super::{parse_emulation_params, process_result}; -#[tracing::instrument(skip(state))] +#[tracing::instrument(skip(state, request_id), fields(id = request_id.as_str()))] +#[post("/emulate")] pub async fn emulate( - axum::extract::State(state): axum::extract::State, + state: NeonApiState, + request_id: RequestId, Json(emulate_request): Json, -) -> (StatusCode, Json) { +) -> impl Responder { let tx = emulate_request.tx_params.into(); let rpc_client = match api_context::build_rpc_client(&state, emulate_request.slot).await { @@ -21,14 +24,14 @@ pub async fn emulate( Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; - let context = Context::new(rpc_client, state.config.clone()); + let context = Context::new(&*rpc_client, &state.config); let (token, chain, steps, accounts, solana_accounts) = parse_emulation_params(&state.config, &context, &emulate_request.emulation_params).await; process_result( &EmulateCommand::execute( - context.rpc_client.as_ref(), + context.rpc_client, state.config.evm_loader, tx, token, diff --git a/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs b/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs index b16854bc7..e0e77e50d 100644 --- a/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs +++ b/evm_loader/api/src/api_server/handlers/get_ether_account_data.rs @@ -1,29 +1,29 @@ use crate::api_server::handlers::process_error; use crate::commands::get_ether_account_data as GetEtherAccountDataCommand; use crate::{api_context, context::Context, types::request_models::GetEtherRequest, NeonApiState}; -use axum::{ - extract::{Query, State}, - http::StatusCode, - Json, -}; +use actix_request_identifier::RequestId; +use actix_web::{get, http::StatusCode, web::Query, Responder}; use std::convert::Into; use super::process_result; -#[tracing::instrument(skip(state))] +#[tracing::instrument(skip(state, request_id), fields(id = request_id.as_str()))] +#[get("/get-ether-account-data")] pub async fn get_ether_account_data( + state: NeonApiState, + request_id: RequestId, Query(req_params): Query, - State(state): State, -) -> (StatusCode, Json) { +) -> impl Responder { let rpc_client = match api_context::build_rpc_client(&state, req_params.slot).await { Ok(rpc_client) => rpc_client, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; - let context = Context::new(rpc_client, state.config.clone()); + + let context = Context::new(&*rpc_client, &state.config); process_result( &GetEtherAccountDataCommand::execute( - context.rpc_client.as_ref(), + context.rpc_client, &state.config.evm_loader, &req_params.ether, ) diff --git a/evm_loader/api/src/api_server/handlers/get_storage_at.rs b/evm_loader/api/src/api_server/handlers/get_storage_at.rs index f32ebd5d0..c19d0046a 100644 --- a/evm_loader/api/src/api_server/handlers/get_storage_at.rs +++ b/evm_loader/api/src/api_server/handlers/get_storage_at.rs @@ -2,32 +2,31 @@ use crate::api_server::handlers::process_error; use crate::{ api_context, context::Context, types::request_models::GetStorageAtRequest, NeonApiState, }; -use axum::{ - extract::{Query, State}, - http::StatusCode, - Json, -}; +use actix_request_identifier::RequestId; +use actix_web::{get, http::StatusCode, web::Query, Responder}; use std::convert::Into; use crate::commands::get_storage_at as GetStorageAtCommand; use super::process_result; -#[tracing::instrument(skip(state))] +#[tracing::instrument(skip(state, request_id), fields(id = request_id.as_str()))] +#[get("/get-storage-at")] pub async fn get_storage_at( + state: NeonApiState, + request_id: RequestId, Query(req_params): Query, - State(state): State, -) -> (StatusCode, Json) { +) -> impl Responder { let rpc_client = match api_context::build_rpc_client(&state, req_params.slot).await { Ok(rpc_client) => rpc_client, Err(e) => return process_error(StatusCode::BAD_REQUEST, &e), }; - let context = Context::new(rpc_client, state.config.clone()); + let context = Context::new(&*rpc_client, &state.config); process_result( &GetStorageAtCommand::execute( - context.rpc_client.as_ref(), + context.rpc_client, &state.config.evm_loader, req_params.contract_id, &req_params.index, diff --git a/evm_loader/api/src/api_server/handlers/mod.rs b/evm_loader/api/src/api_server/handlers/mod.rs index 252a5fb89..65b631bde 100644 --- a/evm_loader/api/src/api_server/handlers/mod.rs +++ b/evm_loader/api/src/api_server/handlers/mod.rs @@ -1,7 +1,5 @@ -use axum::http::StatusCode; -use axum::response::{IntoResponse, Response}; -use axum::Json; -use ethnum::U256; +use actix_web::http::StatusCode; +use actix_web::web::Json; use evm_loader::types::Address; use serde::Serialize; use serde_json::{json, Value}; @@ -49,30 +47,9 @@ impl From for NeonApiError { } } -impl IntoResponse for NeonApiError { - fn into_response(self) -> Response { - let (status, error_message) = (StatusCode::INTERNAL_SERVER_ERROR, self.0.to_string()); - - let body = Json(json!({ - "result": "error", - "error":error_message, - })); - - (status, body).into_response() - } -} - -pub fn u256_of(index: &str) -> Option { - if index.is_empty() { - return Some(U256::ZERO); - } - - U256::from_str_prefixed(index).ok() -} - pub(crate) async fn parse_emulation_params( config: &Config, - context: &Context, + context: &Context<'_>, params: &EmulationParamsRequestModel, ) -> (Pubkey, u64, u64, Vec