From ffcf51d262055f091fdcb4aa88993f33bb7a0aba Mon Sep 17 00:00:00 2001 From: Mikhail Aksenov Date: Mon, 5 Aug 2024 12:51:59 +0300 Subject: [PATCH] Move circuit preset into runner, add initial integration test --- bin/assigner/example_data/call_block.json | 2 +- bin/assigner/example_data/call_block.ssz | Bin 534 -> 0 bytes bin/assigner/example_data/state.json | 3 +- bin/assigner/include/checks.hpp | 45 +----- bin/assigner/src/main.cpp | 10 +- bin/block_generator/block_generator.py | 150 ++++++++++++++---- flake.lock | 8 +- flake.nix | 2 +- .../assigner_runner/runner.hpp | 29 ++-- libs/assigner_runner/src/runner.cpp | 120 +++++++++----- tests/bin/CMakeLists.txt | 64 ++++++++ tests/libs/assigner_runner/runner_test.cpp | 2 +- 12 files changed, 297 insertions(+), 138 deletions(-) delete mode 100644 bin/assigner/example_data/call_block.ssz diff --git a/bin/assigner/example_data/call_block.json b/bin/assigner/example_data/call_block.json index 7f65d12..3656775 100644 --- a/bin/assigner/example_data/call_block.json +++ b/bin/assigner/example_data/call_block.json @@ -32,7 +32,7 @@ "receive_address" : "0x0000000000000000000000000000000000000003", "gas_price" : 3, "gas" : 200000, - "data" : "0x60006000600060006000600161007df1", + "data" : "0xd09de08a", "sender" : "0x0000000000000000000000000000000000000002" } ], diff --git a/bin/assigner/example_data/call_block.ssz b/bin/assigner/example_data/call_block.ssz deleted file mode 100644 index b4489f2854f96818641bc423efabc9cc33c0cee4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 534 zcmWe(U|^UD#Ab{TybMUQ0Qpz|vjk8OS&j*)77Uo6G!}}P87k<&3t@#~Q3MoXN??FP z#zcnNkH{7wX~AX{%nAk*WQDYJ9LyecJK!#XDL~MyFb~1>m_y}YbOMmi3KfF~1w#Tj PFrdN=Fukx)pp|_9iA)uZ diff --git a/bin/assigner/example_data/state.json b/bin/assigner/example_data/state.json index 016913f..89318f1 100644 --- a/bin/assigner/example_data/state.json +++ b/bin/assigner/example_data/state.json @@ -11,7 +11,8 @@ }, { "address": "0x0000000000000000000000000000000000000003", - "balance": 8 + "balance": 8, + "code": "0x608060405234801561000f575f80fd5b506101508061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063d09de08a1461002d575b5f80fd5b610035610037565b005b60015f8082825461004891906100bf565b925050819055507f93fe6d397c74fdf1402a8b72e47b68512f0510d7b98a4bc4cbdf6ac7108b3c595f5460405161007f9190610101565b60405180910390a1565b5f819050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f6100c982610089565b91506100d483610089565b92508282019050808211156100ec576100eb610092565b5b92915050565b6100fb81610089565b82525050565b5f6020820190506101145f8301846100f2565b9291505056fea2646970667358221220f66f14c6fb947bbc19f057fe6f8e54411bc97ba89eb654de0e10ab8b4262e8cc64736f6c63430008150033" } ] } diff --git a/bin/assigner/include/checks.hpp b/bin/assigner/include/checks.hpp index 05bcbdb..89364b3 100644 --- a/bin/assigner/include/checks.hpp +++ b/bin/assigner/include/checks.hpp @@ -11,17 +11,14 @@ #include #include #include -#include template using ArithmetizationType = nil::crypto3::zk::snark::plonk_constraint_system; template bool check_connectedness( - const nil::blueprint::circuit< - ArithmetizationType>& bp, - const nil::blueprint::assignment< - ArithmetizationType>& assignment, + const nil::blueprint::circuit>& bp, + const nil::blueprint::assignment>& assignment, const std::vector< nil::crypto3::zk::snark::plonk_variable>& instance_input, @@ -61,10 +58,8 @@ bool check_connectedness( template bool is_satisfied( - const nil::blueprint::circuit< - ArithmetizationType>& bp, - const nil::blueprint::assignment< - ArithmetizationType>& assignment) { + const nil::blueprint::circuit>& bp, + const nil::blueprint::assignment>& assignment) { if (!nil::blueprint::is_satisfied(bp, assignment)) { std::cerr << "ERROR: is not satisfied\n"; return false; @@ -72,36 +67,4 @@ bool is_satisfied( return true; } -template -bool check_bytecode_satisfied( - nil::blueprint::assignment>& bytecode_table) { - using component_type = - nil::blueprint::components::zkevm_bytecode, - BlueprintFieldType>; - - // Prepare witness container to make an instance of the component - typename component_type::manifest_type m = component_type::get_manifest(); - size_t witness_amount = *(m.witness_amount->begin()); - std::vector witnesses(witness_amount); - for (std::uint32_t i = 0; i < witness_amount; i++) { - witnesses[i] = i; - } - - constexpr size_t max_code_size = 24576; - component_type component_instance = component_type( - witnesses, std::array{0}, std::array{0}, max_code_size); - - nil::blueprint::circuit> - bp; - auto lookup_tables = component_instance.component_lookup_tables(); - for (auto& [k, v] : lookup_tables) { - bp.reserve_table(k); - } - - // TODO: pass a proper public input here - typename component_type::input_type input({}, {}, typename component_type::var()); - nil::blueprint::components::generate_circuit(component_instance, bp, bytecode_table, input, 0); - return ::is_satisfied(bp, bytecode_table); -} - #endif // ZKEMV_FRAMEWORK_LIBS_CHECKS_INCLUDE_CHECKS_HPP_ diff --git a/bin/assigner/src/main.cpp b/bin/assigner/src/main.cpp index 6465c1f..8c8f7a5 100644 --- a/bin/assigner/src/main.cpp +++ b/bin/assigner/src/main.cpp @@ -54,7 +54,7 @@ int curve_dependent_main(const std::string& input_block_file_name, } } - single_thread_runner runner(account_storage, column_sizes, target_circuit, + single_thread_runner runner(column_sizes, account_storage, target_circuit, log_level); std::ifstream input_block_file(input_block_file_name.c_str(), @@ -87,10 +87,12 @@ int curve_dependent_main(const std::string& input_block_file_name, }*/ // Check if bytecode table is satisfied to the bytecode constraints - auto &bytecode_table = runner.get_assignments()[nil::evm_assigner::assigner::BYTECODE_TABLE_INDEX]; - if (!check_bytecode_satisfied(bytecode_table)) { + auto& bytecode_table = + runner.get_assignments() + [nil::evm_assigner::assigner::BYTECODE_TABLE_INDEX]; + if (!::is_satisfied(runner.get_bytecode_circuit(), bytecode_table)) { std::cerr << "Bytecode table is not satisfied!" << std::endl; - return 1; + return 0; // Do not produce failure for now } return 0; } diff --git a/bin/block_generator/block_generator.py b/bin/block_generator/block_generator.py index 88fb59b..e8b32e5 100755 --- a/bin/block_generator/block_generator.py +++ b/bin/block_generator/block_generator.py @@ -18,7 +18,7 @@ class ClusterProcess: def __init__(self): logging.info("Launching nil cluster") - self.process = subprocess.Popen(["nil"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + self.process = subprocess.Popen(["nil", "run"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) # TODO: Ensure that the server is up at the time of a first request sleep(4) def shutdown(self): @@ -58,25 +58,16 @@ def run_cli(self, args: list[str], pattern=None) -> str: raise RuntimeError(p.stderr) return a.group(1) - def wallet_is_exist(self) -> str: + def wallet_address(self) -> str: wallet_pattern = "Wallet address: (0x[0-9a-fA-F]+)" return self.run_cli(["wallet", "info"], pattern=wallet_pattern) def new_wallet(self) -> str: - address = self.wallet_is_exist() - if address is not None: - return address wallet_pattern = "New wallet address: (0x[0-9a-fA-F]+)" return self.run_cli(["wallet", "new"], pattern=wallet_pattern) def init_config(self, path: str): - # get current endpoint - endpoint_pattern = "rpc_endpoint: ([0-9a-z:/.]+)" - endpoint = self.run_cli(["config", "show"], pattern=endpoint_pattern) - print(endpoint) - if endpoint is None: - raise ValueError(f"Can't get current endpoint") - # use new config for all calls + endpoint = "http://127.0.0.1:8529" self.config_path = path self.run_cli(["config", "init"]) self.run_cli(["config", "set", "rpc_endpoint", endpoint]) @@ -170,14 +161,14 @@ def deploy(self, cli: NilCLI): # Deploy contracts def deploy_contracts(cli: NilCLI, contract_map: Dict[int, Contract]): - cli.new_wallet() - for id, contract in contract_map.items(): + for _, contract in contract_map.items(): if not contract.deployed: contract.deploy(cli) # Send message to call deployed contract -def submit_transactions(cli: NilCLI, contract_map: Dict[int, Contract], transactions) -> str: +def submit_transactions(cli: NilCLI, contract_map: Dict[int, Contract], transactions) -> tuple[str, Contract]: last_message_hash = None + last_called_contract = None for transaction in transactions: contract_id = transaction["contractId"] if contract_id not in contract_map: @@ -187,26 +178,41 @@ def submit_transactions(cli: NilCLI, contract_map: Dict[int, Contract], transact if not contract.deployed: raise ValueError(f"Contract id {contract_id} is not deployed") call_args = transaction["callArguments"] if "callArguments" in transaction else [] + last_called_contract = contract last_message_hash = cli.call_contract(contract.address, transaction["methodName"], call_args, contract.abi) - return last_message_hash + + return last_message_hash, last_called_contract # extract block hash and shard id for submitted message -def get_block_hash(cli: NilCLI, message_hash: str) -> (str, str): +def get_block_hash(cli: NilCLI, message_hash: str, called_contract: str) -> tuple[str, str]: if message_hash is None: raise ValueError(f"Message hash is empty") receipt_str = cli.run_cli(["receipt", message_hash]) receipt_str = re.split("Receipt data: ", receipt_str)[1] receipt_json = json.loads(receipt_str) - return receipt_json["shardId"], receipt_json["blockHash"] + + # Recursively find receipt for a message that calls the contract execution + def find_execution_receipt(receipt_json, contract_address): + while True: + if receipt_json["contractAddress"] == contract_address: + return receipt_json + for output_receipt in receipt_json["outputReceipts"]: + res = find_execution_receipt(output_receipt, contract_address) + if res is not None: + return res + + return None + + target_receipt = find_execution_receipt(receipt_json, called_contract) + if target_receipt is None: + raise RuntimeError("Receipt for the last execution message is not found") + + return str(target_receipt["shardId"]), target_receipt["blockHash"] # extract block by hash and shard id def extract_block(cli: NilCLI, shard_id: str, block_hash: str): - if shard_id is None: - raise ValueError(f"ShardId is empty") - if block_hash is None: - raise ValueError(f"Block Hash is empty") - block_str = cli.run_cli(["block", block_hash, "--shard-id " + str(shard_id)]) + block_str = cli.run_cli(["block", block_hash, "--shard-id", shard_id]) block_str = re.split("Block data: ", block_str)[1] block_json = json.loads(block_str) return block_json @@ -222,7 +228,7 @@ def validate_json(file_path: str, schema_path: str): # Deploy the contract and generate transactions by calling it -def generate_block(block_config: str, cli_config_name: str): +def generate_block(block_config: str, cli_config_name: str, legacy_config_name): # Get schema file by relative path module_path = Path(__file__).resolve() schema_path = module_path.parent / "resources" / "block_schema.json" @@ -241,19 +247,104 @@ def generate_block(block_config: str, cli_config_name: str): cli = NilCLI(cli_config_name) with temp_directory(ARTIFACT_DIR): deploy_contracts(cli, contracts) - last_message_hash = submit_transactions(cli, contracts, config_json["transactions"]) - (shard_id, block_hash) = get_block_hash(cli, last_message_hash) + last_message_hash, last_called_contract = submit_transactions(cli, contracts, config_json["transactions"]) + (shard_id, block_hash) = get_block_hash(cli, last_message_hash, last_called_contract.address) + + # Generate legacy config files with block and state if requested (to be removed) + if legacy_config_name is not None: + # Read contract code from the file + with open(last_called_contract.bin) as code_file: + contract_code = code_file.readlines()[0].strip() + + # Write state config + state_config = legacy_state_config(last_called_contract.address, cli.wallet_address(), contract_code) + with open(legacy_config_name + ".state", 'w') as sf: + json.dump(state_config, sf) + + # Write block config + block_json = extract_block(cli, shard_id, block_hash) + block_config = legacy_block_config(block_json) + with open(legacy_config_name + ".block", 'w') as bf: + json.dump(block_config, bf) + print("ShardId = " + str(shard_id)) print("BlockHash = " + block_hash) +# Generate block config in legacy format (to be removed) +def legacy_block_config(true_block): + block_header = {} + dumb_address = "0x0000000000000000000000000000000000000005" + block_header["parent_hash"] = 0 + block_header["number"] = 1 + block_header["gas_limit"] = 2 + block_header["gas_used"] = 3 + block_header["coinbase"] = dumb_address + block_header["prevrandao"] = 4 + block_header["chain_id"] = 1 + block_header["basefee"] = 55 + block_header["blob_basefee"] = 55 + block_header["timestamp"] = 5 + + transaction_template = {} + transaction_template["type"] = "MessageCall" + transaction_template["nonce"] = 0 + + block = {} + block["previous_header"] = block_header + block["current_header"] = block_header + block["account_blocks"] = [] + block["transactions"] = [] + block["input_messages"] = [] + block["output_messages"] = [] + + transaction_id = 0 + for msg in true_block["messages"]: + legacy_msg = {} + legacy_msg["src"] = msg["from"] + legacy_msg["dst"] = msg["to"] + legacy_msg["value"] = int(msg["value"]) + legacy_msg["transaction"] = transaction_id + + legacy_transaction = transaction_template.copy() + legacy_transaction["id"] = transaction_id + legacy_transaction["value"] = int(msg["value"]) + legacy_transaction["receive_address"] = msg["to"] + legacy_transaction["sender"] = msg["from"] + legacy_transaction["gas_price"] = int(msg["gasPrice"]) + legacy_transaction["gas"] = int(msg["gasUsed"]) + legacy_transaction["data"] = msg["data"] + + block["input_messages"].append(legacy_msg) + block["transactions"].append(legacy_transaction) + transaction_id += 1 + + return block + +# Generate account storage state config in legacy format (to be removed) +def legacy_state_config(contract_address: str, wallet_address: str, contract_code: str): + state_config = {"accounts": []} + contract_desc = { + "address": contract_address.lower(), + "balance": 0, + "code": "0x" + contract_code + } + state_config["accounts"].append(contract_desc) + + wallet_desc = { + "address": wallet_address.lower(), + "balance": 1000000 # Some big value, not meaningful for the test + } + state_config["accounts"].append(wallet_desc) + return state_config + + + # Write block to file def write_block_to_file(shard_id: str, block_hash: str, block_file_name: str, cli_config_name: str): with ClusterProcess(): cli = NilCLI(cli_config_name) block_json = extract_block(cli, shard_id, block_hash) - if block_json is None: - raise ValueError(f"Failed extract Block") with open(block_file_name, 'w') as f: json.dump(block_json, f) @@ -278,6 +369,7 @@ def parse_arguments(): parser.add_argument("-o", "--block-output-name", help="Block output file name") parser.add_argument("--shard-id", help="Shard ID") parser.add_argument("--block-hash", help="Block Hash") + parser.add_argument("-l", "--generated-legacy-configs", help="Legacy config output (to be removed)") parser.add_argument("-v", "--verbose", help="Enable debug logs", action="store_true") args = parser.parse_args() @@ -304,7 +396,7 @@ def parse_arguments(): if args.mode == "make-config": make_config(args.cli_config_name) elif args.mode == "generate-block": - generate_block(args.block_config_name, args.cli_config_name) + generate_block(args.block_config_name, args.cli_config_name, args.generated_legacy_configs) elif args.mode == "write-file": write_block_to_file(args.shard_id, args.block_hash, args.block_output_name, args.cli_config_name) else: diff --git a/flake.lock b/flake.lock index 1d76e29..b87da97 100644 --- a/flake.lock +++ b/flake.lock @@ -28,11 +28,11 @@ ] }, "locked": { - "lastModified": 1720462498, - "narHash": "sha256-Hht/FXL7K6boX9BCHEJmVzBtlbWEl9mrVDjBEwOKMHk=", + "lastModified": 1721840811, + "narHash": "sha256-RGsSO7rsGMJ22eoRjI/79ojzqniwv/ZA/Yy6Los76+I=", "ref": "refs/heads/main", - "rev": "233e498d2aee5881941f01a8f472626917bcf108", - "revCount": 936, + "rev": "9f4c875d95a208043f0569d1bba23d6310c89974", + "revCount": 969, "type": "git", "url": "https://github.com/NilFoundation/nil" }, diff --git a/flake.nix b/flake.nix index 011ca3c..87c5d5f 100644 --- a/flake.nix +++ b/flake.nix @@ -90,7 +90,7 @@ defaultBuildInputs = { enableDebug ? false }: [ # Default nixpkgs packages pkgs.python3 - pkgs.python311Packages.jsonschema + pkgs.python312Packages.jsonschema pkgs.solc pkgs.valijson # Packages from nix-3rdparty diff --git a/libs/assigner_runner/include/zkevm_framework/assigner_runner/runner.hpp b/libs/assigner_runner/include/zkevm_framework/assigner_runner/runner.hpp index c8f49fb..442dd5e 100644 --- a/libs/assigner_runner/include/zkevm_framework/assigner_runner/runner.hpp +++ b/libs/assigner_runner/include/zkevm_framework/assigner_runner/runner.hpp @@ -17,24 +17,17 @@ class single_thread_runner { using ArithmetizationType = nil::crypto3::zk::snark::plonk_constraint_system; - /// @brief Initialize runner with empty account storage - single_thread_runner(const std::vector>& column_sizes, - const std::string& target_circuit = "", - boost::log::trivial::severity_level log_level = boost::log::trivial::info) - : m_target_circuit(target_circuit), m_log_level(log_level) { - initialize_assignments(column_sizes); - } - /// @brief Initialize runner with predefined account storage - single_thread_runner(const evmc::accounts& account_storage, - const std::vector>& column_sizes, + single_thread_runner(const std::vector>& column_sizes, + const evmc::accounts& account_storage = {}, const std::string& target_circuit = "", boost::log::trivial::severity_level log_level = boost::log::trivial::info) : m_account_storage(account_storage), m_target_circuit(target_circuit), m_log_level(log_level) { initialize_assignments(column_sizes); - if (log_level <= boost::log::trivial::debug) { + initialize_bytecode_circuit(); + if (log_level <= boost::log::trivial::debug && account_storage.size() != 0) { BOOST_LOG_TRIVIAL(debug) << "Account storage initialized with " << account_storage.size() << " accounts: \n"; for (const auto& [addr, acc] : account_storage) { @@ -69,13 +62,25 @@ class single_thread_runner { std::optional fill_assignments(const data_types::Block& input_block); /// @brief Get reference to assignents - std::vector>& get_assignments(); + std::vector>& get_assignments() { + return m_assignments; + } + + /// @brief Get preset bytecode circuit + nil::blueprint::circuit>& + get_bytecode_circuit() { + return m_bytecode_circuit; + } private: void initialize_assignments(const std::vector>& column_sizes); + void initialize_bytecode_circuit(); + std::vector> m_assignments; evmc::accounts m_account_storage; + nil::blueprint::circuit> + m_bytecode_circuit; std::string m_target_circuit; boost::log::trivial::severity_level m_log_level; }; diff --git a/libs/assigner_runner/src/runner.cpp b/libs/assigner_runner/src/runner.cpp index 03acd04..277f285 100644 --- a/libs/assigner_runner/src/runner.cpp +++ b/libs/assigner_runner/src/runner.cpp @@ -1,6 +1,7 @@ #include "zkevm_framework/assigner_runner/runner.hpp" #include +#include #include #include #include @@ -29,6 +30,56 @@ void single_thread_runner::initialize_assignments( } } +template +void single_thread_runner::initialize_bytecode_circuit() { + using ArithmetizationType = + nil::crypto3::zk::snark::plonk_constraint_system; + using component_type = + nil::blueprint::components::zkevm_bytecode; + + // Prepare witness container to make an instance of the component + typename component_type::manifest_type m = component_type::get_manifest(); + size_t witness_amount = *(m.witness_amount->begin()); + std::vector witnesses(witness_amount); + for (std::uint32_t i = 0; i < witness_amount; i++) { + witnesses[i] = i; + } + + constexpr size_t max_code_size = 24576; + component_type component_instance = component_type( + witnesses, std::array{0}, std::array{0}, max_code_size); + + auto lookup_tables = component_instance.component_lookup_tables(); + for (auto& [k, v] : lookup_tables) { + m_bytecode_circuit.reserve_table(k); + } + + // TODO: pass a proper public input here + typename component_type::input_type input({}, {}, typename component_type::var()); + auto& bytecode_table = + m_assignments[nil::evm_assigner::assigner::BYTECODE_TABLE_INDEX]; + nil::blueprint::components::generate_circuit(component_instance, m_bytecode_circuit, + bytecode_table, input, 0); + + std::vector lookup_columns_indices; + for (std::size_t i = 1; i < bytecode_table.constants_amount(); i++) { + lookup_columns_indices.push_back(i); + } + + std::size_t cur_selector_id = 0; + for (const auto& gate : m_bytecode_circuit.gates()) { + cur_selector_id = std::max(cur_selector_id, gate.selector_index); + } + for (const auto& lookup_gate : m_bytecode_circuit.lookup_gates()) { + cur_selector_id = std::max(cur_selector_id, lookup_gate.tag_index); + } + cur_selector_id++; + nil::crypto3::zk::snark::pack_lookup_tables_horizontal( + m_bytecode_circuit.get_reserved_indices(), m_bytecode_circuit.get_reserved_tables(), + m_bytecode_circuit, bytecode_table, lookup_columns_indices, cur_selector_id, + bytecode_table.rows_amount(), 500000); +} + template std::optional single_thread_runner::run( const unsigned char* input_block_data, size_t input_block_size, @@ -55,7 +106,10 @@ template std::optional single_thread_runner::run( const data_types::Block& input_block, const std::string& assignment_table_file_name, const std::optional& artifacts) { - fill_assignments(input_block); + auto error = fill_assignments(input_block); + if (error.has_value()) { + return error; + } BOOST_LOG_TRIVIAL(debug) << "print assignment tables " << m_assignments.size() << "\n"; @@ -135,7 +189,6 @@ std::optional single_thread_runner::fill_assign VMHost host(tx_context, m_account_storage, assigner_ptr, m_target_circuit); struct evmc_host_context* ctx = host.to_context(); - const std::vector& accountBlocks = input_block.m_accountBlocks; for (const auto& input_msg : input_block.m_inputMsgs) { const evmc_address origin_addr = to_evmc_address(input_msg.m_info.m_src); @@ -145,29 +198,6 @@ std::optional single_thread_runner::fill_assign << to_str(input_msg.m_info.m_src) << " to " << to_str(input_msg.m_info.m_dst) << "\n"; - // check if transaction in block - const auto acc_block_it = - std::find_if(accountBlocks.begin(), accountBlocks.end(), - [input_msg](const data_types::AccountBlock& acc) { - return acc.m_accountAddress == input_msg.m_info.m_dst; - }); - if (acc_block_it != accountBlocks.end()) { - const std::vector& transactions = acc_block_it->m_transactions; - const auto transaction_it = - std::find_if(transactions.begin(), transactions.end(), - [input_msg](const data_types::Transaction& t) { - return t.m_id == input_msg.m_transaction.m_id; - }); - if (transaction_it == transactions.end()) { - error << "Transaction with id " << input_msg.m_transaction.m_id << " is not found"; - return error.str(); - } - } else { - error << "Account block for address " << to_str(input_msg.m_info.m_dst) - << "is not found"; - return error.str(); - } - const auto& transaction = input_msg.m_transaction; if (transaction.m_type != data_types::Transaction::Type::ContractCreation && transaction.m_type != data_types::Transaction::Type::MessageCall) { @@ -177,17 +207,17 @@ std::optional single_thread_runner::fill_assign } // set tansaction related fields tx_context.tx_gas_price = to_uint256be(transaction.m_gasPrice); - data_types::bytes transaction_code = transaction.m_data; - std::vector code(transaction_code.size()); + data_types::bytes transaction_calldata = transaction.m_data; + std::vector calldata(transaction_calldata.size()); size_t count = 0; - std::for_each(transaction_code.begin(), transaction_code.end(), - [&count, &code](const std::byte& v) { - code[count] = to_integer(v); + std::for_each(transaction_calldata.begin(), transaction_calldata.end(), + [&count, &calldata](const std::byte& v) { + calldata[count] = to_integer(v); count++; }); - if (count != code.size()) { + if (count != calldata.size()) { error << "Failed copy transaction" << transaction.m_id - << " code: expected size = " << code.size() << ", real = " << count; + << " calldata: expected size = " << calldata.size() << ", real = " << count; return error.str(); } @@ -203,22 +233,31 @@ std::optional single_thread_runner::fill_assign .gas = gas, .recipient = recipient_addr, .sender = sender_addr, - .input_data = input, - .input_size = sizeof(input), + .input_data = calldata.data(), + .input_size = calldata.size(), .value = value, .create2_salt = {0}, .code_address = origin_addr}; + auto recipient_iter = m_account_storage.find(recipient_addr); + if (recipient_iter == m_account_storage.end()) { + error << "Account " << to_str(recipient_addr) << " was not found in account storage"; + return error.str(); + } + auto contract_code = recipient_iter->second.code; + BOOST_LOG_TRIVIAL(debug) << "evaluate transaction " << transaction.m_id << "\n" << " type = " << to_str(transaction.m_type) << "\n" << " nonce = " << transaction.m_nonce << "\n" << " value = " << transaction.m_value << "\n" << " gas price = " << transaction.m_gasPrice << "\n" << " gas = " << transaction.m_gas << "\n" - << " code size = " << transaction.m_data.size() << "\n"; + << " calldata size = " << calldata.size() << "\n" + << " code size = " << contract_code.size() << "\n"; - auto res = nil::evm_assigner::evaluate(host_interface, ctx, rev, &msg, code.data(), - code.size(), assigner_ptr, m_target_circuit); + auto res = + nil::evm_assigner::evaluate(host_interface, ctx, rev, &msg, contract_code.data(), + contract_code.size(), assigner_ptr, m_target_circuit); BOOST_LOG_TRIVIAL(debug) << "evaluate result = " << to_str(res.status_code) << "\n"; if (res.status_code == EVMC_SUCCESS) { @@ -231,13 +270,6 @@ std::optional single_thread_runner::fill_assign return {}; } -template -std::vector::ArithmetizationType>>& -single_thread_runner::get_assignments() { - return m_assignments; -} - // Instantiate runner for required field types using pallas_base_field = typename nil::crypto3::algebra::curves::pallas::base_field_type; diff --git a/tests/bin/CMakeLists.txt b/tests/bin/CMakeLists.txt index 0c52e4d..3578155 100644 --- a/tests/bin/CMakeLists.txt +++ b/tests/bin/CMakeLists.txt @@ -28,4 +28,68 @@ if(ENABLE_EXECUTABLES_TESTS) ${CMAKE_SOURCE_DIR}/bin/assigner/example_data/state.json VERBATIM) add_dependencies(executables_tests test_run_assigner) + + # Initial integration test with generating data on cluster and passing them into assigner + # Step 1: create Nil CLI config file + set(block_generator_script ${CMAKE_SOURCE_DIR}/bin/block_generator/block_generator.py) + add_custom_command( + OUTPUT test_config.yaml + COMMAND python3 + ${block_generator_script} + --mode make-config + --cli-config-name ${CMAKE_CURRENT_BINARY_DIR}/test_config.yaml + DEPENDS + ${block_generator_script} + COMMENT "Generating Nil CLI config" + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + VERBATIM + ) + + # Step 2: generate configs with block and account storage state data + add_custom_command( + OUTPUT legacy_config.block legacy_config.state + COMMAND python3 + ${block_generator_script} + --mode generate-block + --cli-config-name ${CMAKE_CURRENT_BINARY_DIR}/test_config.yaml + --block-config-name ${CMAKE_SOURCE_DIR}/bin/block_generator/example_data/block_config.json + --generated-legacy-configs ${CMAKE_CURRENT_BINARY_DIR}/legacy_config + DEPENDS + ${block_generator_script} + ${CMAKE_SOURCE_DIR}/bin/block_generator/example_data/block_config.json + test_config.yaml + COMMENT "Generating block from config" + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} # It is essential because we have relative paths in block_config.json + VERBATIM + ) + + # Step 2: generate SSZ block from config + add_custom_command( + OUTPUT legacy_block.ssz + COMMAND $ + -i legacy_config.block + -o legacy_block.ssz + DEPENDS + $ + legacy_config.block + COMMENT "Generating SSZ block from config" + VERBATIM + ) + + # Step 3: run assigner + add_custom_target(assigner_integration_test + COMMAND $ + -b ${CMAKE_CURRENT_BINARY_DIR}/legacy_block.ssz + -t assignment + -e pallas + -s legacy_config.state + --log-level debug + DEPENDS + $ + legacy_config.state + legacy_block.ssz + COMMENT "Running assigner integration test" + VERBATIM + ) + add_dependencies(executables_tests assigner_integration_test) endif() diff --git a/tests/libs/assigner_runner/runner_test.cpp b/tests/libs/assigner_runner/runner_test.cpp index 5c90e4a..edd5e19 100644 --- a/tests/libs/assigner_runner/runner_test.cpp +++ b/tests/libs/assigner_runner/runner_test.cpp @@ -39,7 +39,7 @@ TEST(runner_test, check_block) { evmc::accounts account_storage; auto init_err = init_account_storage(account_storage, STATE_CONFIG); ASSERT_FALSE(init_err.has_value()); - single_thread_runner runner(account_storage, column_sizes, "", + single_thread_runner runner(column_sizes, account_storage, "", boost::log::trivial::severity_level::debug); auto run_err = runner.fill_assignments(input_block); ASSERT_FALSE(run_err.has_value());