|
42 | 42 | #include <silkworm/db/buffer.hpp> |
43 | 43 | #include <silkworm/db/datastore/snapshots/index_builder.hpp> |
44 | 44 | #include <silkworm/db/datastore/snapshots/segment/segment_reader.hpp> |
| 45 | +#include <silkworm/db/kv/grpc/client/remote_client.hpp> |
45 | 46 | #include <silkworm/db/stages.hpp> |
46 | 47 | #include <silkworm/db/state/schema_config.hpp> |
| 48 | +#include <silkworm/execution/domain_state.hpp> |
| 49 | +#include <silkworm/execution/remote_state.hpp> |
| 50 | +#include <silkworm/execution/state_factory.hpp> |
47 | 51 | #include <silkworm/infra/common/bounded_buffer.hpp> |
48 | 52 | #include <silkworm/infra/common/directories.hpp> |
49 | 53 | #include <silkworm/infra/common/stopwatch.hpp> |
50 | 54 | #include <silkworm/infra/concurrency/context_pool_settings.hpp> |
51 | 55 | #include <silkworm/infra/concurrency/signal_handler.hpp> |
| 56 | +#include <silkworm/infra/concurrency/spawn.hpp> |
52 | 57 | #include <silkworm/infra/concurrency/thread_pool.hpp> |
| 58 | +#include <silkworm/infra/grpc/client/client_context_pool.hpp> |
53 | 59 | #include <silkworm/node/execution/block/block_executor.hpp> |
54 | 60 | #include <silkworm/node/stagedsync/execution_engine.hpp> |
55 | 61 | #include <silkworm/rpc/daemon.hpp> |
| 62 | +#include <silkworm/rpc/ethbackend/remote_backend.hpp> |
| 63 | +#include <silkworm/rpc/ethdb/kv/backend_providers.hpp> |
56 | 64 |
|
57 | 65 | #include "common.hpp" |
58 | 66 | #include "instance.hpp" |
59 | 67 |
|
60 | 68 | using namespace std::chrono_literals; |
61 | 69 | using namespace silkworm; |
| 70 | +// using namespace silkworm::db; |
| 71 | +// using namespace silkworm::rpc; |
62 | 72 |
|
63 | 73 | static MemoryMappedRegion make_region(const SilkwormMemoryMappedFile& mmf) { |
64 | 74 | return {mmf.memory_address, mmf.memory_length}; |
@@ -741,6 +751,84 @@ int silkworm_execute_blocks_perpetual(SilkwormHandle handle, MDBX_env* mdbx_env, |
741 | 751 | } |
742 | 752 | } |
743 | 753 |
|
| 754 | +SILKWORM_EXPORT int silkworm_execute_txn(SilkwormHandle handle, MDBX_txn* mdbx_tx, uint64_t block_num, struct SilkwormBytes32 block_hash, uint64_t txn_index, uint64_t txn_num, uint64_t* gas_used, uint64_t* blob_gas_used) SILKWORM_NOEXCEPT { |
| 755 | + log::Info{"silkworm_execute_txn", {"block_num", std::to_string(block_num), "txn_index", std::to_string(txn_index)}}; |
| 756 | + if (!handle) { |
| 757 | + return SILKWORM_INVALID_HANDLE; |
| 758 | + } |
| 759 | + |
| 760 | + if (!mdbx_tx) { |
| 761 | + return SILKWORM_INVALID_MDBX_TXN; |
| 762 | + } |
| 763 | + |
| 764 | + if (gas_used) { |
| 765 | + *gas_used = 0; |
| 766 | + } |
| 767 | + |
| 768 | + if (blob_gas_used) { |
| 769 | + *blob_gas_used = 0; |
| 770 | + } |
| 771 | + |
| 772 | + silkworm::Hash block_header_hash{}; |
| 773 | + memcpy(block_header_hash.bytes, block_hash.bytes, sizeof(block_hash.bytes)); |
| 774 | + BlockNum block_number{block_num}; |
| 775 | + TxnId txn_id_{txn_num}; |
| 776 | + |
| 777 | + auto unmanaged_tx = datastore::kvdb::RWTxnUnmanaged{mdbx_tx}; |
| 778 | + auto unmanaged_env = silkworm::datastore::kvdb::EnvUnmanaged{::mdbx_txn_env(mdbx_tx)}; |
| 779 | + auto chain_db = db::DataStore::make_chaindata_database(std::move(unmanaged_env)); |
| 780 | + auto db_ref = chain_db.ref(); |
| 781 | + auto state = silkworm::execution::DomainState{txn_id_, unmanaged_tx, db_ref, *handle->blocks_repository, *handle->state_repository}; |
| 782 | + if (!handle->chain_config) { |
| 783 | + handle->chain_config = db::read_chain_config(unmanaged_tx); |
| 784 | + } |
| 785 | + |
| 786 | + // TODO: cache block, also consider preloading |
| 787 | + silkworm::Block block{}; |
| 788 | + auto block_read_ok = state.read_body(block_number, block_header_hash, block); |
| 789 | + if (!block_read_ok) { |
| 790 | + SILK_ERROR << "Block not found" |
| 791 | + << " block_number: " << block_number << " block_hash: " << block_header_hash; |
| 792 | + return SILKWORM_INVALID_BLOCK; |
| 793 | + } |
| 794 | + auto header = state.read_header(block_number, block_header_hash); |
| 795 | + if (!header) { |
| 796 | + SILK_ERROR << "Header not found" |
| 797 | + << " block_number: " << block_number << " block_hash: " << block_header_hash; |
| 798 | + return SILKWORM_INVALID_BLOCK; |
| 799 | + } |
| 800 | + block.header = header.value(); |
| 801 | + |
| 802 | + if (txn_index >= block.transactions.size()) { |
| 803 | + SILK_ERROR << "Transaction not found" |
| 804 | + << " txn_index: " << txn_index; |
| 805 | + return SILKWORM_INVALID_BLOCK; |
| 806 | + } |
| 807 | + |
| 808 | + auto& transaction = block.transactions[txn_index]; |
| 809 | + |
| 810 | + auto protocol_rule_set_{protocol::rule_set_factory(*handle->chain_config)}; |
| 811 | + ExecutionProcessor processor{block, *protocol_rule_set_, state, *handle->chain_config, false}; |
| 812 | + // TODO: add analysis cache, check block exec for more |
| 813 | + |
| 814 | + silkworm::Receipt receipt{}; |
| 815 | + const ValidationResult err{protocol::validate_transaction(transaction, processor.intra_block_state(), processor.available_gas())}; |
| 816 | + if (err != ValidationResult::kOk) { |
| 817 | + return SILKWORM_INVALID_BLOCK; |
| 818 | + } |
| 819 | + processor.execute_transaction(transaction, receipt); |
| 820 | + state.insert_receipts(block_number, std::vector<silkworm::Receipt>{receipt}); |
| 821 | + |
| 822 | + if (gas_used) { |
| 823 | + *gas_used = receipt.cumulative_gas_used; |
| 824 | + } |
| 825 | + if (blob_gas_used) { |
| 826 | + *blob_gas_used = transaction.total_blob_gas(); |
| 827 | + } |
| 828 | + |
| 829 | + return SILKWORM_OK; |
| 830 | +} |
| 831 | + |
744 | 832 | SILKWORM_EXPORT int silkworm_fini(SilkwormHandle handle) SILKWORM_NOEXCEPT { |
745 | 833 | if (!handle) { |
746 | 834 | return SILKWORM_INVALID_HANDLE; |
|
0 commit comments